Logo Search packages:      
Sourcecode: bamboo version File versions

FolderPageStore.php

<?php 

/***************************************************************************
****************************************************************************

A class for storing and retrieving pages using a file system as
storage. Defines abstract class PageStore. Singleton.

Each page is represented as a directory with this structure:

page_name/  -- the enclosing directory
  b.basic   -- basic page properties which cannot be inherited. 
               ie title, page type, timestamp, nav info.
  b.inherit -- properties which may be inherited
                       ie permissions, visibility.
  b.en.txt  -- static text data in english
  b.es.txt  -- static text data in spanish
  b.en.html -- static html data in english, and so on...
  b.order   -- if this page contains other pages, this file
                       lists their order.
  sub_1/    -- a storage directory for a sub page.
  sub_2/    -- ditto.
  
any other files in the page's directory without a .b. in the filename
somewhere are considered to be attachments to the page. The .b. is used
to deny direct access to these files without going through bamboo's frontdoor.
  
To the $page object, we add the variable $storage. $storage points to the
absolute path of the enclosing directory which stores data for this page.

***************************************************************************
**************************************************************************/

$base = dirname(dirname(__FILE__));
require_once("$base/common.php");
require_once("$base/Properties.php");
require_once("$base/PageStore.php");

class FolderPageStore extends PageStore {

var $versioning = false;

#function FolderPageStore() {
#     if (is_file(`which rcs`))
#           $this->versioning = true;
#}

// initializes the $page to be able
// to talk to this PageStore.
function init(&$page) {
      $page->storage = $this->locateStorage($page);
      $page->fnf = !is_dir($page->storage);
}

/*
 * returns an array of basic page info for page object
 */
 
function loadbasic($siteroot, $path) {
      $storage = $this->locateStorageFromPath($siteroot,$path);
      $file = "$storage/b.basic";
      $ret = array();
      if (is_file($file)) 
            $ret = $this->loadProperties($file);
      $ret['name'] = deurlize($path); // name is special, can't be set, based on path.
      return $ret;
}

function loadinherit($siteroot, $path) {
      $storage = $this->locateStorageFromPath($siteroot,$path);
      $file = "$storage/b.inherit";
      if (is_file($file))
            return $this->loadProperties($file);
      else
            return null;
}

function savebasic($siteroot, $path, &$data) {
      $storage = $this->locateStorageFromPath($siteroot,$path);
      $file = "$storage/b.basic";
      $err = $this->saveProperties($file, $data);
      return $err;
}

function saveinherit($siteroot, $path, &$data) {
      $storage = $this->locateStorageFromPath($siteroot,$path);
      $file = "$storage/b.basic";
      $err = $this->saveProperties($file, $data);
      return $err;
}


/*
 * returns the contents of a page
 * (only for static pages, obviously)
 */
function fetch(&$_the_page_) {
      # the wacky $_the_page is so that it will be less likely to
      # collide with anything we might include if the page type is php.
      # in the future, we need a way to reset the symbol table if the php
      # page type is going to be useful.

      if ($_the_page_->fnf) return;

      $data = null;
      $contentfile = find_multilingual_content_file($_the_page_->storage, $_the_page_->type);
      if (!is_file($contentfile)) {
            return;
      }
      else {
            ob_start();
                  readfile($contentfile);
                  $data = &ob_get_contents();
            ob_end_clean();
      }

      if ($_the_page_->type == 'php') {
            $_the_page_->phpfile = $contentfile;
            # $content for php files is only used for the editor.
            # we should probably not bother loading the file unless
            # we are actually editing.
      }
            
      $_the_page_->content = &$data;
}

/* 
 * saves changes to 'content' or 'name'
 * (property saving is handled by Properties class.
 */
function commit(&$page) {
      if (!$page->dirty()) return;
      
      if ($page->isdirty('content')) {
            $lang = $_SESSION['lang'];
            $languages = split(' ',$page->get('languages'));
            if (!in_array($lang,$languages)) {
                  // the page does not allow saving as $lang, so use the default.
                  $lang = $page->get('default-lang');
            }
            $contentfile = "$page->storage/b.$lang.$page->type";
            $handle = fopen($contentfile,'w');
            if ($handle != FALSE) {
                  fwrite($handle,$page->content);
                  fclose($handle);
                  if ($this->versioning) {
                        $msg = '';
                        $this->saveVersion($contentfile, $msg);
                  }
                  $page->undirty('content');
            }
      }
      if ($page->isdirty('name')) {
            $oldpath = $page->path;
            $newpath = dirname($page->path) . '/' . $page->name;
            $ok = $this->movePage($page, $newpath);
            $page->undirty('name');
            return $ok;
      }
      return true;
}

function getContentSize(&$page) {
      $contentfile = find_multilingual_content_file($page->storage, $page->type);
      if (is_file($contentfile))
            return filesize($contentfile); 
      else
            return 0;
}

// returns a list of languages which have translated content.
function availableContent(&$page) {
      $files = find_all_content_files($page->storage,$page->type);
      for($i=0;$i<count($files);$i++) {
            $files[$i] = preg_replace("/^b\.(.*)\.$page->type$/",'$1',$files[$i]);
      }
      return $files;
}

function rebuildOrder(&$page) {
/*
      $listing = $this->getDirListing($page->storage);
      $newlist = array();
      foreach($listing as $name) {
            $child = $page->child($name);
            if (!$child->fnf)
                  $newlist[] = $name;
      }
      $this->writeOrderFile($page->storage, $newlist);
*/
}

function getOrder(&$page) {
      $name = basename($page->path);
      $parent = $page->parent();
      $listing = $this->getDirListing($parent->storage);
      return array_search($name, $listing);
}

function &getNext(&$page,$offset=1) {
      $name = basename($page->path);
      $parent = $page->parent();
      $listing = $this->getDirListing($parent->storage);
      $index = array_search($name, $listing);
      if (isset($listing[$index+$offset])) {
            $p = $this->getPage($page->parentpath . '/' . $listing[$index+$offset]);
            return $p;
      }
      else
            return null;
}

function &getPrev(&$page) {
      return $this->getNext($page, -1);
}

function setOrder(&$page, $order) {
      $parent = $page->parent();
      $name = basename($page->path);
      $listing = $this->getDirListing($parent->storage);
      $files = array();

      $count = count($listing);
      if ($order >= $count || $order < 0)
            return;
                  
      unset($listing[array_search($name,$listing)]);
      reset($listing);
      for($i=0; $i<$count; $i++) {
            if ($i == $order) {
                  $files[$i] = $name;
            }
            else {
                  $files[$i] = current($listing);
                  next($listing);
            }
      }
      $this->writeOrderFile($parent->storage, $files);
}

/*
 * Creates a new page as a child of $page.
 */
      #$skeleton = dirname(__FILE__) . "/skeleton/page";
      #$err = `cp -ar $skeleton $newpage->storage 2>&1`;

function &newChild(&$page, $name) {
      $name = urlize($name);
      $newpath = "$page->path/$name";
      $newpage = new Page($this, $newpath);
      $err = `mkdir $newpage->storage 2>&1`;
      if (!empty($err)) {
            $page->error("Could not create $newpage->storage: " . $err);
      }
      $newpage->init($this,$newpath);
      return $newpage;
}

function destroyPage(&$page) {
      $err = `rm -r $page->storage/ 2>&1`;
      if (!empty($err)) {
            $page->error("Could not rm $page->storage: " . $err);
      }
}

function movePage(&$page, $newpath) {
      $newpage = new Page($this,$newpath);
      if (is_dir($newpage->storage)) {
            $page->error($newpage->path . _(" already exists. "));
            return false;
      }
      else {
            $err = `mv $page->storage/ $newpage->storage/ 2>&1`;
            if (!empty($err)) {
                  $page->error("Could not move page $page->path to $newpage->path: " . $err);
                  return false;
            }
            $this->rebuildOrder($page->parent());
            $page->init($this, $newpath);
            return true;
      }
}

function duplicatePage(&$page, $newpath) {
      $newpage = new Page($this,$newpath);
      $err = `cp -ar $page->storage/ $newpage->storage/ 2>&1`;
      if (!empty($err)) {
            $page->error("Could not duplicate page $page->path to $newpage->path: " . $err);
      }
}

function getFirstChild($page) {
      $filepath = $this->getFilePath($page->path);
      if (!is_dir($filepath)) 
            return null;
            
      $files = $this->getDirListing($filepath);
      if (isset($files[0]))
            return $this->getPage($page->path . '/' . $files[0]);
      else
            return null;
}

function getChildren(&$page) {            
      $ret = array();   
      $files = $this->getDirListing($page->storage);
      foreach($files as $file) {
            $ret[] = $this->getPage($page->path . '/' . $file);
      }
      return $ret;
}     


/**
 * returns the navigation title from just the path.
 * does not require a page object.
 **/

function getNavTitle($path) {
      // may be optimized in the future have a better way of doing this
      $page = $this->getPage($path);
      if ($page->fnf)
            return deurlize($path);
      else
            return $page->get('title');
}

#################################################
## Attachments

function getAttachments(&$page) {
      $path = $page->storage;
      $handle = opendir($path);
      $files = array();
      while ($filename = readdir($handle)) { 
            if ($filename{0} == '.' || is_dir("$path/$filename") || substr($filename,0,2) == 'b.') {
                  continue;
            }
            $files[$filename] = array(
                  'file' => "$path/$filename",
                  'size' => filesize("$path/$filename"),
                  'type' => mime_type("$path/$filename"),
                  'mtime' => filemtime("$path/$filename"),
                  'name' => $filename
            );
      }
      return $files;
}

function addAttachment(&$page,$filedata) {
      $path = $page->storage;
      $err = '';
      if ($filedata['error']) {
            switch ($filedata['error']) {
                  case UPLOAD_ERR_INI_SIZE: $err = "The uploaded file exceeds the upload_max_filesize directive in php.ini."; break;
                  case UPLOAD_ERR_FORM_SIZE: $err = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form."; break;
                  case UPLOAD_ERR_PARTIAL: $err = "The uploaded file was only partially uploaded."; break;
                  case UPLOAD_ERR_NO_FILE: $err = "No file was uploaded."; break;
            }
      }
      elseif (file_exists("$path/$filedata[name]")) {
            $err = _("That file already exists");
      }
      
      if (!$err && move_uploaded_file($filedata['tmp_name'],"$path/$filedata[name]" )) {
            return true;
      } else {
            $err = $err ? $err : 'unknown';
            error_log("file upload failed! $err");
            $page->error("file upload failed! $err");
            return true;
      }
}

function removeAttachment(&$page,$filename) {
      $file = safepath("$page->storage/$filename");
      if (is_dir($file)) {
            $page->error("Something is wrong: that is a directory");
            return;
      }
      $err = `rm -r $file 2>&1`;
      if (!empty($err)) {
            $page->error("Could not remove $file: " . $err);
      }
}


#################################################
## Private Functions
#################################################

#################################################
## File reading/writing

// returns an array of data in file.
// file                  -->     array
// sample_prop = value   -->     $array['sample_prop'] == 'value'
function &loadProperties($filename) {
      $ret = parse_ini_file($filename);
      if ($ret == null)
            return array();
      else  
            return $ret;
}

function saveProperties($filename, &$array) {
      $out = fopen($filename, 'w');
      if ($out != false) {    
            foreach($array as $key => $value) {
                  if ($this->prop->proptype($key) == 'boolean') {
                        if ($value == false)
                              $value = 'false';
                        fwrite($out, "$key = $value\n");
                  }
                  else {
                        $value = preg_replace('/"/', '&quot;', $value);
                        fwrite($out, "$key = \"$value\"\n");
                  }
            }
            fclose($out);
      }
}

/*
 * returns a lits of the bamboo 'pages' in filesystem directory $dir
 * using b.order to sort. If b.order doesn't exist or is out of date, 
 * we create a new one.
 */
 
function getDirListing($storagedir) {
      $handle = opendir($storagedir);
      $subdirs = array();
      while ($filename = readdir($handle)) { 
            if (!is_dir("$storagedir/$filename") || $filename{0} == '.' || substr($filename,0,2) == "b." )
                  continue;
            $subdirs[] = $filename;
      }
      closedir($handle);
      if (is_file("$storagedir/b.order")) {
            $order = array_map('trim',file("$storagedir/b.order"));
            $rebuildneeded = count(array_diff($subdirs,$order)) || count(array_diff($order,$subdirs));
            if ( $rebuildneeded ) {
                  unlink("$storagedir/b.order");

                  // retain as much of the previous order as we can:
                  $newdirs = array();                 
                  foreach ($order as $dir) {
                        if (in_array($dir,$subdirs))
                              $newdirs[] = $dir;
                  }
                  foreach ($subdirs as $dir) {
                        if (!in_array($dir,$newdirs))
                              $newdirs[] = $dir;
                  }
                  $this->writeOrderFile($storagedir,$newdirs);
                  return $newdirs;
            }
            else {
                  return $order;
            }
      }
      elseif (count($subdirs)) {
            sort($subdirs);
            $this->writeOrderFile($storagedir,$subdirs);
            return $subdirs;
      }
      else {
            return array();
      }
}

function writeOrderFile($dir, $filelist) {
      $out = fopen("$dir/b.order", 'w');
      if ($out != false) {
            foreach($filelist as $file) {
                  fwrite($out, "$file\n");
            }
            fclose($out);
      }
}

###################################################
## File paths

/*
 * same as dirname, but if only / is left, return ''.
 */
function dirname($path) {
      $ret = dirname($path);
      if ($ret=='/') return '';
      else return $ret;
}

/*
 returns the absolute path to the file system directory
 where $page is stored. 
*/
function locateStorage(&$page) {
      $ret = $_SERVER['DOCUMENT_ROOT']
            . '/' . $page->prop->getGlobal('siteroot')
            . '/' . $page->path;
      $ret = preg_replace(
            array("'/{2,}'","'/$'"),
            array('/',''),
            $ret
      );
      return $ret;
}

function locateStorageFromPath($siteroot, $path) {
      $ret = $_SERVER['DOCUMENT_ROOT'] . '/' . $siteroot . '/' . $path;
      $ret = preg_replace(
            array("'/{2,}'","'/$'"),
            array('/',''),
            $ret
      );
      return $ret;
}

// this is easy and nice, but a little hackish
function storage($path) {
      global $prop;
      $ret = $_SERVER['DOCUMENT_ROOT'].'/'.$prop->getGlobal('siteroot').'/'.$path;
      $ret = preg_replace(array("'/{2,}'","'/$'"),array('/',''),$ret);
      return $ret;
}

function mkdirectory($path) {
      $filename = $this->storage($path);
      if (!is_dir($filename)) {
            if (!is_writeable(dirname($filename))) {
                  $user = posix_getpwuid(posix_getuid());
                  die(dirname($filename) . " must be writeable by " . $user['name']);
            }
            else {
                  mkdir($filename);
            }
      }
}

// returns true if there exists a page with path equal to $path
function exists($path) {
      $filename = $this->storage($path);
      return is_dir($filename);
}

###################################################
## Versioning

function saveVersion($contentfile, $msg) {
      # this is the *wrong* solution for versioning
      # but i wanted something before data got lost -kellan
      $rcsfile = $contentfile . ',v';
      if (! is_file($rcsfile) ) {
            # create an empty rcs file to match our $contentfile
            `rcs -q -i $rcsfile < /dev/null`;
      }
      # check in current contentfile
      `ci -l $contentfile < /dev/null`;
}

} // end class

####################################################
####################################################

// the system call mime_content_type seems to be broken, so we use our own:
function mime_type($file) {
      return exec("file -bi " . safepath($file));
}

function find_multilingual_content_file($storage, $type) {
      $languages = Lang::priority();
      $lang_len = count( $languages );
      $i = 0;
      $contentfile = $storage . '/b.' . $languages[ $i ] . '.' . $type;
      while ( !is_file( $contentfile ) && ( $i < $lang_len ) ) {
            $contentfile = $storage . '/b.' . $languages[ $i++ ] . '.' . $type;
      }
      return $contentfile;
}

// returns a list of all content files, for the given type.
function find_all_content_files($storage, $type) {
      $handle = opendir($storage);
      $files = array();
      while ($filename = readdir($handle)) { 
            if (preg_match("/^b\..*\.$type$/",$filename))
                  $files[] = $filename;
      }
      closedir($handle);
      return $files;
}

?>

Generated by  Doxygen 1.6.0   Back to index