Newer
Older
ubixos-web / docroot / phpwiki / lib / dbalib.php
@reddawg reddawg on 29 Jun 2004 8 KB UbixOS Web Site
<?php  

   rcs_id('$Id$');

   /*
      Database functions:

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


   // 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; // hash of all the DBM file names

      reset($WikiDB);
      while (list($key, $file) = each($WikiDB)) {
         while (($dbi[$key] = @dba_open($file, "c", DBM_FILE_TYPE)) < 1) {
            $numattempts++;
            if ($numattempts > MAX_DBM_ATTEMPTS) {
               ExitWiki("Cannot open database '$key' : '$file', giving up.");
            }
            sleep(1);
         }
      }
      return $dbi;
   }


   function CloseDataBase($dbi) {
      reset($dbi);
      while (list($dbmfile, $dbihandle) = each($dbi)) {
         dba_close($dbihandle);
      }
      return;
   }


   // take a serialized hash, return same padded out to
   // the next largest number bytes divisible by 500. This
   // is to save disk space in the long run, since DBM files
   // leak memory.
   function PadSerializedData($data) {
      // calculate the next largest number divisible by 500
      $nextincr = 500 * ceil(strlen($data) / 500);
      // pad with spaces
      $data = sprintf("%-${nextincr}s", $data);
      return $data;
   }

   // strip trailing whitespace from the serialized data 
   // structure.
   function UnPadSerializedData($data) {
      return chop($data);
   }



   // Return hash of page + attributes or default
   function RetrievePage($dbi, $pagename, $pagestore) {
      if ($data = dba_fetch($pagename, $dbi[$pagestore])) {
         // unserialize $data into a hash
         $pagehash = unserialize(UnPadSerializedData($data));
         $pagehash['pagename'] = $pagename;
         return $pagehash;
      } else {
         return -1;
      }
   }


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

      if (!dba_insert($pagename, $pagedata, $dbi['wiki'])) {
         if (!dba_replace($pagename, $pagedata, $dbi['wiki'])) {
            ExitWiki("Error inserting page '$pagename'");
         }
      } 
   }


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

      $pagedata = PadSerializedData(serialize($pagehash));

      if (!dba_insert($pagename, $pagedata, $dbi[$ArchivePageStore])) {
         if (!dba_replace($pagename, $pagedata, $dbi['archive'])) {
            ExitWiki("Error storing '$pagename' into archive");
         }
      } 
   }


   function IsWikiPage($dbi, $pagename) {
      return dba_exists($pagename, $dbi['wiki']);
   }


   function IsInArchive($dbi, $pagename) {
      return dba_exists($pagename, $dbi['archive']);
   }


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

      return $pos;
   }

   // iterating through database
   function TitleSearchNextMatch($dbi, &$pos) {
      while ($pos['key']) {
         $page = $pos['key'];
         $pos['key'] = dba_nextkey($dbi['wiki']);

         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) {
      while ($pos['key']) {
         $key = $pos['key'];
         $pos['key'] = dba_nextkey($dbi['wiki']);

         $pagedata = dba_fetch($key, $dbi['wiki']);
         // test the serialized data
         if (preg_match($pos['search'], $pagedata)) {
	    $page['pagename'] = $key;
            $pagedata = unserialize(UnPadSerializedData($pagedata));
	    $page['content'] = $pagedata['content'];
	    return $page;
	 }
      }
      return 0;
   }

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

   // Compute PCRE suitable for searching for links to the given page.
   function MakeBackLinkSearchRegexp($pagename) {
      global $WikiNameRegexp;
     
      $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['key'] = dba_firstkey($dbi['wiki']);
      
      return $pos;
   }

   // iterating through back-links
   function BackLinkSearchNextMatch($dbi, &$pos) {
      while ($pos['key']) {
         $page = $pos['key'];
         $pos['key'] = dba_nextkey($dbi['wiki']);

         $rawdata = dba_fetch($page, $dbi['wiki']);
	 if ( ! preg_match($pos['search'], $rawdata))
	     continue;
	 
	 $pagedata = unserialize(UnPadSerializedData($rawdata));
	 while (list($i, $line) = each($pagedata['content'])) {
	    if (preg_match($pos['search'], $line))
	       return $page;
	 }
      }
      return 0;
   }

   function IncreaseHitCount($dbi, $pagename) {

      if (dba_exists($pagename, $dbi['hitcount'])) {
         // increase the hit count
         // echo "$pagename there, incrementing...<br>\n";
         $count = dba_fetch($pagename, $dbi['hitcount']);
         $count++;
         dba_replace($pagename, $count, $dbi['hitcount']);
      } else {
         // add it, set the hit count to one
         // echo "adding $pagename to hitcount...<br>\n";
         $count = 1;
         dba_insert($pagename, $count, $dbi['hitcount']);
      }
   }

   function GetHitCount($dbi, $pagename) {

      if (dba_exists($pagename, $dbi['hitcount'])) {
         // increase the hit count
         $count = dba_fetch($pagename, $dbi['hitcount']);
         return $count;
      } else {
         return 0;
      }
   }

   function InitMostPopular($dbi, $limit) {
      // iterate through the whole dbm file for hit counts
      // sort the results highest to lowest, and return 
      // n..$limit results

      $pagename = dba_firstkey($dbi['hitcount']);
      $res[$pagename] = dba_fetch($pagename, $dbi['hitcount']);

      while ($pagename = dba_nextkey($dbi['hitcount'])) {
         $res[$pagename] = dba_fetch($pagename, $dbi['hitcount']);
         //echo "got $pagename with value " . $res[$pagename] . "<br>\n";
      }

      arsort($res);
      return($res);
   }

   function MostPopularNextMatch($dbi, &$res) {

      // the return result is a two element array with 'hits'
      // and 'pagename' as the keys

      if (count($res) == 0)
         return 0;

      if (list($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
         );
         // $dbm_mostpopular_cntr++;
         return $nextpage;
      } else {
         return 0;
      }
   } 

   function GetAllWikiPagenames($dbi) {
      $namelist = array();
      $ctr = 0;

      $namelist[$ctr] = $key = dba_firstkey($dbi);

      while ($key = dba_nextkey($dbi)) {
         $ctr++;
         $namelist[$ctr] = $key;
      }

      return $namelist;
   }

?>