Newer
Older
ubixos-web / docroot / phpwiki / lib / db_filesystem.php
@reddawg reddawg on 29 Jun 2004 9 KB UbixOS Web Site
<?php  rcs_id('$Id$');
   /*
      Database functions:

      OpenDataBase($table)
      CloseDataBase($dbi)
      RetrievePage($dbi, $pagename, $pagestore)
      InsertPage($dbi, $pagename, $pagehash)
      SaveCopyToArchive($dbi, $pagename, $pagehash) 
      IsWikiPage($dbi, $pagename)
      InitTitleSearch($dbi, $search)
      TitleSearchNextMatch($dbi, $res)
      InitFullSearch($dbi, $search)
      FullSearchNextMatch($dbi, $res)
      MakeBackLinkSearchRegexp($pagename)
      InitBackLinkSearch($dbi, $pagename) 
      BackLinkSearchNextMatch($dbi, &$pos) 
      IncreaseHitCount($dbi, $pagename)
      GetHitCount($dbi, $pagename)
      InitMostPopular($dbi, $limit)
      MostPopularNextMatch($dbi, $res)
   */


   // open a database and return the handle
   // loop until we get a handle; php has its own
   // locking mechanism, thank god.
   // Suppress ugly error message with @.

   function OpenDataBase($dbname) {
      global $WikiDB;

      ksort($WikiDB);
      reset($WikiDB);

      return $WikiDB;
   }


   function CloseDataBase($dbi) {
      return;
   }

   // Sort of urlencode() the pagename.
   // We only encode a limited set of characters to minimize breakage
   // of existing databases.  The encoded names can be decoded with
   // urldecode.
   function EncodePagename($pagename) {
      if ($pagename == '.')
        return '%2e';
      else if ($pagename == '..')
        return '%2e.';
      
      $bad_chars = '%/\\:'; // '%' must be first!
      for ($i = 0; $i < strlen($bad_chars); $i++) {
	 $pagename = str_replace($bad_chars[$i],
	                         rawurlencode($bad_chars[$i]), $pagename);
      }
        
      return $pagename;
   }

   // Return hash of page + attributes or default
   function RetrievePage($dbi, $pagename, $pagestore) {
      $filename = $dbi[$pagestore] . "/" . EncodePagename($pagename);
      if ($fd = @fopen($filename, "rb")) {
         $locked = flock($fd, 1); # Read lock
         if (!$locked) { 
            ExitWiki("Timeout while obtaining lock. Please try again"); 
         }
         if ($data = fread($fd, filesize($filename))) {
            // unserialize $data into a hash
            $pagehash = unserialize($data);
            $pagehash['pagename'] = $pagename;
	    if (!is_array($pagehash))
		ExitWiki(sprintf(gettext("'%s': corrupt file"),
				 htmlspecialchars($filename)));
	 }	
	 fclose($fd);
	 if ($data) {
	    return $pagehash;
	 }
      } else {
         return -1;
      }
   }


   // Either insert or replace a key/value (a page)
   function Filesystem_WritePage($dbi, $pagename, $pagehash) {
      global $WikiPageStore;
      $pagedata = serialize($pagehash);

      if (!file_exists($dbi)) {
	     $d = split("/", $dbi);
		 $dt = "";
		 while(list($key, $val) = each($d)) {
			$dt = $dt.$val."/";
		    @mkdir($dt, 0755);
		 }
	  }

      $filename = $dbi . "/" . EncodePagename($pagename);
      if($fd = fopen($filename, 'a+b')) { 
         $locked = flock($fd,2); #Exclusive blocking lock 
         if (!$locked) { 
            ExitWiki("Timeout while obtaining lock. Please try again"); 
         }
	 

         #Second (actually used) filehandle 
         #$fdsafe = fopen($filename, 'wb'); 
         #fwrite($fdsafe, $pagedata); 
         #fclose($fdsafe);

	 rewind($fd);
	 ftruncate($fd, 0);
         fwrite($fd, $pagedata); 
         fclose($fd);
      } else {
         ExitWiki("Error while writing page '$pagename'");
      }
   }

   function InsertPage($dbi, $pagename, $pagehash) {
      return Filesystem_WritePage($dbi['wiki'], $pagename, $pagehash);
   }

   // for archiving pages to a seperate dbm
   function SaveCopyToArchive($dbi, $pagename, $pagehash) {
      global $ArchivePageStore;
      return Filesystem_WritePage($dbi[$ArchivePageStore], $pagename, $pagehash);
   }


   function IsWikiPage($dbi, $pagename) {
      return file_exists($dbi['wiki'] . "/" . EncodePagename($pagename));
   }


   function IsInArchive($dbi, $pagename) {
      return file_exists($dbi['archive'] . "/" . EncodePagename($pagename));
   }


   // setup for title-search
   function InitTitleSearch($dbi, $search) { 
      $pos['search'] = '=' . preg_quote($search) . '=i';
      $pos['data'] = GetAllWikiPageNames($dbi['wiki']);

      return $pos;
   }

   // iterating through database
   function TitleSearchNextMatch($dbi, &$pos) { 
      while (list($key, $page) = each($pos['data'])) {
         if (preg_match($pos['search'], $page)) {
            return $page;
         }
      }
      return 0;
   }

   // setup for full-text search
   function InitFullSearch($dbi, $search) { 
      return InitTitleSearch($dbi, $search);
   }

   //iterating through database
   function FullSearchNextMatch($dbi, &$pos) { 
      global $WikiPageStore;
      while (list($key, $page) = each($pos['data'])) {
         $pagedata = RetrievePage($dbi, $page, $WikiPageStore);
         if (preg_match($pos['search'], serialize($pagedata))) {
	        return $pagedata;
         }
      }
      return 0;
   }

   ////////////////////////
   // new database features

   // Compute PCRE suitable for searching for links to the given page.
   function MakeBackLinkSearchRegexp($pagename) {
      global $WikiNameRegexp;

      // Note that in (at least some) PHP 3.x's, preg_quote only takes
      // (at most) one argument.  Also it doesn't quote '/'s.
      // It does quote '='s, so we'll use that for the delimeter.
      $quoted_pagename = preg_quote($pagename);
      if (preg_match("/^$WikiNameRegexp\$/", $pagename)) {
	 # FIXME: This may need modification for non-standard (non-english) $WikiNameRegexp.
	 return "=(?<![A-Za-z0-9!])$quoted_pagename(?![A-Za-z0-9])=";
      }
      else {
	 // Note from author: Sorry. :-/
	 return ( '='
		  . '(?<!\[)\[(?!\[)' // Single, isolated '['
		  . '([^]|]*\|)?'     // Optional stuff followed by '|'
	          . '\s*'             // Optional space
		  . $quoted_pagename  // Pagename
		  . '\s*\]=' );	      // Optional space, followed by ']'
	 // FIXME: the above regexp is still not quite right.
	 // Consider the text: " [ [ test page ]".  This is a link to a page
	 // named '[ test page'.  The above regexp will recognize this
	 // as a link either to '[ test page' (good) or to 'test page' (wrong).
      } 
   }

   // setup for back-link search
   function InitBackLinkSearch($dbi, $pagename) {
      $pos['search'] = MakeBackLinkSearchRegexp($pagename);
      $pos['data'] = GetAllWikiPageNames($dbi['wiki']);

      return $pos;
   }

   // iterating through back-links
   function BackLinkSearchNextMatch($dbi, &$pos) {
      global $WikiPageStore;
      while (list($key, $page) = each($pos['data'])) {
         $pagedata = RetrievePage($dbi, $page, $WikiPageStore);
	 if (!is_array($pagedata)) {
	    printf(gettext("%s: bad data<br>\n"), htmlspecialchars($page));
	    continue;
	 }
	 
	 while (list($i, $line) = each($pagedata['content'])) {
	    if (preg_match($pos['search'], $line))
	       return $page;
	 }
      }
      return 0;
   }

   function IncreaseHitCount($dbi, $pagename) {
      return;
return;
      // kluge: we ignore the $dbi for hit counting
      global $WikiDB;

      $hcdb = OpenDataBase($WikiDB['hitcount']);

      if (dbmexists($hcdb['active'], $pagename)) {
         // increase the hit count
         $count = dbmfetch($hcdb['active'], $pagename);
         $count++;
         dbmreplace($hcdb['active'], $pagename, $count);
      } else {
         // add it, set the hit count to one
         $count = 1;
         dbminsert($hcdb['active'], $pagename, $count);
      }

      CloseDataBase($hcdb);
   }

   function GetHitCount($dbi, $pagename) {
      return;
      // kluge: we ignore the $dbi for hit counting
      global $WikiDB;

      $hcdb = OpenDataBase($WikiDB['hitcount']);
      if (dbmexists($hcdb['active'], $pagename)) {
         // increase the hit count
         $count = dbmfetch($hcdb['active'], $pagename);
         return $count;
      } else {
         return 0;
      }

      CloseDataBase($hcdb);
   }


   function InitMostPopular($dbi, $limit) {
     return;
      $pagename = dbmfirstkey($dbi['hitcount']);
      $res[$pagename] = dbmfetch($dbi['hitcount'], $pagename);
      while ($pagename = dbmnextkey($dbi['hitcount'], $pagename)) {
         $res[$pagename] = dbmfetch($dbi['hitcount'], $pagename);
         echo "got $pagename with value " . $res[$pagename] . "<br>\n";
      }

      rsort($res);
      reset($res);
      return($res);
   }

   function MostPopularNextMatch($dbi, $res) {
      return;
      // the return result is a two element array with 'hits'
      // and 'pagename' as the keys

      if (list($index1, $index2, $pagename, $hits) = each($res)) {
         echo "most popular next match called<br>\n";
         echo "got $pagename, $hits back<br>\n";
         $nextpage = array(
            "hits" => $hits,
            "pagename" => $pagename
         );
         return $nextpage;
      } else {
         return 0;
      }
   } 

   function GetAllWikiPagenames($dbi) {
      $namelist = array();
      $d = opendir($dbi);
      while($entry = readdir($d)) {
	 if ($entry == '.' || $entry == '..')
	    continue;
	 $pagename = rawurldecode($entry);
	 if ($entry != EncodePagename($pagename)) {
	    printf(gettext("%s: Bad filename in database<br>\n"),
		   htmlspecialchars("$dbi/$entry"));
	    continue;
	 }
	 $namelist[] = $pagename;
      }

      return $namelist;
   }
?>