]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiDB/backend/file.php
add case_exact search
[SourceForge/phpwiki.git] / lib / WikiDB / backend / file.php
1 <?php // -*-php-*-
2 rcs_id('$Id: file.php,v 1.20 2004-11-23 13:35:49 rurban Exp $');
3
4 /**
5  Copyright 1999, 2000, 2001, 2002, 2003 $ThePhpWikiProgrammingTeam
6
7  This file is part of PhpWiki.
8
9  PhpWiki is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  PhpWiki is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with PhpWiki; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24
25
26 /**
27  * Backend for handling file storage. 
28  *
29  * Author: Jochen Kalmbach, Jochen@kalmbachnet.de
30  */
31
32 /*
33  * TODO: 
34  * - Implement "optimize" / "sync" / "check" / "rebuild"
35  * - Optimize "get_previous_version"
36  * - Optimize "get_links" (reversed = true)
37  * - Optimize "get_all_revisions"
38  * - Optimize "most_popular" (separate file for "hitcount", 
39  *   which contains all pages)
40  * - Optimize "most_recent"
41  * - What should be done in "lock"/"unlock"/"close" ?
42  * - "WikiDB_backend_file_iter": Do I need to return 'version' and 'versiondata' ?
43  *
44  */
45
46 require_once('lib/WikiDB/backend.php');
47 require_once('lib/ErrorManager.php');
48
49 class WikiDB_backend_file
50 extends WikiDB_backend
51 {
52     var $data_dir;
53     var $_dir_names;
54
55     var $_page_data;          // temporarily stores the pagedata (via _loadPageData)
56     var $_page_version_data;  // temporarily stores the versiondata (via _loadVersionData)
57     var $_latest_versions;    // temporarily stores the latest version-numbers (for every pagename)
58
59     function WikiDB_backend_file( $dbparam )
60     {
61         $this->data_dir = $dbparam['directory'];
62         if (file_exists($this->data_dir) and is_file($this->data_dir))
63                 unlink($this->data_dir);
64         if (is_dir($this->data_dir) == false) {
65             mkdir($this->data_dir, 0755);
66         }
67
68         $this->_dir_names
69             = array('ver_data'     => $this->data_dir.'/'.'ver_data',
70                     'page_data'    => $this->data_dir.'/'.'page_data',
71                     'latest_ver'   => $this->data_dir.'/'.'latest_ver',
72                     'links'        => $this->data_dir.'/'.'links' );
73
74         foreach ($this->_dir_names as $key => $val) {
75                 if (file_exists($val) and is_file($val))
76                     unlink($val);
77             if (is_dir($val) == false)
78                 mkdir($val, 0755);
79         }
80
81         $this->_page_data = NULL;
82         $this->_page_version_data = NULL;
83         $this->_latest_versions = NULL;
84
85
86     }
87
88     // *********************************************************************
89     // common file load / save functions:
90     function _pagename2filename($type, $pagename, $version) {
91          if ($version == 0)
92              return $this->_dir_names[$type].'/'.urlencode($pagename);
93          else
94              return $this->_dir_names[$type].'/'.urlencode($pagename).'--'.$version;
95     }
96
97     function _loadPage($type, $pagename, $version, $set_pagename = true) {
98       $filename = $this->_pagename2filename($type, $pagename, $version);
99       if (!file_exists($filename)) return NULL;
100       if (!filesize($filename)) return array();
101       if ($fd = @fopen($filename, "rb")) {
102          $locked = flock($fd, 1); # Read lock
103          if (!$locked) { 
104             ExitWiki("Timeout while obtaining lock. Please try again"); 
105          }
106          if ($data = fread($fd, filesize($filename))) {
107             $pd = unserialize($data);
108             if ($set_pagename == true)
109                 $pd['pagename'] = $pagename;
110             if ($version != 0)
111                 $pd['version'] = $version;
112             if (!is_array($pd))
113                 ExitWiki(sprintf(gettext("'%s': corrupt file"),
114                                  htmlspecialchars($filename)));
115             else
116               return $pd;
117          }      
118          fclose($fd);
119       }
120       return NULL;
121     }
122
123     function _savePage($type, $pagename, $version, $data) {
124         $filename = $this->_pagename2filename($type, $pagename, $version);
125         if($fd = fopen($filename, 'a+b')) { 
126            $locked = flock($fd,2); #Exclusive blocking lock 
127            if (!$locked) { 
128               ExitWiki("Timeout while obtaining lock. Please try again"); 
129            }
130
131            rewind($fd);
132            ftruncate($fd, 0);
133            $pagedata = serialize($data);
134            fwrite($fd, $pagedata); 
135            fclose($fd);
136         } else {
137            ExitWiki("Error while writing page '$pagename'");
138         }
139     }
140
141     function _removePage($type, $pagename, $version) {
142         $filename = $this->_pagename2filename($type, $pagename, $version);
143         if (!file_exists($filename)) return NULL;
144         $f = @unlink($filename);
145         if ($f == false)
146             trigger_error("delete file failed: ".$filename." ver: ".$version, E_USER_WARNING);
147     }
148
149     // *********************************************************************
150
151     // *********************************************************************
152     // Load/Save Version-Data
153     function _loadVersionData($pagename, $version) {
154         if ($this->_page_version_data != NULL) {
155             if ( ($this->_page_version_data['pagename'] == $pagename) && 
156                 ($this->_page_version_data['version'] == $version) ) {
157                 return $this->_page_version_data;
158              }
159         }
160         $vd = $this->_loadPage('ver_data', $pagename, $version);
161         if ($vd != NULL) {
162             $this->_page_version_data = $vd;
163             if ( ($this->_page_version_data['pagename'] == $pagename) && 
164                 ($this->_page_version_data['version'] == $version) ) {
165                 return $this->_page_version_data;
166              }
167         }
168         return NULL;
169     }
170
171     function _saveVersionData($pagename, $version, $data) {
172         $this->_savePage('ver_data', $pagename, $version, $data);
173
174         // check if this is a newer version:
175         if ($this->_getLatestVersion($pagename) < $version) {
176             // write new latest-version-info
177             $this->_setLatestVersion($pagename, $version);
178         }
179     }
180
181
182     // *********************************************************************
183     // Load/Save Page-Data
184     function _loadPageData($pagename) {
185         if ($this->_page_data != NULL) {
186             if ($this->_page_data['pagename'] == $pagename) {
187                 return $this->_page_data;
188              }
189         }
190         $pd = $this->_loadPage('page_data', $pagename, 0);
191         if ($pd != NULL)
192             $this->_page_data = $pd;
193         if ($this->_page_data != NULL) {
194             if ($this->_page_data['pagename'] == $pagename) {
195                 return $this->_page_data;
196              }
197         }
198         return array();  // no values found
199     }
200
201     function _savePageData($pagename, $data) {
202         $this->_savePage('page_data', $pagename, 0, $data);
203     }
204
205     // *********************************************************************
206     // Load/Save Latest-Version
207     function _saveLatestVersions() {
208         $data = $this->_latest_versions;
209         if ($data == NULL)
210             $data = array();
211         $this->_savePage('latest_ver', 'latest_versions', 0, $data);
212     }
213
214     function _setLatestVersion($pagename, $version) {
215         // make sure the page version list is loaded:
216         $this->_getLatestVersion($pagename);
217         if ($version > 0) {
218             $this->_getLatestVersion($pagename);
219             $this->_latest_versions[$pagename] = $version;
220         }
221         else {
222             // Remove this page from the Latest-Version-List:
223             unset($this->_latest_versions[$pagename]);
224         }
225         $this->_saveLatestVersions();
226     }
227
228     function _loadLatestVersions() {
229         if ($this->_latest_versions != NULL)
230             return;
231
232         $pd = $this->_loadPage('latest_ver', 'latest_versions', 0, false);
233         if ($pd != NULL)
234             $this->_latest_versions = $pd;
235         else
236             $this->_latest_versions = array(); // empty array
237     }
238
239     function _getLatestVersion($pagename) {
240        $this->_loadLatestVersions();
241        if (array_key_exists($pagename, $this->_latest_versions) == false)
242            return 0; // do version exists
243        return $this->_latest_versions[$pagename];
244     }
245
246
247     // *********************************************************************
248     // Load/Save Page-Links
249     function _loadPageLinks($pagename) {
250         $pd = $this->_loadPage('links', $pagename, 0, false);
251         if ($pd != NULL)
252             return $pd;;
253         return array();  // no values found
254     }
255
256     function _savePageLinks($pagename, $links) {
257         $this->_savePage('links', $pagename, 0, $links);
258     }
259
260
261
262     /**
263      * Get page meta-data from database.
264      *
265      * @param $pagename string Page name.
266      * @return hash
267      * Returns a hash containing the page meta-data.
268      * Returns an empty array if there is no meta-data for the requested page.
269      * Keys which might be present in the hash are:
270      * <dl>
271      *  <dt> locked  <dd> If the page is locked.
272      *  <dt> hits    <dd> The page hit count.
273      *  <dt> created <dd> Unix time of page creation. (FIXME: Deprecated: I
274      *                    don't think we need this...) 
275      * </dl>
276      */
277     function get_pagedata($pagename) {
278         return $this->_loadPageData($pagename);
279     }
280
281     /**
282      * Update the page meta-data.
283      *
284      * Set page meta-data.
285      *
286      * Only meta-data whose keys are preset in $newdata is affected.
287      *
288      * For example:
289      * <pre>
290      *   $backend->update_pagedata($pagename, array('locked' => 1)); 
291      * </pre>
292      * will set the value of 'locked' to 1 for the specified page, but it
293      * will not affect the value of 'hits' (or whatever other meta-data
294      * may have been stored for the page.)
295      *
296      * To delete a particular piece of meta-data, set it's value to false.
297      * <pre>
298      *   $backend->update_pagedata($pagename, array('locked' => false)); 
299      * </pre>
300      *
301      * @param $pagename string Page name.
302      * @param $newdata hash New meta-data.
303      */
304     /**
305      * This will create a new page if page being requested does not
306      * exist.
307      */
308     function update_pagedata($pagename, $newdata) {
309         $data = $this->get_pagedata($pagename);
310         if (count($data) == 0) {
311             $this->_savePageData($pagename, $newdata);  // create a new pagedata-file
312             return;
313         }
314         
315         foreach ($newdata as $key => $val) {
316             if (empty($val))
317                 unset($data[$key]);
318             else
319                 $data[$key] = $val;
320         }
321         $this->_savePageData($pagename, $data);  // write new pagedata-file
322     }
323     
324
325     /**
326      * Get the current version number for a page.
327      *
328      * @param $pagename string Page name.
329      * @return int The latest version number for the page.  Returns zero if
330      *  no versions of a page exist.
331      */
332     function get_latest_version($pagename) {
333         return $this->_getLatestVersion($pagename);
334     }
335     
336     /**
337      * Get preceding version number.
338      *
339      * @param $pagename string Page name.
340      * @param $version int Find version before this one.
341      * @return int The version number of the version in the database which
342      *  immediately preceeds $version.
343      *
344      * FIXED: Check if this version really exists!
345      */
346     function get_previous_version($pagename, $version) {
347         $prev = ($version > 0 ? $version - 1 : 0);
348         while ($prev and !file_exists($this->_pagename2filename('ver_data', $pagename, $prev))) {
349             $prev--;
350         }
351         return $prev;
352     }
353     
354     /**
355      * Get revision meta-data and content.
356      *
357      * @param $pagename string Page name.
358      * @param $version integer Which version to get.
359      * @param $want_content boolean
360      *  Indicates the caller really wants the page content.  If this
361      *  flag is not set, the backend is free to skip fetching of the
362      *  page content (as that may be expensive).  If the backend omits
363      *  the content, the backend might still want to set the value of
364      *  '%content' to the empty string if it knows there's no content.
365      *
366      * @return hash The version data, or false if specified version does not
367      *    exist.
368      *
369      * Some keys which might be present in the $versiondata hash are:
370      * <dl>
371      * <dt> %content
372      *  <dd> This is a pseudo-meta-data element (since it's actually
373      *       the page data, get it?) containing the page content.
374      *       If the content was not fetched, this key may not be present.
375      * </dl>
376      * For description of other version meta-data see WikiDB_PageRevision::get().
377      * @see WikiDB_PageRevision::get
378      */
379     function get_versiondata($pagename, $version, $want_content = false) {
380         $vd = $this->_loadVersionData($pagename, $version);
381         if ($vd == NULL)
382             return false;
383         return $vd;
384     }
385
386     /**
387      * Rename all files for this page
388      *
389      * @access protected   Via WikiDB
390      */
391     function rename_page($pagename, $to) {
392         $version = _getLatestVersion($pagename);
393         foreach ($this->_dir_names as $type => $path) {
394             if (is_dir($path)) {
395                 $filename = $this->_pagename2filename($type, $pagename, $version);
396                 $new = $this->_pagename2filename($type, $to, $version);
397                 @rename($filename,$new);
398             }
399         }
400         $this->update_pagedata($pagename, array('pagename' => $to)); 
401         return true;
402     }
403
404     /**
405      * Delete page from the database.
406      *
407      * Delete page (and all it's revisions) from the database.
408      *
409      * @param $pagename string Page name.
410      */
411     function delete_page($pagename) {
412         $ver = $this->get_latest_version($pagename);
413         while($ver > 0) {
414             $this->_removePage('ver_data', $pagename, $ver);
415             $ver = $this->get_previous_version($pagename, $ver);
416         }
417         $this->_removePage('page_data', $pagename, 0);
418         $this->_removePage('links', $pagename, 0);
419         // remove page from latest_version...
420         $this->_setLatestVersion($pagename, 0);
421     }
422             
423     /**
424      * Delete an old revision of a page.
425      *
426      * Note that one is never allowed to delete the most recent version,
427      * but that this requirement is enforced by WikiDB not by the backend.
428      *
429      * In fact, to be safe, backends should probably allow the deletion of
430      * the most recent version.
431      *
432      * @param $pagename string Page name.
433      * @param $version integer Version to delete.
434      */
435     function delete_versiondata($pagename, $version) {
436         if ($this->get_latest_version($pagename) == $version) {
437             // try to delete the latest version!
438             // so check if an older version exist:
439             if ($this->get_versiondata($pagename, 
440                                        $this->get_previous_version($pagename, $version), 
441                                        false) == false) {
442               // there is no older version....
443               // so the completely page will be removed:
444               $this->delete_page($pagename);
445               return;
446             }
447         }
448         $this->_removePage('ver_data', $pagename, $version);
449     }                           
450
451     /**
452      * Create a new page revision.
453      *
454      * If the given ($pagename,$version) is already in the database,
455      * this method completely overwrites any stored data for that version.
456      *
457      * @param $pagename string Page name.
458      * @param $version int New revisions content.
459      * @param $data hash New revision metadata.
460      *
461      * @see get_versiondata
462      */
463     function set_versiondata($pagename, $version, $data) {
464         $this->_saveVersionData($pagename, $version, $data);
465     }
466
467     /**
468      * Update page version meta-data.
469      *
470      * If the given ($pagename,$version) is already in the database,
471      * this method only changes those meta-data values whose keys are
472      * explicity listed in $newdata.
473      *
474      * @param $pagename string Page name.
475      * @param $version int New revisions content.
476      * @param $newdata hash New revision metadata.
477      * @see set_versiondata, get_versiondata
478      */
479     function update_versiondata($pagename, $version, $newdata) {
480         $data = $this->get_versiondata($pagename, $version, true);
481         if (!$data) {
482             assert($data);
483             return;
484         }
485         foreach ($newdata as $key => $val) {
486             if (empty($val))
487                 unset($data[$key]);
488             else
489                 $data[$key] = $val;
490         }
491         $this->set_versiondata($pagename, $version, $data);
492     }
493     
494     /**
495      * Set links for page.
496      *
497      * @param $pagename string Page name.
498      *
499      * @param $links array List of page(names) which page links to.
500      */
501     function set_links($pagename, $links) {
502         $this->_savePageLinks($pagename, $links);
503     }
504         
505     /**
506      * Find pages which link to or are linked from a page.
507      *
508      * @param $pagename string Page name.
509      * @param $reversed boolean True to get backlinks.
510      *
511      * FIXME: array or iterator?
512      * @return object A WikiDB_backend_iterator.
513      */
514     function get_links($pagename, $reversed) {
515         if ($reversed == false)
516             return new WikiDB_backend_file_iter($this, $this->_loadPageLinks($pagename));
517
518         $this->_loadLatestVersions();
519         $pagenames = $this->_latest_versions;  // now we have an array with the key is the pagename of all pages
520
521         $out = array();  // create empty out array
522
523         foreach ($pagenames as $key => $val) {
524             $links = $this->_loadPageLinks($key);
525             foreach ($links as $key2 => $val2) {
526                 if ($val2 == $pagename)
527                     array_push($out, $key);
528             }
529         }
530         return new WikiDB_backend_file_iter($this, $out);
531     }
532
533     /**
534      * Get all revisions of a page.
535      *
536      * @param $pagename string The page name.
537      * @return object A WikiDB_backend_iterator.
538      */
539     /*
540     function get_all_revisions($pagename) {
541         include_once('lib/WikiDB/backend/dumb/AllRevisionsIter.php');
542         return new WikiDB_backend_dumb_AllRevisionsIter($this, $pagename);
543     }
544     */
545     
546     /**
547      * Get all pages in the database.
548      *
549      * Pages should be returned in alphabetical order if that is
550      * feasable.
551      *
552      * @access protected
553      *
554      * @param $include_defaulted boolean
555      * If set, even pages with no content will be returned
556      * --- but still only if they have at least one revision (not
557      * counting the default revision 0) entered in the database.
558      *
559      * Normally pages whose current revision has empty content
560      * are not returned as these pages are considered to be
561      * non-existing.
562      *
563      * @return object A WikiDB_backend_iterator.
564      */
565     function get_all_pages($include_empty=false, $sortby=false, $limit=false, $exclude=false) {
566         require_once("lib/PageList.php");
567         $this->_loadLatestVersions();
568         $a = array_keys($this->_latest_versions);
569         if (empty($a))
570             return new WikiDB_backend_file_iter($this, $a);
571         $sortby = $this->sortby($sortby, 'db', $this->sortable_columns());
572         switch ($sortby) {
573         case '': break;
574         case 'pagename ASC':  sort($a); break;
575         case 'pagename DESC': rsort($a); break;
576         }
577         return new WikiDB_backend_file_iter($this, $a);
578     }
579
580     function sortable_columns() {
581         return array('pagename');
582     }
583
584     function numPages($filter=false, $exclude='') {
585         $this->_loadLatestVersions();
586         return count($this->_latest_versions);
587     }
588
589     /**
590      * Lock backend database.
591      *
592      * Calls may be nested.
593      *
594      * @param $write_lock boolean Unless this is set to false, a write lock
595      *     is acquired, otherwise a read lock.  If the backend doesn't support
596      *     read locking, then it should make a write lock no matter which type
597      *     of lock was requested.
598      *
599      *     All backends <em>should</em> support write locking.
600      */
601     function lock($write_lock = true) {
602         //trigger_error("lock: Not Implemented", E_USER_WARNING);
603     }
604
605     /**
606      * Unlock backend database.
607      *
608      * @param $force boolean Normally, the database is not unlocked until
609      *  unlock() is called as many times as lock() has been.  If $force is
610      *  set to true, the the database is unconditionally unlocked.
611      */
612     function unlock($force = false) {
613         //trigger_error("unlock: Not Implemented", E_USER_WARNING);
614     }
615
616
617     /**
618      * Close database.
619      */
620     function close () {
621         //trigger_error("close: Not Implemented", E_USER_WARNING);
622     }
623
624     /**
625      * Synchronize with filesystem.
626      *
627      * This should flush all unwritten data to the filesystem.
628      */
629     function sync() {
630         //trigger_error("sync: Not Implemented", E_USER_WARNING);
631     }
632
633     /**
634      * Optimize the database.
635      */
636     function optimize() {
637         return 0;//trigger_error("optimize: Not Implemented", E_USER_WARNING);
638     }
639
640     /**
641      * Check database integrity.
642      *
643      * This should check the validity of the internal structure of the database.
644      * Errors should be reported via:
645      * <pre>
646      *   trigger_error("Message goes here.", E_USER_WARNING);
647      * </pre>
648      *
649      * @return boolean True iff database is in a consistent state.
650      */
651     function check() {
652         //trigger_error("check: Not Implemented", E_USER_WARNING);
653     }
654
655     /**
656      * Put the database into a consistent state.
657      *
658      * This should put the database into a consistent state.
659      * (I.e. rebuild indexes, etc...)
660      *
661      * @return boolean True iff successful.
662      */
663     function rebuild() {
664         //trigger_error("rebuild: Not Implemented", E_USER_WARNING);
665     }
666
667     function _parse_searchwords($search) {
668         $search = strtolower(trim($search));
669         if (!$search)
670             return array(array(),array());
671         
672         $words = preg_split('/\s+/', $search);
673         $exclude = array();
674         foreach ($words as $key => $word) {
675             if ($word[0] == '-' && $word != '-') {
676                 $word = substr($word, 1);
677                 $exclude[] = preg_quote($word);
678                 unset($words[$key]);
679             }
680         }
681         return array($words, $exclude);
682     }
683        
684 };
685
686 class WikiDB_backend_file_iter extends WikiDB_backend_iterator
687 {
688     function WikiDB_backend_file_iter(&$backend, &$query_result) {
689         $this->_backend = &$backend;
690         $this->_result = $query_result;
691
692         if (count($this->_result) > 0)
693             reset($this->_result);
694     }
695     
696     function next() {
697         if (!$this->_result)
698             return false;
699         if (count($this->_result) <= 0)
700             return false;
701
702         $e = each($this->_result);
703         if ($e == false) {
704             return false;
705         }
706         
707         $pn = $e[1];
708         $pagedata = $this->_backend->get_pagedata($pn);
709         // don't pass _cached_html via iterators
710         if (isset($pagedata['_cached_html']))
711             unset($pagedata['_cached_html']);
712         unset($pagedata['pagename']);
713         $rec = array('pagename' => $pn,
714                      'pagedata' => $pagedata);
715         //$rec['version'] = $backend->get_latest_version($pn);
716         //$rec['versiondata'] = $backend->get_versiondata($pn, $rec['version'], true);
717         return $rec;
718     }
719     function asArray() {
720         reset($this->_result);
721         return $this->_result;
722     }
723     function count() {
724         return count($this->_result);
725     }
726     function free () {
727         $this->_result = array();
728     }
729 }
730
731 // $Log: not supported by cvs2svn $
732 // Revision 1.19  2004/11/21 11:59:26  rurban
733 // remove final \n to be ob_cache independent
734 //
735 // Revision 1.18  2004/11/09 17:11:17  rurban
736 // * revert to the wikidb ref passing. there's no memory abuse there.
737 // * use new wikidb->_cache->_id_cache[] instead of wikidb->_iwpcache, to effectively
738 //   store page ids with getPageLinks (GleanDescription) of all existing pages, which
739 //   are also needed at the rendering for linkExistingWikiWord().
740 //   pass options to pageiterator.
741 //   use this cache also for _get_pageid()
742 //   This saves about 8 SELECT count per page (num all pagelinks).
743 // * fix passing of all page fields to the pageiterator.
744 // * fix overlarge session data which got broken with the latest ACCESS_LOG_SQL changes
745 //
746 // Revision 1.17  2004/07/09 13:05:34  rurban
747 // just aesthetics
748 //
749 // Revision 1.16  2004/07/09 12:47:45  rurban
750 // dont cache _ cached_html and pagename in flatfile page iterators
751 //
752 // Revision 1.15  2004/07/09 10:06:50  rurban
753 // Use backend specific sortby and sortable_columns method, to be able to
754 // select between native (Db backend) and custom (PageList) sorting.
755 // Fixed PageList::AddPageList (missed the first)
756 // Added the author/creator.. name to AllPagesBy...
757 //   display no pages if none matched.
758 // Improved dba and file sortby().
759 // Use &$request reference
760 //
761 // Revision 1.14  2004/07/08 17:31:43  rurban
762 // improve numPages for file (fixing AllPagesTest)
763 //
764 // Revision 1.13  2004/07/08 15:23:59  rurban
765 // less verbose for tests
766 //
767 // Revision 1.12  2004/07/08 13:50:32  rurban
768 // various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
769 //
770 // Revision 1.11  2004/07/08 11:12:49  rurban
771 // quiet the testruns
772 //
773 // Revision 1.10  2004/06/03 22:08:17  rurban
774 // fix bug #963268 (check existing previous version)
775 //
776 // Revision 1.9  2004/04/27 16:03:05  rurban
777 // missing pageiter::count methods
778 //
779 // Revision 1.8  2004/03/01 13:48:45  rurban
780 // rename fix
781 // p[] consistency fix
782 //
783 // Revision 1.7  2004/02/12 14:11:36  rurban
784 // more rename_page backend methods: only tested for PearDB! please help
785 //
786 // Revision 1.6  2004/01/26 09:17:51  rurban
787 // * changed stored pref representation as before.
788 //   the array of objects is 1) bigger and 2)
789 //   less portable. If we would import packed pref
790 //   objects and the object definition was changed, PHP would fail.
791 //   This doesn't happen with an simple array of non-default values.
792 // * use $prefs->retrieve and $prefs->store methods, where retrieve
793 //   understands the interim format of array of objects also.
794 // * simplified $prefs->get() and fixed $prefs->set()
795 // * added $user->_userid and class '_WikiUser' portability functions
796 // * fixed $user object ->_level upgrading, mostly using sessions.
797 //   this fixes yesterdays problems with loosing authorization level.
798 // * fixed WikiUserNew::checkPass to return the _level
799 // * fixed WikiUserNew::isSignedIn
800 // * added explodePageList to class PageList, support sortby arg
801 // * fixed UserPreferences for WikiUserNew
802 // * fixed WikiPlugin for empty defaults array
803 // * UnfoldSubpages: added pagename arg, renamed pages arg,
804 //   removed sort arg, support sortby arg
805 //
806 // Revision 1.5  2004/01/25 08:17:29  rurban
807 // ORDER BY support for all other backends,
808 // all non-SQL simply ignoring it, using plain old dumb_iter instead
809 //
810 // Revision 1.4  2003/02/24 01:53:28  dairiki
811 // Bug fix.  Don't need to urldecode pagenames in WikiDB_backend_file_iter.
812 //
813 // Revision 1.3  2003/01/04 03:41:51  wainstead
814 // Added copyleft flowerboxes
815 //
816 // Revision 1.2  2003/01/04 03:30:34  wainstead
817 // added log tag, converted file to unix format
818 //
819
820 // For emacs users
821 // Local Variables:
822 // mode: php
823 // tab-width: 8
824 // c-basic-offset: 4
825 // c-hanging-comment-ender-p: nil
826 // indent-tabs-mode: nil
827 // End:
828 ?>