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