]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new...
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php //-*-php-*-
2 rcs_id('$Id: loadsave.php,v 1.118 2004-07-08 13:50:32 rurban Exp $');
3
4 /*
5  Copyright 1999, 2000, 2001, 2002 $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 require_once("lib/ziplib.php");
26 require_once("lib/Template.php");
27
28 /**
29  * ignore fatal errors during dump
30  */
31 function _dump_error_handler(&$error) {
32     if ($error->isFatal()) {
33         $error->errno = E_USER_WARNING;
34         return true;
35     }
36     return true;         // Ignore error
37     /*
38     if (preg_match('/Plugin/', $error->errstr))
39         return true;
40     */
41     // let the message come through: call the remaining handlers:
42     // return false; 
43 }
44
45 function StartLoadDump(&$request, $title, $html = '')
46 {
47     if (isa($request,'MockRequest'))
48         return;
49     // FIXME: This is a hack
50     if ($html)
51         $html->pushContent('%BODY%');
52     $tmpl = Template('html', array('TITLE' => $title,
53                                    'HEADER' => $title,
54                                    'CONTENT' => $html ? $html : '%BODY%'));
55     echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
56
57     /* Ignore fatals or warnings in any pagedumps (failing plugins). 
58      * WikiFunctionCb() fails with 4.0.6, works ok with 4.1.1 
59      */
60     if (!check_php_version(4,1) or (DEBUG & _DEBUG_VERBOSE)) return;
61     global $ErrorManager;
62     $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
63 }
64
65 function EndLoadDump(&$request)
66 {
67     if (isa($request,'MockRequest'))
68         return;
69     if (check_php_version(4,1)) {
70         global $ErrorManager;
71         $ErrorManager->popErrorHandler();
72     }
73     $action = $request->getArg('action');
74     $label = '';
75     switch ($action) {
76     case 'zip':        $label = _("ZIP files of database"); break;
77     case 'dumpserial': $label = _("Dump to directory"); break;
78     case 'upload':     $label = _("Upload File"); break;
79     case 'loadfile':   $label = _("Load File"); break;
80     case 'upgrade':    $label = _("Upgrade"); break;
81     case 'dumphtml': 
82     case 'ziphtml':    $label = _("Dump pages as XHTML"); break;
83     }
84     if ($label) $label = str_replace(" ","_",$label);
85     if ($action == 'browse') // loading virgin 
86         $pagelink = WikiLink(HOME_PAGE);
87     else
88         $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"),false,$label));
89
90     PrintXML(HTML::p(HTML::strong(_("Complete."))),
91              HTML::p(fmt("Return to %s", $pagelink)));
92     echo "</body></html>\n";
93 }
94
95
96 ////////////////////////////////////////////////////////////////
97 //
98 //  Functions for dumping.
99 //
100 ////////////////////////////////////////////////////////////////
101
102 /**
103  * For reference see:
104  * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
105  * http://www.faqs.org/rfcs/rfc2045.html
106  * (RFC 1521 has been superceeded by RFC 2045 & others).
107  *
108  * Also see http://www.faqs.org/rfcs/rfc2822.html
109  */
110 function MailifyPage ($page, $nversions = 1)
111 {
112     $current = $page->getCurrentRevision();
113     $head = '';
114
115     if (STRICT_MAILABLE_PAGEDUMPS) {
116         $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
117         //This is for unix mailbox format: (not RFC (2)822)
118         // $head .= "From $from  " . CTime(time()) . "\r\n";
119         $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
120         $head .= "From: $from (PhpWiki)\r\n";
121         // RFC 2822 requires only a Date: and originator (From:)
122         // field, however the obsolete standard RFC 822 also
123         // requires a destination field.
124         $head .= "To: $from (PhpWiki)\r\n";
125     }
126     $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
127     $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
128                      PHPWIKI_VERSION);
129
130     // This should just be entered by hand (or by script?)
131     // in the actual pgsrc files, since only they should have
132     // RCS ids.
133     //$head .= "X-Rcs-Id: \$Id\$\r\n";
134
135     $iter = $page->getAllRevisions();
136     $parts = array();
137     while ($revision = $iter->next()) {
138         $parts[] = MimeifyPageRevision($revision);
139         if ($nversions > 0 && count($parts) >= $nversions)
140             break;
141     }
142     if (count($parts) > 1)
143         return $head . MimeMultipart($parts);
144     assert($parts);
145     return $head . $parts[0];
146 }
147
148 /***
149  * Compute filename to used for storing contents of a wiki page.
150  *
151  * Basically we do a rawurlencode() which encodes everything except
152  * ASCII alphanumerics and '.', '-', and '_'.
153  *
154  * But we also want to encode leading dots to avoid filenames like
155  * '.', and '..'. (Also, there's no point in generating "hidden" file
156  * names, like '.foo'.)
157  *
158  * @param $pagename string Pagename.
159  * @return string Filename for page.
160  */
161 function FilenameForPage ($pagename)
162 {
163     $enc = rawurlencode($pagename);
164     return preg_replace('/^\./', '%2e', $enc);
165 }
166
167 /**
168  * The main() function which generates a zip archive of a PhpWiki.
169  *
170  * If $include_archive is false, only the current version of each page
171  * is included in the zip file; otherwise all archived versions are
172  * included as well.
173  */
174 function MakeWikiZip (&$request)
175 {
176     if ($request->getArg('include') == 'all') {
177         $zipname         = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
178         $include_archive = true;
179     }
180     else {
181         $zipname         = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
182         $include_archive = false;
183     }
184
185
186     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
187
188     /* ignore fatals in plugins */
189     if (check_php_version(4,1)) {
190         global $ErrorManager;
191         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
192     }
193
194     $dbi = $request->getDbh();
195     $thispage = $request->getArg('pagename'); // for "Return to ..."
196     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
197         $excludeList = explodePageList($exclude); 
198     } else {
199         $excludeList = array();
200     }
201     if ($whichpages = $request->getArg('pages')) {  // which pagenames
202         if ($whichpages == '[]') // current page
203             $whichpages = $thispage;
204         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
205     } else {
206         $pages = $dbi->getAllPages();
207     }
208     $request_args = $request->args;
209     
210     while ($page = $pages->next()) {
211         $request->args = $request_args; // some plugins might change them (esp. on POST)
212         //if (! $request->getArg('start_debug'))
213         @set_time_limit(30); // Reset watchdog
214
215         $current = $page->getCurrentRevision();
216         if ($current->getVersion() == 0)
217             continue;
218
219         $pagename = $page->getName();
220         $wpn = new WikiPageName($pagename);
221         if (!$wpn->isValid())
222             continue;
223         if (in_array($page->getName(), $excludeList)) {
224             continue;
225         }
226
227         $attrib = array('mtime'    => $current->get('mtime'),
228                         'is_ascii' => 1);
229         if ($page->get('locked'))
230             $attrib['write_protected'] = 1;
231
232         if ($include_archive)
233             $content = MailifyPage($page, 0);
234         else
235             $content = MailifyPage($page);
236
237         $zip->addRegularFile( FilenameForPage($pagename),
238                               $content, $attrib);
239     }
240     $zip->finish();
241     if (check_php_version(4,1)) {
242         $ErrorManager->popErrorHandler();
243     }
244 }
245
246 function DumpToDir (&$request)
247 {
248     $directory = $request->getArg('directory');
249     if (empty($directory))
250         $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
251     if (empty($directory))
252         $request->finish(_("You must specify a directory to dump to"));
253
254     // see if we can access the directory the user wants us to use
255     if (! file_exists($directory)) {
256         if (! mkdir($directory, 0755))
257             $request->finish(fmt("Cannot create directory '%s'", $directory));
258         else
259             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
260                                 $directory));
261     } else {
262         $html = HTML::p(fmt("Using directory '%s'", $directory));
263     }
264
265     StartLoadDump($request, _("Dumping Pages"), $html);
266
267     $dbi = $request->getDbh();
268     $thispage = $request->getArg('pagename'); // for "Return to ..."
269     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
270         $excludeList = explodePageList($exclude); 
271     } else {
272         $excludeList = array();
273     }
274     if ($whichpages = $request->getArg('pages')) {  // which pagenames
275         if ($whichpages == '[]') // current page
276             $whichpages = $thispage;
277         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
278     } else {
279         $pages = $dbi->getAllPages();
280     }
281
282     $request_args = $request->args;
283     
284     while ($page = $pages->next()) {
285         $request->args = $request_args; // some plugins might change them (esp. on POST)
286         //if (! $request->getArg('start_debug'))
287         @set_time_limit(30); // Reset watchdog.
288
289         $pagename = $page->getName();
290         if (!isa($request,'MockRequest')) {
291             PrintXML(HTML::br(), $pagename, ' ... ');
292             flush();
293         }
294
295         if (in_array($pagename, $excludeList)) {
296             if (!isa($request,'MockRequest')) {
297                 PrintXML(_("Skipped."));
298                 flush();
299             }
300             continue;
301         }
302         $filename = FilenameForPage($pagename);
303         $msg = HTML();
304         if($page->getName() != $filename) {
305             $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
306                               " ... ");
307         }
308
309         if ($request->getArg('include') == 'all')
310             $data = MailifyPage($page, 0);
311         else
312             $data = MailifyPage($page);
313
314         if ( !($fd = fopen("$directory/$filename", "wb")) ) {
315             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
316                                                "$directory/$filename")));
317             $request->finish($msg);
318         }
319
320         $num = fwrite($fd, $data, strlen($data));
321         $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
322         if (!isa($request,'MockRequest')) {
323             PrintXML($msg);
324             flush();
325         }
326         assert($num == strlen($data));
327         fclose($fd);
328     }
329
330     EndLoadDump($request);
331 }
332
333 /**
334  * Dump all pages as XHTML to a directory, as pagename.html.
335  * Copies all used css files to the directory, all used images to a 
336  * "images" subdirectory, and all used buttons to a "images/buttons" subdirectory.
337  * The webserver must have write permissions to these directories. 
338  *   chown httpd HTML_DUMP_DIR; chmod u+rwx HTML_DUMP_DIR 
339  * should be enough.
340  *
341  * @param string directory (optional) path to dump to. Default: HTML_DUMP_DIR
342  * @param string pages     (optional) Comma-seperated of glob-style pagenames to dump
343  * @param string exclude   (optional) Comma-seperated of glob-style pagenames to exclude
344  */
345 function DumpHtmlToDir (&$request)
346 {
347     $directory = $request->getArg('directory');
348     if (empty($directory))
349         $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
350     if (empty($directory))
351         $request->finish(_("You must specify a directory to dump to"));
352
353     // see if we can access the directory the user wants us to use
354     if (! file_exists($directory)) {
355         if (! mkdir($directory, 0755))
356             $request->finish(fmt("Cannot create directory '%s'", $directory));
357         else
358             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
359                                 $directory));
360     } else {
361         $html = HTML::p(fmt("Using directory '%s'", $directory));
362     }
363
364     StartLoadDump($request, _("Dumping Pages"), $html);
365     $thispage = $request->getArg('pagename'); // for "Return to ..."
366
367     $dbi = $request->getDbh();
368     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
369         $excludeList = explodePageList($exclude); 
370     } else {
371         $excludeList = array();
372     }
373     if ($whichpages = $request->getArg('pages')) {  // which pagenames
374         if ($whichpages == '[]') // current page
375             $whichpages = $thispage;
376         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
377     } else {
378         $pages = $dbi->getAllPages();
379     }
380
381     global $WikiTheme;
382     if (defined('HTML_DUMP_SUFFIX'))
383         $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
384     $WikiTheme->DUMP_MODE = 'HTML';
385     $request_args = $request->args;
386     
387     while ($page = $pages->next()) {
388         $request->args = $request_args; // some plugins might change them (esp. on POST)
389         //if (!$request->getArg('start_debug'))
390         @set_time_limit(30); // Reset watchdog.
391           
392         $pagename = $page->getName();
393         if (!isa($request,'MockRequest')) {
394             PrintXML(HTML::br(), $pagename, ' ... ');
395             flush();
396         }
397         if (in_array($pagename, $excludeList)) {
398             if (!isa($request,'MockRequest')) {
399                 PrintXML(_("Skipped."));
400                 flush();
401             }
402             continue;
403         }
404
405         $request->setArg('pagename', $pagename); // Template::_basepage fix
406         $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
407         $msg = HTML();
408
409         $revision = $page->getCurrentRevision();
410         $transformedContent = $revision->getTransformedContent();
411         $template = new Template('browse', $request,
412                                  array('revision' => $revision,
413                                        'CONTENT' => $transformedContent));
414
415         $data = GeneratePageasXML($template, $pagename);
416
417         if ( !($fd = fopen("$directory/$filename", "wb")) ) {
418             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
419                                                "$directory/$filename")));
420             $request->finish($msg);
421         }
422         $num = fwrite($fd, $data, strlen($data));
423         if($page->getName() != $filename) {
424             $prefix = '';
425             if (isWindows()) {  
426                 // drive where apache is installed
427                 $prefix = '/' . substr($_SERVER["DOCUMENT_ROOT"],0,2);
428             }
429             $link = LinkURL("file://".$prefix.$directory."/".$filename, 
430                             $filename);
431             $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
432         }
433         $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
434         if (!isa($request,'MockRequest')) {
435             PrintXML($msg);
436             flush();
437         }
438
439         assert($num == strlen($data));
440         fclose($fd);
441     }
442
443     if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
444         @mkdir("$directory/images");
445         foreach ($WikiTheme->dumped_images as $img_file) {
446             if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
447                 $target = "$directory/images/".basename($img_file);
448                 if (copy($WikiTheme->_path . $from, $target)) {
449                     $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
450                     if (!isa($request,'MockRequest'))
451                         PrintXML($msg);
452                 }
453             } else {
454                 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
455                 if (!isa($request,'MockRequest'))
456                     PrintXML($msg);
457             }
458         }
459     }
460     if (!empty($WikiTheme->dumped_buttons) and is_array($WikiTheme->dumped_buttons)) {
461         // Buttons also
462         @mkdir("$directory/images/buttons");
463         foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
464             if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
465                 $target = "$directory/images/buttons/".basename($img_file);
466                 if (copy($WikiTheme->_path . $from, $target)) {
467                     $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
468                     if (!isa($request,'MockRequest'))
469                         PrintXML($msg);
470                 }
471             } else {
472                 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
473                 if (!isa($request,'MockRequest'))
474                     PrintXML($msg);
475             }
476         }
477     }
478     if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
479       foreach ($WikiTheme->dumped_css as $css_file) {
480           if (($from = $WikiTheme->_findFile(basename($css_file))) and basename($from)) {
481               $target = "$directory/" . basename($css_file);
482               if (copy($WikiTheme->_path . $from, $target)) {
483                   $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
484                   if (!isa($request,'MockRequest'))
485                       PrintXML($msg);
486               }
487           } else {
488               $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
489               if (!isa($request,'MockRequest'))
490                   PrintXML($msg);
491           }
492       }
493     }
494     $WikiTheme->HTML_DUMP_SUFFIX = '';
495     $WikiTheme->DUMP_MODE = false;
496
497     $request->setArg('pagename',$thispage); // Template::_basepage fix
498     EndLoadDump($request);
499 }
500
501 /* Known problem: any plugins or other code which echo()s text will
502  * lead to a corrupted html zip file which may produce the following
503  * errors upon unzipping:
504  *
505  * warning [wikihtml.zip]:  2401 extra bytes at beginning or within zipfile
506  * file #58:  bad zipfile offset (local header sig):  177561
507  *  (attempting to re-compensate)
508  *
509  * However, the actual wiki page data should be unaffected.
510  */
511 function MakeWikiZipHtml (&$request)
512 {
513     $zipname = "wikihtml.zip";
514     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
515     $dbi = $request->getDbh();
516     $thispage = $request->getArg('pagename'); // for "Return to ..."
517     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
518         $excludeList = explodePageList($exclude); 
519     } else {
520         $excludeList = array();
521     }
522     if ($whichpages = $request->getArg('pages')) {  // which pagenames
523         if ($whichpages == '[]') // current page
524             $whichpages = $thispage;
525         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
526     } else {
527         $pages = $dbi->getAllPages();
528     }
529
530     global $WikiTheme;
531     if (defined('HTML_DUMP_SUFFIX'))
532         $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
533
534     /* ignore fatals in plugins */
535     if (check_php_version(4,1)) {
536         global $ErrorManager;
537         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
538     }
539
540     $request_args = $request->args;
541     
542     while ($page = $pages->next()) {
543         $request->args = $request_args; // some plugins might change them (esp. on POST)
544         //if (! $request->getArg('start_debug'))
545         @set_time_limit(30); // Reset watchdog.
546
547         $current = $page->getCurrentRevision();
548         if ($current->getVersion() == 0)
549             continue;
550         $pagename = $page->getName();
551         if (in_array($pagename, $excludeList)) {
552             continue;
553         }
554
555         $attrib = array('mtime'    => $current->get('mtime'),
556                         'is_ascii' => 1);
557         if ($page->get('locked'))
558             $attrib['write_protected'] = 1;
559
560         $request->setArg('pagename',$pagename); // Template::_basepage fix
561         $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
562         $revision = $page->getCurrentRevision();
563
564         $transformedContent = $revision->getTransformedContent();
565
566         $template = new Template('browse', $request,
567                                  array('revision' => $revision,
568                                        'CONTENT' => $transformedContent));
569
570         $data = GeneratePageasXML($template, $pagename);
571
572         $zip->addRegularFile( $filename, $data, $attrib);
573     }
574     // FIXME: Deal with images here.
575     $zip->finish();
576     if (check_php_version(4,1)) {
577         $ErrorManager->popErrorHandler();
578     }
579     $WikiTheme->$HTML_DUMP_SUFFIX = '';
580 }
581
582
583 ////////////////////////////////////////////////////////////////
584 //
585 //  Functions for restoring.
586 //
587 ////////////////////////////////////////////////////////////////
588
589 function SavePage (&$request, $pageinfo, $source, $filename)
590 {
591     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
592     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
593
594     if (empty($pageinfo['pagename'])) {
595         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
596         return;
597     }
598
599     if (empty($versiondata['author_id']))
600         $versiondata['author_id'] = $versiondata['author'];
601
602     $pagename = $pageinfo['pagename'];
603     $content  = $pageinfo['content'];
604
605     if ($pagename ==_("InterWikiMap"))
606         $content = _tryinsertInterWikiMap($content);
607
608     $dbi = $request->getDbh();
609     $page = $dbi->getPage($pagename);
610
611     // Try to merge if updated pgsrc contents are different. This
612     // whole thing is hackish
613     //
614     // TODO: try merge unless:
615     // if (current contents = default contents && pgsrc_version >=
616     // pgsrc_version) then just upgrade this pgsrc
617     $needs_merge = false;
618     $merging = false;
619     $overwrite = false;
620
621     if ($request->getArg('merge')) {
622         $merging = true;
623     }
624     else if ($request->getArg('overwrite')) {
625         $overwrite = true;
626     }
627
628     $current = $page->getCurrentRevision();
629     if ( (! $current->hasDefaultContents())
630          && ($current->getPackedContent() != $content)
631          && ($merging == true) ) {
632         include_once('lib/editpage.php');
633         $request->setArg('pagename', $pagename);
634         $r = $current->getVersion();
635         $request->setArg('revision', $current->getVersion());
636         $p = new LoadFileConflictPageEditor($request);
637         $p->_content = $content;
638         $p->_currentVersion = $r - 1;
639         $p->editPage($saveFailed = true);
640         return; //early return
641     }
642
643     foreach ($pagedata as $key => $value) {
644         if (!empty($value))
645             $page->set($key, $value);
646     }
647
648     $mesg = HTML::dd();
649     $skip = false;
650     if ($source)
651         $mesg->pushContent(' ', fmt("from %s", $source));
652
653
654     //$current = $page->getCurrentRevision();
655     if ($current->getVersion() == 0) {
656         $mesg->pushContent(' - ', _("new page"));
657         $isnew = true;
658     }
659     else {
660         if ( (! $current->hasDefaultContents())
661              && ($current->getPackedContent() != $content) ) {
662             if ($overwrite) {
663                 $mesg->pushContent(' ',
664                                    fmt("has edit conflicts - overwriting anyway"));
665                 $skip = false;
666                 if (substr_count($source, 'pgsrc')) {
667                     $versiondata['author'] = _("The PhpWiki programming team");
668                     // but leave authorid as userid who loaded the file
669                 }
670             }
671             else {
672                 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
673                 $needs_merge = true; // hackish
674                 $skip = true;
675             }
676         }
677         else if ($current->getPackedContent() == $content
678                  && $current->get('author') == $versiondata['author']) {
679             // The page metadata is already changed, we don't need a new revision.
680             // This was called previously "is identical to current version %d - skipped"
681             // which is wrong, since the pagedata was stored, not skipped.
682             $mesg->pushContent(' ',
683                                fmt("content is identical to current version %d - no new revision created",
684                                    $current->getVersion()));
685             $skip = true;
686         }
687         $isnew = false;
688     }
689
690     if (! $skip ) {
691         // in case of failures print the culprit:
692         if (!isa($request,'MockRequest')) {
693             PrintXML(HTML::dt(WikiLink($pagename))); flush();
694         }
695         $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
696         $dbi->touch();
697         $mesg->pushContent(' ', fmt("- saved to database as version %d",
698                                     $new->getVersion()));
699     }
700     if ($needs_merge) {
701         $f = $source;
702         // hackish, $source contains needed path+filename
703         $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
704         $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
705         $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
706         //check if uploaded file? they pass just the content, but the file is gone
707         if (@stat($f)) {
708             global $WikiTheme;
709             $meb = Button(array('action' => 'loadfile',
710                                 'merge'=> true,
711                                 'source'=> $f),
712                           _("Merge Edit"),
713                           _("PhpWikiAdministration"),
714                           'wikiadmin');
715             $owb = Button(array('action' => 'loadfile',
716                                 'overwrite'=> true,
717                                 'source'=> $f),
718                           _("Restore Anyway"),
719                           _("PhpWikiAdministration"),
720                           'wikiunsafe');
721             $mesg->pushContent(' ', $meb, " ", $owb);
722         } else {
723             $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
724         }
725     }
726
727     if (!isa($request,'MockRequest')) {
728       if ($skip)
729         PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
730       else
731         PrintXML($mesg);
732       flush();
733     }
734 }
735
736 // action=revert (by diff)
737 function RevertPage (&$request)
738 {
739     $mesg = HTML::dd();
740     $pagename = $request->getArg('pagename');
741     $version = $request->getArg('version');
742     if (!$version) {
743         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
744                  HTML::dd(_("missing required version argument")));
745         return;
746     }
747     $dbi = $request->getDbh();
748     $page = $dbi->getPage($pagename);
749     $current = $page->getCurrentRevision();
750     if ($current->getVersion() == 0) {
751         $mesg->pushContent(' ', _("no page content"));
752         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
753                  $mesg);
754         return;
755     }
756     if ($current->getVersion() == $version) {
757         $mesg->pushContent(' ', _("same version page"));
758         return;
759     }
760     $rev = $page->getRevision($version);
761     $content = $rev->getPackedContent();
762     $versiondata = $rev->_data;
763     $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
764     $new = $page->save($content, $current->getVersion() + 1, $versiondata);
765     $dbi->touch();
766     $mesg->pushContent(' ', fmt("- version %d saved to database as version %d",
767                                 $version, $new->getVersion()));
768     PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
769              $mesg);
770     flush();
771 }
772
773 function _tryinsertInterWikiMap($content) {
774     $goback = false;
775     if (strpos($content, "<verbatim>")) {
776         //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
777         $goback = true;
778     }
779     if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
780         $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
781         $goback = true;
782     }
783     $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
784     if (!$goback && !file_exists($mapfile)) {
785         $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
786         $goback = true;
787     }
788
789     if (!empty($error_html))
790         trigger_error(_("Default InterWiki map file not loaded.")
791                       . $error_html, E_USER_NOTICE);
792     if ($goback)
793         return $content;
794
795     // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
796     echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
797
798     $fd = fopen ($mapfile, "rb");
799     $data = fread ($fd, filesize($mapfile));
800     fclose ($fd);
801     $content = $content . "\n<verbatim>\n$data</verbatim>\n";
802     return $content;
803 }
804
805 function ParseSerializedPage($text, $default_pagename, $user)
806 {
807     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
808         return false;
809
810     $pagehash = unserialize($text);
811
812     // Split up pagehash into four parts:
813     //   pagename
814     //   content
815     //   page-level meta-data
816     //   revision-level meta-data
817
818     if (!defined('FLAG_PAGE_LOCKED'))
819         define('FLAG_PAGE_LOCKED', 1);
820     $pageinfo = array('pagedata'    => array(),
821                       'versiondata' => array());
822
823     $pagedata = &$pageinfo['pagedata'];
824     $versiondata = &$pageinfo['versiondata'];
825
826     // Fill in defaults.
827     if (empty($pagehash['pagename']))
828         $pagehash['pagename'] = $default_pagename;
829     if (empty($pagehash['author'])) {
830         $pagehash['author'] = $user->getId();
831     }
832
833     foreach ($pagehash as $key => $value) {
834         switch($key) {
835             case 'pagename':
836             case 'version':
837             case 'hits':
838                 $pageinfo[$key] = $value;
839                 break;
840             case 'content':
841                 $pageinfo[$key] = join("\n", $value);
842                 break;
843             case 'flags':
844                 if (($value & FLAG_PAGE_LOCKED) != 0)
845                     $pagedata['locked'] = 'yes';
846                 break;
847             case 'owner':
848             case 'created':
849                 $pagedata[$key] = $value;
850                 break;
851             case 'acl':
852             case 'perm':
853                 $pagedata['perm'] = ParseMimeifiedPerm($value);
854                 break;
855             case 'lastmodified':
856                 $versiondata['mtime'] = $value;
857                 break;
858             case 'author':
859             case 'author_id':
860             case 'summary':
861                 $versiondata[$key] = $value;
862                 break;
863         }
864     }
865     return $pageinfo;
866 }
867
868 function SortByPageVersion ($a, $b) {
869     return $a['version'] - $b['version'];
870 }
871
872 function LoadFile (&$request, $filename, $text = false, $mtime = false)
873 {
874     if (!is_string($text)) {
875         // Read the file.
876         $stat  = stat($filename);
877         $mtime = $stat[9];
878         $text  = implode("", file($filename));
879     }
880
881     //if (! $request->getArg('start_debug'))
882     @set_time_limit(30); // Reset watchdog.
883
884     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
885     $basename = basename("/dummy/" . $filename);
886
887     if (!$mtime)
888         $mtime = time();    // Last resort.
889
890     $default_pagename = rawurldecode($basename);
891
892     if ( ($parts = ParseMimeifiedPages($text)) ) {
893         usort($parts, 'SortByPageVersion');
894         foreach ($parts as $pageinfo)
895             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
896                                                   $filename), $basename);
897     }
898     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
899                                                $request->getUser())) ) {
900         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
901                                               $filename), $basename);
902     }
903     else {
904         $user = $request->getUser();
905
906         // Assume plain text file.
907         $pageinfo = array('pagename' => $default_pagename,
908                           'pagedata' => array(),
909                           'versiondata'
910                           => array('author' => $user->getId()),
911                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
912                                                      chop($text))
913                           );
914         SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
915                  $basename);
916     }
917 }
918
919 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
920     $zip = new ZipReader($zipfile);
921     while (list ($fn, $data, $attrib) = $zip->readFile()) {
922         // FIXME: basename("filewithnoslashes") seems to return
923         // garbage sometimes.
924         $fn = basename("/dummy/" . $fn);
925         if ( ($files && !in_array($fn, $files))
926              || ($exclude && in_array($fn, $exclude)) ) {
927             PrintXML(HTML::dt(WikiLink($fn)),
928                      HTML::dd(_("Skipping")));
929             flush();
930             continue;
931         }
932
933         LoadFile($request, $fn, $data, $attrib['mtime']);
934     }
935 }
936
937 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
938     $fileset = new LimitedFileSet($dirname, $files, $exclude);
939
940     if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
941         PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
942         $list = HTML::ul();
943         foreach ($skiplist as $file)
944             $list->pushContent(HTML::li(WikiLink($file)));
945         PrintXML(HTML::dd($list));
946     }
947
948     // Defer HomePage loading until the end. If anything goes wrong
949     // the pages can still be loaded again.
950     $files = $fileset->getFiles();
951     if (in_array(HOME_PAGE, $files)) {
952         $files = array_diff($files, array(HOME_PAGE));
953         $files[] = HOME_PAGE;
954     }
955     foreach ($files as $file) {
956         if (substr($file,-1,1) != '~') // refuse to load backup files
957             LoadFile($request, "$dirname/$file");
958     }
959 }
960
961 class LimitedFileSet extends FileSet {
962     function LimitedFileSet($dirname, $_include, $exclude) {
963         $this->_includefiles = $_include;
964         $this->_exclude = $exclude;
965         $this->_skiplist = array();
966         parent::FileSet($dirname);
967     }
968
969     function _filenameSelector($fn) {
970         $incl = &$this->_includefiles;
971         $excl = &$this->_exclude;
972
973         if ( ($incl && !in_array($fn, $incl))
974              || ($excl && in_array($fn, $excl)) ) {
975             $this->_skiplist[] = $fn;
976             return false;
977         } else {
978             return true;
979         }
980     }
981
982     function getSkippedFiles () {
983         return $this->_skiplist;
984     }
985 }
986
987
988 function IsZipFile ($filename_or_fd)
989 {
990     // See if it looks like zip file
991     if (is_string($filename_or_fd))
992     {
993         $fd    = fopen($filename_or_fd, "rb");
994         $magic = fread($fd, 4);
995         fclose($fd);
996     }
997     else
998     {
999         $fpos  = ftell($filename_or_fd);
1000         $magic = fread($filename_or_fd, 4);
1001         fseek($filename_or_fd, $fpos);
1002     }
1003
1004     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1005 }
1006
1007
1008 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
1009 {
1010     // Try urlencoded filename for accented characters.
1011     if (!file_exists($file_or_dir)) {
1012         // Make sure there are slashes first to avoid confusing phps
1013         // with broken dirname or basename functions.
1014         // FIXME: windows uses \ and :
1015         if (is_integer(strpos($file_or_dir, "/"))) {
1016             $file_or_dir = FindFile($file_or_dir);
1017             // Panic
1018             if (!file_exists($file_or_dir))
1019                 $file_or_dir = dirname($file_or_dir) . "/"
1020                     . urlencode(basename($file_or_dir));
1021         } else {
1022             // This is probably just a file.
1023             $file_or_dir = urlencode($file_or_dir);
1024         }
1025     }
1026
1027     $type = filetype($file_or_dir);
1028     if ($type == 'link') {
1029         // For symbolic links, use stat() to determine
1030         // the type of the underlying file.
1031         list(,,$mode) = stat($file_or_dir);
1032         $type = ($mode >> 12) & 017;
1033         if ($type == 010)
1034             $type = 'file';
1035         elseif ($type == 004)
1036             $type = 'dir';
1037     }
1038
1039     if (! $type) {
1040         $request->finish(fmt("Unable to load: %s", $file_or_dir));
1041     }
1042     else if ($type == 'dir') {
1043         LoadDir($request, $file_or_dir, $files, $exclude);
1044     }
1045     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
1046     {
1047         $request->finish(fmt("Bad file type: %s", $type));
1048     }
1049     else if (IsZipFile($file_or_dir)) {
1050         LoadZip($request, $file_or_dir, $files, $exclude);
1051     }
1052     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
1053     {
1054         LoadFile($request, $file_or_dir);
1055     }
1056 }
1057
1058 function LoadFileOrDir (&$request)
1059 {
1060     $source = $request->getArg('source');
1061     $finder = new FileFinder;
1062     $source = $finder->slashifyPath($source);
1063     $page = rawurldecode(basename($source));
1064     StartLoadDump($request, fmt("Loading '%s'", 
1065         HTML(dirname($source),
1066              dirname($source) ? "/" : "",
1067              WikiLink($page,'auto'))));
1068     echo "<dl>\n";
1069     LoadAny($request, $source);
1070     echo "</dl>\n";
1071     EndLoadDump($request);
1072 }
1073
1074 function SetupWiki (&$request)
1075 {
1076     global $GenericPages, $LANG;
1077
1078
1079     //FIXME: This is a hack (err, "interim solution")
1080     // This is a bogo-bogo-login:  Login without
1081     // saving login information in session state.
1082     // This avoids logging in the unsuspecting
1083     // visitor as "The PhpWiki programming team".
1084     //
1085     // This really needs to be cleaned up...
1086     // (I'm working on it.)
1087     $real_user = $request->_user;
1088     if (ENABLE_USER_NEW)
1089         $request->_user = new _BogoUser(_("The PhpWiki programming team"));
1090
1091     else
1092         $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
1093                                        WIKIAUTH_BOGO);
1094
1095     StartLoadDump($request, _("Loading up virgin wiki"));
1096     echo "<dl>\n";
1097
1098     $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1099     $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1100
1101     $request->setArg('overwrite',true);
1102     if ($default_pgsrc != $pgsrc) {
1103         LoadAny($request, $default_pgsrc, $GenericPages);
1104     }
1105     $request->setArg('overwrite',false);
1106     LoadAny($request, $pgsrc);
1107
1108     // Ensure that all mandatory pages are loaded
1109     $finder = new FileFinder;
1110     foreach (array_merge(explode(':','OldTextFormattingRules:TextFormattingRules:PhpWikiAdministration'),
1111                          $GLOBALS['AllActionPages'],
1112                          array(constant('HOME_PAGE'))) as $f) {
1113         $page = gettext($f);
1114         if (isSubPage($page))
1115             $page = urlencode($page);
1116         if (! $request->_dbi->isWikiPage(urldecode($page)) ) {
1117             // translated version provided?
1118             if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $page, 1))
1119                 LoadAny($request, $lf);
1120             else { // load english version of required action page
1121                 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1122                 $page = $f;
1123             }
1124         }
1125         if (!$request->_dbi->isWikiPage(urldecode($page))) {
1126             trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1127                           E_USER_WARNING);
1128         }
1129     }
1130
1131     echo "</dl>\n";
1132     EndLoadDump($request);
1133 }
1134
1135 function LoadPostFile (&$request)
1136 {
1137     $upload = $request->getUploadedFile('file');
1138
1139     if (!$upload)
1140         $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1141
1142
1143     // Dump http headers.
1144     StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1145     echo "<dl>\n";
1146
1147     $fd = $upload->open();
1148     if (IsZipFile($fd))
1149         LoadZip($request, $fd, false, array(_("RecentChanges")));
1150     else
1151         LoadFile($request, $upload->getName(), $upload->getContents());
1152
1153     echo "</dl>\n";
1154     EndLoadDump($request);
1155 }
1156
1157 /**
1158  $Log: not supported by cvs2svn $
1159  Revision 1.117  2004/07/02 09:55:58  rurban
1160  more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
1161
1162  Revision 1.116  2004/07/01 09:05:41  rurban
1163  support pages and exclude arguments for all 4 dump methods
1164
1165  Revision 1.115  2004/07/01 08:51:22  rurban
1166  dumphtml: added exclude, print pagename before processing
1167
1168  Revision 1.114  2004/06/28 12:51:41  rurban
1169  improved dumphtml and virgin setup
1170
1171  Revision 1.113  2004/06/27 10:26:02  rurban
1172  oci8 patch by Philippe Vanhaesendonck + some ADODB notes+fixes
1173
1174  Revision 1.112  2004/06/25 14:29:20  rurban
1175  WikiGroup refactoring:
1176    global group attached to user, code for not_current user.
1177    improved helpers for special groups (avoid double invocations)
1178  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
1179  fixed a XHTML validation error on userprefs.tmpl
1180
1181  Revision 1.111  2004/06/21 16:38:55  rurban
1182  fixed the StartLoadDump html argument hack.
1183
1184  Revision 1.110  2004/06/21 16:22:30  rurban
1185  add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1186  fixed dumping buttons locally (images/buttons/),
1187  support pages arg for dumphtml,
1188  optional directory arg for dumpserial + dumphtml,
1189  fix a AllPages warning,
1190  show dump warnings/errors on DEBUG,
1191  don't warn just ignore on wikilens pagelist columns, if not loaded.
1192  RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1193
1194  Revision 1.109  2004/06/17 11:31:05  rurban
1195  jump back to label after dump/upgrade
1196
1197  Revision 1.108  2004/06/16 12:43:01  rurban
1198  4.0.6 cannot use this errorhandler (not found)
1199
1200  Revision 1.107  2004/06/14 11:31:37  rurban
1201  renamed global $Theme to $WikiTheme (gforge nameclash)
1202  inherit PageList default options from PageList
1203    default sortby=pagename
1204  use options in PageList_Selectable (limit, sortby, ...)
1205  added action revert, with button at action=diff
1206  added option regex to WikiAdminSearchReplace
1207
1208  Revision 1.106  2004/06/13 13:54:25  rurban
1209  Catch fatals on the four dump calls (as file and zip, as html and mimified)
1210  FoafViewer: Check against external requirements, instead of fatal.
1211  Change output for xhtmldumps: using file:// urls to the local fs.
1212  Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1213  Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1214
1215  Revision 1.105  2004/06/08 19:48:16  rurban
1216  fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1217
1218  Revision 1.104  2004/06/08 13:51:57  rurban
1219  some comments only
1220
1221  Revision 1.103  2004/06/08 10:54:46  rurban
1222  better acl dump representation, read back acl and owner
1223
1224  Revision 1.102  2004/06/06 16:58:51  rurban
1225  added more required ActionPages for foreign languages
1226  install now english ActionPages if no localized are found. (again)
1227  fixed default anon user level to be 0, instead of -1
1228    (wrong "required administrator to view this page"...)
1229
1230  Revision 1.101  2004/06/04 20:32:53  rurban
1231  Several locale related improvements suggested by Pierrick Meignen
1232  LDAP fix by John Cole
1233  reanable admin check without ENABLE_PAGEPERM in the admin plugins
1234
1235  Revision 1.100  2004/05/02 21:26:38  rurban
1236  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1237    because they will not survive db sessions, if too large.
1238  extended action=upgrade
1239  some WikiTranslation button work
1240  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1241  some temp. session debug statements
1242
1243  Revision 1.99  2004/05/02 15:10:07  rurban
1244  new finally reliable way to detect if /index.php is called directly
1245    and if to include lib/main.php
1246  new global AllActionPages
1247  SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1248  WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1249  PageGroupTestOne => subpages
1250  renamed PhpWikiRss to PhpWikiRecentChanges
1251  more docs, default configs, ...
1252
1253  Revision 1.98  2004/04/29 23:25:12  rurban
1254  re-ordered locale init (as in 1.3.9)
1255  fixed loadfile with subpages, and merge/restore anyway
1256    (sf.net bug #844188)
1257
1258  Revision 1.96  2004/04/19 23:13:03  zorloc
1259  Connect the rest of PhpWiki to the IniConfig system.  Also the keyword regular expression is not a config setting
1260
1261  Revision 1.95  2004/04/18 01:11:52  rurban
1262  more numeric pagename fixes.
1263  fixed action=upload with merge conflict warnings.
1264  charset changed from constant to global (dynamic utf-8 switching)
1265
1266  Revision 1.94  2004/03/14 16:36:37  rurban
1267  dont load backup files
1268
1269  Revision 1.93  2004/02/26 03:22:05  rurban
1270  also copy css and images with XHTML Dump
1271
1272  Revision 1.92  2004/02/26 02:25:54  rurban
1273  fix empty and #-anchored links in XHTML Dumps
1274
1275  Revision 1.91  2004/02/24 17:19:37  rurban
1276  debugging helpers only
1277
1278  Revision 1.90  2004/02/24 17:09:24  rurban
1279  fixed \r\r\n with dumping on windows
1280
1281  Revision 1.88  2004/02/22 23:20:31  rurban
1282  fixed DumpHtmlToDir,
1283  enhanced sortby handling in PageList
1284    new button_heading th style (enabled),
1285  added sortby and limit support to the db backends and plugins
1286    for paging support (<<prev, next>> links on long lists)
1287
1288  Revision 1.87  2004/01/26 09:17:49  rurban
1289  * changed stored pref representation as before.
1290    the array of objects is 1) bigger and 2)
1291    less portable. If we would import packed pref
1292    objects and the object definition was changed, PHP would fail.
1293    This doesn't happen with an simple array of non-default values.
1294  * use $prefs->retrieve and $prefs->store methods, where retrieve
1295    understands the interim format of array of objects also.
1296  * simplified $prefs->get() and fixed $prefs->set()
1297  * added $user->_userid and class '_WikiUser' portability functions
1298  * fixed $user object ->_level upgrading, mostly using sessions.
1299    this fixes yesterdays problems with loosing authorization level.
1300  * fixed WikiUserNew::checkPass to return the _level
1301  * fixed WikiUserNew::isSignedIn
1302  * added explodePageList to class PageList, support sortby arg
1303  * fixed UserPreferences for WikiUserNew
1304  * fixed WikiPlugin for empty defaults array
1305  * UnfoldSubpages: added pagename arg, renamed pages arg,
1306    removed sort arg, support sortby arg
1307
1308  Revision 1.86  2003/12/02 16:18:26  carstenklapp
1309  Minor enhancement: Provide more meaningful filenames for WikiDB zip
1310  dumps & snapshots.
1311
1312  Revision 1.85  2003/11/30 18:18:13  carstenklapp
1313  Minor code optimization: use include_once instead of require_once
1314  inside functions that might not always called.
1315
1316  Revision 1.84  2003/11/26 20:47:47  carstenklapp
1317  Redo bugfix: My last refactoring broke merge-edit & overwrite
1318  functionality again, should be fixed now. Sorry.
1319
1320  Revision 1.83  2003/11/20 22:18:54  carstenklapp
1321  New feature: h1 during merge-edit displays WikiLink to original page.
1322  Internal changes: Replaced some hackish url-generation code in
1323  function SavePage (for pgsrc merge-edit) with appropriate Button()
1324  calls.
1325
1326  Revision 1.82  2003/11/18 19:48:01  carstenklapp
1327  Fixed missing gettext _() for button name.
1328
1329  Revision 1.81  2003/11/18 18:28:35  carstenklapp
1330  Bugfix: In the Load File function of PhpWikiAdministration: When doing
1331  a "Merge Edit" or "Restore Anyway", page names containing accented
1332  letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1333  found error (Use FilenameForPage funtion to urlencode page names).
1334
1335  Revision 1.80  2003/03/07 02:46:57  dairiki
1336  Omit checks for safe_mode before set_time_limit().  Just prefix the
1337  set_time_limit() calls with @ so that they fail silently if not
1338  supported.
1339
1340  Revision 1.79  2003/02/26 01:56:05  dairiki
1341  Only zip pages with legal pagenames.
1342
1343  Revision 1.78  2003/02/24 02:05:43  dairiki
1344  Fix "n bytes written" message when dumping HTML.
1345
1346  Revision 1.77  2003/02/21 04:12:05  dairiki
1347  Minor fixes for new cached markup.
1348
1349  Revision 1.76  2003/02/16 19:47:17  dairiki
1350  Update WikiDB timestamp when editing or deleting pages.
1351
1352  Revision 1.75  2003/02/15 03:04:30  dairiki
1353  Fix for WikiUser constructor API change.
1354
1355  Revision 1.74  2003/02/15 02:18:04  dairiki
1356  When default language was English (at least), pgsrc was being
1357  loaded twice.
1358
1359  LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1360
1361  SetupWiki(): Fix bugs in loading of $GenericPages.
1362
1363  Revision 1.73  2003/01/28 21:09:17  zorloc
1364  The get_cfg_var() function should only be used when one is
1365  interested in the value from php.ini or similar. Use ini_get()
1366  instead to get the effective value of a configuration variable.
1367  -- Martin Geisler
1368
1369  Revision 1.72  2003/01/03 22:25:53  carstenklapp
1370  Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1371  programming team" as author when loading from pgsrc. Source
1372  reformatting.
1373
1374  Revision 1.71  2003/01/03 02:48:05  carstenklapp
1375  function SavePage: Added loadfile options for overwriting or merge &
1376  compare a loaded pgsrc file with an existing page.
1377
1378  function LoadAny: Added a general error message when unable to load a
1379  file instead of defaulting to "Bad file type".
1380
1381  */
1382
1383 // For emacs users
1384 // Local Variables:
1385 // mode: php
1386 // tab-width: 8
1387 // c-basic-offset: 4
1388 // c-hanging-comment-ender-p: nil
1389 // indent-tabs-mode: nil
1390 // End:
1391 ?>