<?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; } ?>