]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/db_filesystem.php
Fix encoding of page names '.' and '..'.
[SourceForge/phpwiki.git] / lib / db_filesystem.php
1 <?php  rcs_id('$Id: db_filesystem.php,v 1.4.2.5 2001-11-06 20:43:45 dairiki Exp $');
2    /*
3       Database functions:
4
5       OpenDataBase($table)
6       CloseDataBase($dbi)
7       RetrievePage($dbi, $pagename, $pagestore)
8       InsertPage($dbi, $pagename, $pagehash)
9       SaveCopyToArchive($dbi, $pagename, $pagehash) 
10       IsWikiPage($dbi, $pagename)
11       InitTitleSearch($dbi, $search)
12       TitleSearchNextMatch($dbi, $res)
13       InitFullSearch($dbi, $search)
14       FullSearchNextMatch($dbi, $res)
15       MakeBackLinkSearchRegexp($pagename)
16       InitBackLinkSearch($dbi, $pagename) 
17       BackLinkSearchNextMatch($dbi, &$pos) 
18       IncreaseHitCount($dbi, $pagename)
19       GetHitCount($dbi, $pagename)
20       InitMostPopular($dbi, $limit)
21       MostPopularNextMatch($dbi, $res)
22    */
23
24
25    // open a database and return the handle
26    // loop until we get a handle; php has its own
27    // locking mechanism, thank god.
28    // Suppress ugly error message with @.
29
30    function OpenDataBase($dbname) {
31       global $WikiDB;
32
33       ksort($WikiDB);
34       reset($WikiDB);
35
36       return $WikiDB;
37    }
38
39
40    function CloseDataBase($dbi) {
41       return;
42    }
43
44    // Sort of urlencode() the pagename.
45    // We only encode a limited set of characters to minimize breakage
46    // of existing databases.  The encoded names can be decoded with
47    // urldecode.
48    function EncodePagename($pagename) {
49       if ($pagename == '.')
50         return '%2e';
51       else if ($pagename == '..')
52         return '%2e.';
53       
54       $bad_chars = '%/\\:'; // '%' must be first!
55       for ($i = 0; $i < strlen($bad_chars); $i++) {
56          $pagename = str_replace($bad_chars[$i],
57                                  rawurlencode($bad_chars[$i]), $pagename);
58       }
59         
60       return $pagename;
61    }
62
63    // Return hash of page + attributes or default
64    function RetrievePage($dbi, $pagename, $pagestore) {
65       $filename = $dbi[$pagestore] . "/" . EncodePagename($pagename);
66       if ($fd = @fopen($filename, "rb")) {
67          $locked = flock($fd, 1); # Read lock
68          if (!$locked) { 
69             ExitWiki("Timeout while obtaining lock. Please try again"); 
70          }
71          if ($data = fread($fd, filesize($filename))) {
72             // unserialize $data into a hash
73             $pagehash = unserialize($data);
74             $pagehash['pagename'] = $pagename;
75             if (!is_array($pagehash))
76                 ExitWiki(sprintf(gettext("'%s': corrupt file"),
77                                  htmlspecialchars($filename)));
78          }      
79          fclose($fd);
80          if ($data) {
81             return $pagehash;
82          }
83       } else {
84          return -1;
85       }
86    }
87
88
89    // Either insert or replace a key/value (a page)
90    function Filesystem_WritePage($dbi, $pagename, $pagehash) {
91       global $WikiPageStore;
92       $pagedata = serialize($pagehash);
93
94       if (!file_exists($dbi)) {
95              $d = split("/", $dbi);
96                  $dt = "";
97                  while(list($key, $val) = each($d)) {
98                         $dt = $dt.$val."/";
99                     @mkdir($dt, 0755);
100                  }
101           }
102
103       $filename = $dbi . "/" . EncodePagename($pagename);
104       if($fd = fopen($filename, 'a+b')) { 
105          $locked = flock($fd,2); #Exclusive blocking lock 
106          if (!$locked) { 
107             ExitWiki("Timeout while obtaining lock. Please try again"); 
108          }
109          
110
111          #Second (actually used) filehandle 
112          #$fdsafe = fopen($filename, 'wb'); 
113          #fwrite($fdsafe, $pagedata); 
114          #fclose($fdsafe);
115
116          rewind($fd);
117          ftruncate($fd, 0);
118          fwrite($fd, $pagedata); 
119          fclose($fd);
120       } else {
121          ExitWiki("Error while writing page '$pagename'");
122       }
123    }
124
125    function InsertPage($dbi, $pagename, $pagehash) {
126       return Filesystem_WritePage($dbi['wiki'], $pagename, $pagehash);
127    }
128
129    // for archiving pages to a seperate dbm
130    function SaveCopyToArchive($dbi, $pagename, $pagehash) {
131       global $ArchivePageStore;
132       return Filesystem_WritePage($dbi[$ArchivePageStore], $pagename, $pagehash);
133    }
134
135
136    function IsWikiPage($dbi, $pagename) {
137       return file_exists($dbi['wiki'] . "/" . EncodePagename($pagename));
138    }
139
140
141    function IsInArchive($dbi, $pagename) {
142       return file_exists($dbi['archive'] . "/" . EncodePagename($pagename));
143    }
144
145
146    // setup for title-search
147    function InitTitleSearch($dbi, $search) { 
148       $pos['search'] = $search;
149       $pos['data'] = GetAllWikiPageNames($dbi['wiki']);
150
151       return $pos;
152    }
153
154    // iterating through database
155    function TitleSearchNextMatch($dbi, &$pos) { 
156       while (list($key, $page) = each($pos['data'])) {
157          if (eregi($pos['search'], $page)) {
158             return $page;
159          }
160       }
161       return 0;
162    }
163
164    // setup for full-text search
165    function InitFullSearch($dbi, $search) { 
166       return InitTitleSearch($dbi, $search);
167    }
168
169    //iterating through database
170    function FullSearchNextMatch($dbi, &$pos) { 
171       global $WikiPageStore;
172       while (list($key, $page) = each($pos['data'])) {
173          $pagedata = RetrievePage($dbi, $page, $WikiPageStore);
174          if (eregi($pos['search'], serialize($pagedata))) {
175                 return $pagedata;
176                  }
177           }
178       return 0;
179    }
180
181    ////////////////////////
182    // new database features
183
184    // Compute PCRE suitable for searching for links to the given page.
185    function MakeBackLinkSearchRegexp($pagename) {
186       global $WikiNameRegexp;
187
188       // Note that in (at least some) PHP 3.x's, preg_quote only takes
189       // (at most) one argument.  Also it doesn't quote '/'s.
190       // It does quote '='s, so we'll use that for the delimeter.
191       $quoted_pagename = preg_quote($pagename);
192       if (preg_match("/^$WikiNameRegexp\$/", $pagename)) {
193          # FIXME: This may need modification for non-standard (non-english) $WikiNameRegexp.
194          return "=(?<![A-Za-z0-9!])$quoted_pagename(?![A-Za-z0-9])=";
195       }
196       else {
197          // Note from author: Sorry. :-/
198          return ( '='
199                   . '(?<!\[)\[(?!\[)' // Single, isolated '['
200                   . '([^]|]*\|)?'     // Optional stuff followed by '|'
201                   . '\s*'             // Optional space
202                   . $quoted_pagename  // Pagename
203                   . '\s*\]=' );       // Optional space, followed by ']'
204          // FIXME: the above regexp is still not quite right.
205          // Consider the text: " [ [ test page ]".  This is a link to a page
206          // named '[ test page'.  The above regexp will recognize this
207          // as a link either to '[ test page' (good) or to 'test page' (wrong).
208       } 
209    }
210
211    // setup for back-link search
212    function InitBackLinkSearch($dbi, $pagename) {
213       return InitTitleSearch($dbi, MakeBackLinkSearchRegexp($pagename));
214    }
215
216    // iterating through back-links
217    function BackLinkSearchNextMatch($dbi, &$pos) {
218       global $WikiPageStore;
219       while (list($key, $page) = each($pos['data'])) {
220          $pagedata = RetrievePage($dbi, $page, $WikiPageStore);
221          if (!is_array($pagedata)) {
222             printf(gettext("%s: bad data<br>\n"), htmlspecialchars($page));
223             continue;
224          }
225          
226          while (list($i, $line) = each($pagedata['content'])) {
227             if (preg_match($pos['search'], $line))
228                return $page;
229          }
230       }
231       return 0;
232    }
233
234    function IncreaseHitCount($dbi, $pagename) {
235       return;
236 return;
237       // kluge: we ignore the $dbi for hit counting
238       global $WikiDB;
239
240       $hcdb = OpenDataBase($WikiDB['hitcount']);
241
242       if (dbmexists($hcdb['active'], $pagename)) {
243          // increase the hit count
244          $count = dbmfetch($hcdb['active'], $pagename);
245          $count++;
246          dbmreplace($hcdb['active'], $pagename, $count);
247       } else {
248          // add it, set the hit count to one
249          $count = 1;
250          dbminsert($hcdb['active'], $pagename, $count);
251       }
252
253       CloseDataBase($hcdb);
254    }
255
256    function GetHitCount($dbi, $pagename) {
257       return;
258       // kluge: we ignore the $dbi for hit counting
259       global $WikiDB;
260
261       $hcdb = OpenDataBase($WikiDB['hitcount']);
262       if (dbmexists($hcdb['active'], $pagename)) {
263          // increase the hit count
264          $count = dbmfetch($hcdb['active'], $pagename);
265          return $count;
266       } else {
267          return 0;
268       }
269
270       CloseDataBase($hcdb);
271    }
272
273
274    function InitMostPopular($dbi, $limit) {
275      return;
276       $pagename = dbmfirstkey($dbi['hitcount']);
277       $res[$pagename] = dbmfetch($dbi['hitcount'], $pagename);
278       while ($pagename = dbmnextkey($dbi['hitcount'], $pagename)) {
279          $res[$pagename] = dbmfetch($dbi['hitcount'], $pagename);
280          echo "got $pagename with value " . $res[$pagename] . "<br>\n";
281       }
282
283       rsort($res);
284       reset($res);
285       return($res);
286    }
287
288    function MostPopularNextMatch($dbi, $res) {
289       return;
290       // the return result is a two element array with 'hits'
291       // and 'pagename' as the keys
292
293       if (list($index1, $index2, $pagename, $hits) = each($res)) {
294          echo "most popular next match called<br>\n";
295          echo "got $pagename, $hits back<br>\n";
296          $nextpage = array(
297             "hits" => $hits,
298             "pagename" => $pagename
299          );
300          return $nextpage;
301       } else {
302          return 0;
303       }
304    } 
305
306    function GetAllWikiPagenames($dbi) {
307       $namelist = array();
308       $d = opendir($dbi);
309       while($entry = readdir($d)) {
310          if ($entry == '.' || $entry == '..')
311             continue;
312          $pagename = rawurldecode($entry);
313          if ($entry != EncodePagename($pagename)) {
314             printf(gettext("%s: Bad filename in database<br>\n"),
315                    htmlspecialchars("$dbi/$entry"));
316             continue;
317          }
318          $namelist[] = $pagename;
319       }
320
321       return $namelist;
322    }
323 ?>