]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
Improve multi-page format handling: abstract _DumpHtmlToDir. get rid of non-external...
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php //-*-php-*-
2 rcs_id('$Id: loadsave.php,v 1.156 2007-09-15 12:32:50 rurban Exp $');
3
4 /*
5  Copyright 1999,2000,2001,2002,2004,2005,2006,2007 $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 require_once("lib/ziplib.php");
25 require_once("lib/Template.php");
26
27 /**
28  * ignore fatal errors during dump
29  */
30 function _dump_error_handler(&$error) {
31     if ($error->isFatal()) {
32         $error->errno = E_USER_WARNING;
33         return true;
34     }
35     return true;         // Ignore error
36     /*
37     if (preg_match('/Plugin/', $error->errstr))
38         return true;
39     */
40     // let the message come through: call the remaining handlers:
41     // return false; 
42 }
43
44 function StartLoadDump(&$request, $title, $html = '')
45 {
46     // MockRequest is from the unit testsuite, a faked request. (may be cmd-line)
47     // We are silent on unittests.
48     if (isa($request,'MockRequest'))
49         return;
50     // FIXME: This is a hack. This really is the worst overall hack in phpwiki.
51     if ($html)
52         $html->pushContent('%BODY%');
53     $tmpl = Template('html', array('TITLE' => $title,
54                                    'HEADER' => $title,
55                                    'CONTENT' => $html ? $html : '%BODY%'));
56     echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
57     $request->chunkOutput();
58     
59     // set marker for sendPageChangeNotification()
60     $request->_deferredPageChangeNotification = array();
61 }
62
63 function EndLoadDump(&$request)
64 {
65     if (isa($request,'MockRequest'))
66         return;
67     $action = $request->getArg('action');
68     $label = '';
69     switch ($action) {
70     case 'zip':        $label = _("ZIP files of database"); break;
71     case 'dumpserial': $label = _("Dump to directory"); break;
72     case 'upload':     $label = _("Upload File"); break;
73     case 'loadfile':   $label = _("Load File"); break;
74     case 'upgrade':    $label = _("Upgrade"); break;
75     case 'dumphtml': 
76     case 'ziphtml':    $label = _("Dump pages as XHTML"); break;
77     }
78     if ($label) $label = str_replace(" ","_",$label);
79     if ($action == 'browse') // loading virgin 
80         $pagelink = WikiLink(HOME_PAGE);
81     else
82         $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"),false,$label));
83
84     // do deferred sendPageChangeNotification()
85     if (!empty($request->_deferredPageChangeNotification)) {
86         $pages = $all_emails = $all_users = array();
87         foreach ($request->_deferredPageChangeNotification as $p) {
88             list($pagename, $emails, $userids) = $p;
89             $pages[] = $pagename;
90             $all_emails = array_unique(array_merge($all_emails, $emails));
91             $all_users = array_unique(array_merge($all_users, $userids));
92         }
93         $editedby = sprintf(_("Edited by: %s"), $request->_user->getId());
94         $content = "Loaded the following pages:\n" . join("\n", $pages);
95         if (mail(join(',',$all_emails),"[".WIKI_NAME."] "._("LoadDump"), 
96                  _("LoadDump")."\n".
97                  $editedby."\n\n".
98                  $content))
99             trigger_error(sprintf(_("PageChange Notification of %s sent to %s"),
100                                   join("\n",$pages), join(',',$all_users)), E_USER_NOTICE);
101         else
102             trigger_error(sprintf(_("PageChange Notification Error: Couldn't send %s to %s"),
103                                   join("\n",$pages), join(',',$all_users)), E_USER_WARNING);
104         unset($pages);
105         unset($all_emails);
106         unset($all_users);
107     }
108     unset($request->_deferredPageChangeNotification);
109
110     PrintXML(HTML::p(HTML::strong(_("Complete."))),
111              HTML::p(fmt("Return to %s", $pagelink)));
112     echo "</body></html>\n";
113 }
114
115
116 ////////////////////////////////////////////////////////////////
117 //
118 //  Functions for dumping.
119 //
120 ////////////////////////////////////////////////////////////////
121
122 /**
123  * For reference see:
124  * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
125  * http://www.faqs.org/rfcs/rfc2045.html
126  * (RFC 1521 has been superceeded by RFC 2045 & others).
127  *
128  * Also see http://www.faqs.org/rfcs/rfc2822.html
129  */
130 function MailifyPage ($page, $nversions = 1)
131 {
132     $current = $page->getCurrentRevision(false);
133     $head = '';
134
135     if (STRICT_MAILABLE_PAGEDUMPS) {
136         $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
137         //This is for unix mailbox format: (not RFC (2)822)
138         // $head .= "From $from  " . CTime(time()) . "\r\n";
139         $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
140         $head .= "From: $from (PhpWiki)\r\n";
141         // RFC 2822 requires only a Date: and originator (From:)
142         // field, however the obsolete standard RFC 822 also
143         // requires a destination field.
144         $head .= "To: $from (PhpWiki)\r\n";
145     }
146     $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
147     $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
148                      PHPWIKI_VERSION);
149
150     // This should just be entered by hand (or by script?)
151     // in the actual pgsrc files, since only they should have
152     // RCS ids.
153     //$head .= "X-Rcs-Id: \$Id\$\r\n";
154
155     $iter = $page->getAllRevisions();
156     $parts = array();
157     while ($revision = $iter->next()) {
158         $parts[] = MimeifyPageRevision($page, $revision);
159         if ($nversions > 0 && count($parts) >= $nversions)
160             break;
161     }
162     if (count($parts) > 1)
163         return $head . MimeMultipart($parts);
164     assert($parts);
165     return $head . $parts[0];
166 }
167
168 /***
169  * Compute filename to used for storing contents of a wiki page.
170  *
171  * Basically we do a rawurlencode() which encodes everything except
172  * ASCII alphanumerics and '.', '-', and '_'.
173  *
174  * But we also want to encode leading dots to avoid filenames like
175  * '.', and '..'. (Also, there's no point in generating "hidden" file
176  * names, like '.foo'.)
177  *
178  * We have to apply a different "/" logic for dumpserial, htmldump and zipdump.
179  * dirs are allowed for zipdump and htmldump, not for dumpserial
180  * 
181  *
182  * @param $pagename string Pagename.
183  * @return string Filename for page.
184  */
185 function FilenameForPage ($pagename, $action = false)
186 {
187     $enc = rawurlencode($pagename);
188     if (!$action) {
189         global $request;
190         $action = $request->getArg('action');
191     }
192     if ($action != 'dumpserial') { // zip, ziphtml, dumphtml
193         // For every %2F we will need to mkdir -p dirname($pagename)
194         $enc = preg_replace('/%2F/', '/', $enc);
195     }
196     $enc = preg_replace('/^\./', '%2E', $enc);
197     $enc = preg_replace('/%20/', ' ', $enc);
198     return $enc;
199 }
200
201 /**
202  * The main() function which generates a zip archive of a PhpWiki.
203  *
204  * If $include_archive is false, only the current version of each page
205  * is included in the zip file; otherwise all archived versions are
206  * included as well.
207  */
208 function MakeWikiZip (&$request)
209 {
210     if ($request->getArg('include') == 'all') {
211         $zipname         = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
212         $include_archive = true;
213     }
214     else {
215         $zipname         = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
216         $include_archive = false;
217     }
218
219
220     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
221
222     /* ignore fatals in plugins */
223     if (check_php_version(4,1)) {
224         global $ErrorManager;
225         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
226     }
227
228     $dbi =& $request->_dbi;
229     $thispage = $request->getArg('pagename'); // for "Return to ..."
230     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
231         $excludeList = explodePageList($exclude); 
232     } else {
233         $excludeList = array();
234     }
235     if ($pages = $request->getArg('pages')) {  // which pagenames
236         if ($pages == '[]') // current page
237             $pages = $thispage;
238         $page_iter = new WikiDB_Array_PageIterator(explodePageList($pages));
239     } else {
240         $page_iter = $dbi->getAllPages(false,false,false,$excludeList);
241     }
242     $request_args = $request->args;
243     $timeout = (! $request->getArg('start_debug')) ? 30 : 240;
244     
245     while ($page = $page_iter->next()) {
246         $request->args = $request_args; // some plugins might change them (esp. on POST)
247         longer_timeout($timeout);       // Reset watchdog
248
249         $current = $page->getCurrentRevision();
250         if ($current->getVersion() == 0)
251             continue;
252
253         $pagename = $page->getName();
254         $wpn = new WikiPageName($pagename);
255         if (!$wpn->isValid())
256             continue;
257         if (in_array($page->getName(), $excludeList)) {
258             continue;
259         }
260
261         $attrib = array('mtime'    => $current->get('mtime'),
262                         'is_ascii' => 1);
263         if ($page->get('locked'))
264             $attrib['write_protected'] = 1;
265
266         if ($include_archive)
267             $content = MailifyPage($page, 0);
268         else
269             $content = MailifyPage($page);
270
271         $zip->addRegularFile( FilenameForPage($pagename),
272                               $content, $attrib);
273     }
274     $zip->finish();
275     if (check_php_version(4,1)) {
276         global $ErrorManager;
277         $ErrorManager->popErrorHandler();
278     }
279 }
280
281 function DumpToDir (&$request)
282 {
283     $directory = $request->getArg('directory');
284     if (empty($directory))
285         $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
286     if (empty($directory))
287         $request->finish(_("You must specify a directory to dump to"));
288
289     // see if we can access the directory the user wants us to use
290     if (! file_exists($directory)) {
291         if (! mkdir($directory, 0755))
292             $request->finish(fmt("Cannot create directory '%s'", $directory));
293         else
294             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
295                                 $directory));
296     } else {
297         $html = HTML::p(fmt("Using directory '%s'", $directory));
298     }
299
300     StartLoadDump($request, _("Dumping Pages"), $html);
301
302     $dbi =& $request->_dbi;
303     $thispage = $request->getArg('pagename'); // for "Return to ..."
304     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
305         $excludeList = explodePageList($exclude); 
306     } else {
307         $excludeList = array();
308     }
309     if ($pages = $request->getArg('pages')) {  // which pagenames
310         if ($pages == '[]') // current page
311             $pages = $thispage;
312         $page_iter = new WikiDB_Array_PageIterator(explodePageList($pages));
313     } else {
314         $page_iter = $dbi->getAllPages(false,false,false,$excludeList);
315     }
316
317     $request_args = $request->args;
318     $timeout = (! $request->getArg('start_debug')) ? 30 : 240;
319
320     while ($page = $page_iter->next()) {
321         $request->args = $request_args; // some plugins might change them (esp. on POST)
322         longer_timeout($timeout);       // Reset watchdog
323
324         $pagename = $page->getName();
325         if (!isa($request,'MockRequest')) {
326             PrintXML(HTML::br(), $pagename, ' ... ');
327             flush();
328         }
329
330         if (in_array($pagename, $excludeList)) {
331             if (!isa($request, 'MockRequest')) {
332                 PrintXML(_("Skipped."));
333                 flush();
334             }
335             continue;
336         }
337         $filename = FilenameForPage($pagename);
338         $msg = HTML();
339         if($page->getName() != $filename) {
340             $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
341                               " ... ");
342         }
343
344         if ($request->getArg('include') == 'all')
345             $data = MailifyPage($page, 0);
346         else
347             $data = MailifyPage($page);
348
349         if ( !($fd = fopen($directory."/".$filename, "wb")) ) {
350             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
351                                                "$directory/$filename")));
352             $request->finish($msg);
353         }
354
355         $num = fwrite($fd, $data, strlen($data));
356         $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
357         if (!isa($request, 'MockRequest')) {
358             PrintXML($msg);
359             flush();
360         }
361         assert($num == strlen($data));
362         fclose($fd);
363     }
364
365     EndLoadDump($request);
366 }
367
368 function _copyMsg($page, $smallmsg) {
369     if (!isa($GLOBALS['request'], 'MockRequest')) {
370         if ($page) $msg = HTML(HTML::br(), HTML($page), HTML::small($smallmsg));
371         else $msg = HTML::small($smallmsg);
372         PrintXML($msg);
373         flush();
374     }
375 }
376
377 function mkdir_p($pathname, $permission = 0777) {
378     $arr = explode("/", $pathname);
379     if (empty($arr)) {
380         return mkdir($pathname, $permission);
381     }
382     $s = array_shift($arr);
383     $ok = TRUE;
384     foreach ($arr as $p) {
385         $curr = "$s/$p";
386         if (!is_dir($curr))
387             $ok = mkdir($curr, $permission);
388         $s = $curr;
389         if (!$ok) return FALSE;
390     }
391     return TRUE;
392 }
393
394 /**
395  * Dump all pages as XHTML to a directory, as pagename.html.
396  * Copies all used css files to the directory, all used images to a 
397  * "images" subdirectory, and all used buttons to a "images/buttons" subdirectory.
398  * The webserver must have write permissions to these directories. 
399  *   chown httpd HTML_DUMP_DIR; chmod u+rwx HTML_DUMP_DIR 
400  * should be enough.
401  *
402  * @param string directory (optional) path to dump to. Default: HTML_DUMP_DIR
403  * @param string pages     (optional) Comma-seperated of glob-style pagenames to dump.
404  *                                    Also array of pagenames allowed.
405  * @param string exclude   (optional) Comma-seperated of glob-style pagenames to exclude
406  */
407 function DumpHtmlToDir (&$request)
408 {
409     global $WikiTheme;
410     $directory = $request->getArg('directory');
411     if (empty($directory))
412         $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
413     if (empty($directory))
414         $request->finish(_("You must specify a directory to dump to"));
415
416     // See if we can access the directory the user wants us to use
417     if (! file_exists($directory)) {
418         if (! mkdir($directory, 0755))
419             $request->finish(fmt("Cannot create directory '%s'", $directory));
420         else
421             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
422                                 $directory));
423     } else {
424         $html = HTML::p(fmt("Using directory '%s'", $directory));
425     }
426     StartLoadDump($request, _("Dumping Pages"), $html);
427     $thispage = $request->getArg('pagename'); // for "Return to ..."
428
429     $dbi =& $request->_dbi;
430     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
431         $excludeList = explodePageList($exclude);
432     } else {
433         $excludeList = array('DebugAuthInfo', 'DebugGroupInfo', 'AuthInfo');
434     }
435     if ($pages = $request->getArg('pages')) {  // which pagenames
436         if ($pages == '[]') // current page
437             $pages = $thispage;
438         $page_iter = new WikiDB_Array_generic_iter(explodePageList($pages));
439     // not at admin page: dump only the current page
440     } elseif ($thispage != _("PhpWikiAdministration")) { 
441         $page_iter = new WikiDB_Array_generic_iter(array($thispage));
442     } else {
443         $page_iter = $dbi->getAllPages(false,false,false,$excludeList);
444     }
445
446     $WikiTheme->DUMP_MODE = 'HTML';
447     _DumpHtmlToDir($directory, $page_iter, $request->getArg('exclude'));
448     $WikiTheme->DUMP_MODE = false;
449
450     $request->setArg('pagename',$thispage); // Template::_basepage fix
451     EndLoadDump($request);
452 }
453
454 /* Known problem: any plugins or other code which echo()s text will
455  * lead to a corrupted html zip file which may produce the following
456  * errors upon unzipping:
457  *
458  * warning [wikihtml.zip]:  2401 extra bytes at beginning or within zipfile
459  * file #58:  bad zipfile offset (local header sig):  177561
460  *  (attempting to re-compensate)
461  *
462  * However, the actual wiki page data should be unaffected.
463  */
464 function MakeWikiZipHtml (&$request)
465 {
466     global $WikiTheme;
467     if ($request->getArg('zipname')) {
468         $zipname = basename($request->getArg('zipname'));
469         if (!preg_match("/\.zip$/i", $zipname))
470             $zipname .= ".zip";
471         $request->setArg('zipname', false);
472     } else {
473         $zipname = "wikihtml.zip";
474     }
475     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
476     $dbi =& $request->_dbi;
477     $thispage = $request->getArg('pagename'); // for "Return to ..."
478     if ($pages = $request->getArg('pages')) {  // which pagenames
479         if ($pages == '[]') // current page
480             $pages = $thispage;
481         $page_iter = new WikiDB_Array_generic_iter(explodePageList($pages));
482     } else {
483         $page_iter = $dbi->getAllPages(false,false,false,$request->getArg('exclude'));
484     }
485
486     $WikiTheme->DUMP_MODE = 'ZIPHTML';
487     _DumpHtmlToDir($zip, $page_iter, $request->getArg('exclude'));
488     $WikiTheme->DUMP_MODE = false;
489 }
490
491 /*
492  * Internal html dumper. Used for dumphtml, ziphtml and pdf
493  */
494 function _DumpHtmlToDir ($target, $page_iter, $exclude = false)
495 {
496     global $WikiTheme, $request;
497     $silent = true; $zip = false; $directory = false;
498     if ($WikiTheme->DUMP_MODE == 'HTML') {
499         $directory = $target;
500         $silent = false;
501     } elseif ($WikiTheme->DUMP_MODE == 'PDFHTML') {
502         $directory = $target;
503     } elseif (is_object($target)) { // $WikiTheme->DUMP_MODE == 'ZIPHTML'
504         $zip = $target;
505     }
506         
507     $request->_TemplatesProcessed = array();
508     if ($exclude) {   // exclude which pagenames
509         $excludeList = explodePageList($exclude);
510     } else {
511         $excludeList = array('DebugAuthInfo', 'DebugGroupInfo', 'AuthInfo');
512     }
513     if ($request->getArg('pages') or isa($page_iter, "WikiDB_Array_generic_iter")) { // pagelist
514         $WikiTheme->VALID_LINKS = array();
515         $page_iter_sav = $page_iter;
516         foreach ($page_iter_sav->asArray() as $handle) {
517             $WikiTheme->VALID_LINKS[] = is_string($handle) ? $handle : $handle->getName();
518         }
519         $page_iter_sav->reset();
520     }
521
522     if (defined('HTML_DUMP_SUFFIX'))
523         $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
524     $_bodyAttr = @$WikiTheme->_MoreAttr['body'];
525     unset($WikiTheme->_MoreAttr['body']);
526
527     if (check_php_version(4,1)) {
528         global $ErrorManager;
529         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
530     }
531
532     // check if the dumped file will be accessible from outside
533     $doc_root = $request->get("DOCUMENT_ROOT");
534     if ($WikiTheme->DUMP_MODE == 'HTML') {
535         $ldir = NormalizeLocalFileName($directory);
536         $wikiroot = NormalizeLocalFileName('');
537         if (string_starts_with($ldir, $doc_root)) {
538             $link_prefix = substr($directory, strlen($doc_root))."/";
539         } elseif (string_starts_with($ldir, $wikiroot)) {
540             $link_prefix = NormalizeWebFileName(substr($directory, strlen($wikiroot)))."/";
541         } else {
542             $prefix = '';
543             if (isWindows()) {
544                 $prefix = '/'; // . substr($doc_root,0,2); // add drive where apache is installed
545             }
546             $link_prefix = "file://".$prefix.$directory."/";
547         }
548     } else {
549         $link_prefix = "";
550     }
551
552     $request_args = $request->args;
553     $timeout = (! $request->getArg('start_debug')) ? 20 : 240;
554     $SAVE_RCS_IDS = $GLOBALS['RCS_IDS'];
555     if ($directory) {
556         if (isWindows())
557             $directory = str_replace("\\", "/", $directory); // no Win95 support.
558         @mkdir("$directory/images");
559     }
560     $already = array();
561     $outfiles = array();
562     $already_images = array();
563     
564     while ($page = $page_iter->next()) {
565         if (is_string($page)) {
566             $pagename = $page;
567             $page = $request->_dbi->getPage($pagename);
568         } else {
569             $pagename = $page->getName();
570         }
571         if (!$firstpage) $firstpage = $pagename;
572         if (array_key_exists($pagename, $already))
573             continue;
574         $already[$pagename] = 1;
575         $current = $page->getCurrentRevision();
576         //if ($current->getVersion() == 0)
577         //    continue;
578
579         $request->args = $request_args; // some plugins might change them (esp. on POST)
580         longer_timeout($timeout);       // Reset watchdog
581
582         if ($zip) {
583             $attrib = array('mtime'    => $current->get('mtime'),
584                             'is_ascii' => 1);
585             if ($page->get('locked'))
586                 $attrib['write_protected'] = 1;
587         } elseif (!$silent) {
588             if (!isa($request,'MockRequest')) {
589                 PrintXML(HTML::br(), $pagename, ' ... ');
590                 flush();
591             }
592         }
593         if (in_array($pagename, $excludeList)) {
594             if (!$silent and !isa($request,'MockRequest')) {
595                 PrintXML(_("Skipped."));
596                 flush();
597             }
598             continue;
599         }
600         $relative_base = '';
601         if ($WikiTheme->DUMP_MODE == 'PDFHTML') 
602             $request->setArg('action', 'pdf');   // to omit cache headers
603         $request->setArg('pagename', $pagename); // Template::_basepage fix
604         $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
605         $args = array('revision'      => $current,
606                       'CONTENT'       => $current->getTransformedContent(),
607                       'relative_base' => $relative_base);
608         // For every %2F will need to mkdir -p dirname($pagename)
609         if (preg_match("/(%2F|\/)/", $filename)) {
610             // mkdir -p and set relative base for subdir pages
611             $filename = preg_replace("/%2F/", "/", $filename);
612             $count = substr_count($filename, "/");
613             $dirname = dirname($filename);
614             if ($directory)
615                 mkdir_p($directory."/".$dirname);
616             // Fails with "XX / YY", "XX" is created, "XX / YY" cannot be written
617             if (isWindows()) // interesting Windows bug: cannot mkdir "bla "
618                 $filename = preg_replace("/ \//", "/", $filename);
619             $relative_base = "../";
620             while ($count > 1) {
621                 $relative_base .= "../";
622                 $count--;
623             }
624             $args['relative_base'] = $relative_base;
625         }
626         $msg = HTML();
627
628         $DUMP_MODE = $WikiTheme->DUMP_MODE;
629         $data = GeneratePageasXML(new Template('browse', $request, $args),
630                                  $pagename, $current, $args);
631         $WikiTheme->DUMP_MODE = $DUMP_MODE;                      
632
633         if (preg_match_all("/<img .*?src=\"(\/.+?)\"/", $data, $m)) {
634             // fix to local relative path for uploaded images, so that pdf will work
635             foreach ($m[1] as $img_file) {
636                 $base = basename($img_file);
637                 $data = str_replace('src="'.$img_file.'"','src="images/'.$base.'"', $data);
638                 // resolve src from webdata to file
639                 $src = $doc_root . $img_file;
640                 if (file_exists($src) and $base) {
641                     $target = "$directory/images/$base";
642                     if ($directory) {
643                         if (copy($src, $target)) {
644                             if (!$silent)
645                                 _copyMsg($img_file, fmt("... copied to %s", $target));
646                         } else {
647                             if (!$silent)
648                                 _copyMsg($img_file, fmt("... not copied to %s", $target));
649                         }
650                     } else {
651                         if (!array_key_exists($img_file, $already_images)) {
652                             $already_images[$img_file] = 1;
653                             if (check_php_version(4,3))
654                                 $zip->addRegularFile($target, file_get_contents($src), $attrib);
655                             else
656                                 $zip->addRegularFile($target, join('', file($src)), $attrib);
657                         }
658                     }
659                 }
660             }
661         }
662         
663         if ($directory) {
664             $outfile = $directory."/".$filename;
665             if ( !($fd = fopen($outfile, "wb")) ) {
666                 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
667                                                    $outfile)));
668                 $request->finish($msg);
669             }
670             $len = strlen($data);
671             $num = fwrite($fd, $data, $len);
672             if ($pagename != $filename) {
673                 $link = LinkURL($link_prefix.$filename, $filename);
674                 $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
675             }
676             $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
677             if (!$silent) {
678                 if (!isa($request, 'MockRequest')) {
679                     PrintXML($msg);
680                 }
681                 flush();
682                 $request->chunkOutput();
683             }
684             assert($num == $len);
685             fclose($fd);
686             $outfiles[] = $outfile;
687         } else {
688             $zip->addRegularFile($filename, $data, $attrib);
689         }
690
691         if (USECACHE) {
692             $request->_dbi->_cache->invalidate_cache($pagename);
693             unset ($request->_dbi->_cache->_pagedata_cache);
694             unset ($request->_dbi->_cache->_versiondata_cache);
695             unset ($request->_dbi->_cache->_glv_cache);
696         }
697         unset ($request->_dbi->_cache->_backend->_page_data);
698
699         unset($msg);
700         unset($current->_transformedContent);
701         unset($current);
702         unset($template->_request);
703         unset($template);
704         unset($data);
705         if (DEBUG)
706             $GLOBALS['RCS_IDS'] = $SAVE_RCS_IDS;
707     }
708     $page_iter->free();
709
710     if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
711         // @mkdir("$directory/images");
712         foreach ($WikiTheme->dumped_images as $img_file) {
713             if (array_key_exists($img_file, $already_images))
714                 continue;
715             $already_images[$img_file] = 1;
716             if ($img_file 
717                 and ($from = $WikiTheme->_findFile($img_file, true)) 
718                 and basename($from)) 
719             {
720                 if ($directory) {
721                     $target = "$directory/images/".basename($from);
722                     if ($silent)
723                         copy($WikiTheme->_path . $from, $target);
724                     else {
725                         if (copy($WikiTheme->_path . $from, $target)) {
726                             _copyMsg($from, fmt("... copied to %s", $target));
727                         } else {
728                             _copyMsg($from, fmt("... not copied to %s", $target));
729                         }
730                     }
731                 } else {
732                     $target = "images/".basename($from);
733                     if (check_php_version(4,3))
734                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
735                     else
736                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
737                 }
738             } elseif (!$silent) {
739                 _copyMsg($from, _("... not found"));
740             }
741         }
742     }
743
744     if (!empty($WikiTheme->dumped_buttons) 
745          and is_array($WikiTheme->dumped_buttons)) 
746     {
747         // Buttons also
748         if ($directory)
749             @mkdir("$directory/images/buttons");
750         foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
751             if (array_key_exists($img_file, $already_images))
752                 continue;
753             $already_images[$img_file] = 1;
754             if ($img_file 
755                 and ($from = $WikiTheme->_findFile($img_file, true)) 
756                 and basename($from)) 
757             {
758                 if ($directory) {
759                     $target = "$directory/images/buttons/".basename($from);
760                     if ($silent)
761                         copy($WikiTheme->_path . $from, $target);
762                     else {
763                         if (copy($WikiTheme->_path . $from, $target)) {
764                             _copyMsg($from, fmt("... copied to %s", $target));
765                         } else {
766                             _copyMsg($from, fmt("... not copied to %s", $target));
767                         }
768                     }
769                 } else {
770                     $target = "images/buttons/".basename($from);
771                     if (check_php_version(4,3))
772                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
773                     else
774                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
775                 }
776             } elseif (!$silent) {
777                 _copyMsg($from, _("... not found"));
778             }
779         }
780     }
781     if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
782         foreach ($WikiTheme->dumped_css as $css_file) {
783             if (array_key_exists($css_file, $already_images))
784                 continue;
785             $already_images[$css_file] = 1;
786             if ($css_file 
787                 and ($from = $WikiTheme->_findFile(basename($css_file), true)) 
788                 and basename($from)) 
789             {
790                 // TODO: fix @import url(main.css);
791                 if ($directory) {
792                     $target = "$directory/" . basename($css_file);
793                     if ($silent)
794                         copy($WikiTheme->_path . $from, $target);
795                     else {
796                         if (copy($WikiTheme->_path . $from, $target)) {
797                             _copyMsg($from, fmt("... copied to %s", $target));
798                         } else {
799                             _copyMsg($from, fmt("... not copied to %s", $target));
800                         }
801                     }
802                 } else {
803                     $target = basename($css_file);
804                     if (check_php_version(4,3))
805                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
806                     else
807                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
808                 }
809             } elseif (!$silent) {
810                 _copyMsg($from, _("... not found"));
811             }
812         }
813     }
814
815     if ($zip) 
816         $zip->finish();
817
818     if ($WikiTheme->DUMP_MODE == 'PDFHTML') {
819         if (USE_EXTERNAL_HTML2PDF and $outfiles) {
820             $cmd = EXTERNAL_HTML2PDF_PAGELIST.' "'.join('" "', $outfiles).'"';
821             $filename = FilenameForPage($firstpage);
822             if (DEBUG) {
823                 $tmpfile = $directory . "/createpdf.bat";
824                 $fp = fopen($tmpfile, "wb");
825                 fwrite($fp, $cmd . " > $filename.pdf");
826                 fclose($fp);
827             }
828             if (!headers_sent()) {
829                 Header('Content-Type: application/pdf');
830                 passthru($cmd);
831             }
832             else {
833                 $tmpdir = getUploadFilePath();
834                 $s = passthru($cmd . " > $tmpdir/$filename.pdf");
835                 $errormsg = "<br />\nGenerated <a href=\"".getUploadDataPath()."$filename.pdf\">Upload:$filename.pdf</a>\n";
836                 $errormsg .= $s;
837                 echo $errormsg;
838             }
839             if (!DEBUG) {
840                 foreach($outfiles as $f) unlink($f);
841             }
842         }
843         if (!empty($errormsg)) {
844             $request->discardOutput();
845             $GLOBALS['ErrorManager']->_postponed_errors = array();
846         }
847     }
848
849     if (check_php_version(4,1)) {
850         global $ErrorManager;
851         $ErrorManager->popErrorHandler();
852     }
853
854     $WikiTheme->HTML_DUMP_SUFFIX = '';
855     $WikiTheme->DUMP_MODE = false;
856     $WikiTheme->_MoreAttr['body'] = $_bodyAttr;
857 }
858
859
860 ////////////////////////////////////////////////////////////////
861 //
862 //  Functions for restoring.
863 //
864 ////////////////////////////////////////////////////////////////
865
866 function SavePage (&$request, &$pageinfo, $source, $filename)
867 {
868     static $overwite_all = false;
869     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
870     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
871
872     if (empty($pageinfo['pagename'])) {
873         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
874         return;
875     }
876
877     if (empty($versiondata['author_id']))
878         $versiondata['author_id'] = $versiondata['author'];
879
880     // remove invalid backend specific chars. utf8 issues mostly
881     $pagename_check = new WikiPagename($pageinfo['pagename']);
882     if (!$pagename_check->isValid()) {
883         PrintXML(HTML::dt(HTML::strong(_("Invalid pagename!")." ".$pageinfo['pagename'])));
884         return;
885     }
886     $pagename = $pagename_check->getName();
887     $content  = $pageinfo['content'];
888
889     if ($pagename == _("InterWikiMap"))
890         $content = _tryinsertInterWikiMap($content);
891
892     $dbi =& $request->_dbi;
893     $page = $dbi->getPage($pagename);
894
895     // Try to merge if updated pgsrc contents are different. This
896     // whole thing is hackish
897     //
898     // TODO: try merge unless:
899     // if (current contents = default contents && pgsrc_version >=
900     // pgsrc_version) then just upgrade this pgsrc
901     $needs_merge = false;
902     $merging = false;
903     $overwrite = false;
904
905     if ($request->getArg('merge')) {
906         $merging = true;
907     }
908     else if ($request->getArg('overwrite')) {
909         $overwrite = true;
910     }
911
912     $current = $page->getCurrentRevision();
913     $skip = false;
914     $edit = $request->getArg('edit');
915     if ($merging) { 
916         if (isset($edit['keep_old'])) {
917             $merging = false;
918             $skip = true;
919         }
920         elseif (isset($edit['overwrite'])) {
921             $merging = false;
922             $overwrite = true;
923         }
924         elseif ( $current and (! $current->hasDefaultContents())
925          && ($current->getPackedContent() != $content) ) 
926         {
927             include_once('lib/editpage.php');
928             $request->setArg('pagename', $pagename);
929             $v = $current->getVersion();
930             $request->setArg('revision', $current->getVersion());
931             $p = new LoadFileConflictPageEditor($request);
932             $p->_content = $content;
933             $p->_currentVersion = $v - 1;
934             $p->editPage($saveFailed = true);
935             return; //early return
936        }
937     }
938     if (!$skip)
939       foreach ($pagedata as $key => $value) {
940         if (!empty($value))
941             $page->set($key, $value);
942       }
943
944     $mesg = HTML::dd();
945     if ($source)
946         $mesg->pushContent(' ', fmt("from %s", $source));
947
948
949     if (!$current) {
950         //FIXME: This should not happen! (empty vdata, corrupt cache or db)
951         $current = $page->getCurrentRevision();
952     }
953     if ($current->getVersion() == 0) {
954         $mesg->pushContent(' - ', _("New page"));
955         $isnew = true;
956     }
957     else {
958         if ( (! $current->hasDefaultContents())
959              && ($current->getPackedContent() != $content) ) {
960             if ($overwrite) {
961                 $mesg->pushContent(' ',
962                                    fmt("has edit conflicts - overwriting anyway"));
963                 $skip = false;
964                 if (substr_count($source, 'pgsrc')) {
965                     $versiondata['author'] = _("The PhpWiki programming team");
966                     // but leave authorid as userid who loaded the file
967                 }
968             }
969             else {
970                 if (isset($edit['keep_old'])) {
971                     $mesg->pushContent(' ', fmt("keep old"));
972                 } else {
973                     $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
974                     $needs_merge = true; // hackish, to display the buttons
975                 }
976                 $skip = true;
977             }
978         }
979         else if ($current->getPackedContent() == $content
980                  && $current->get('author') == $versiondata['author']) {
981             // The page metadata is already changed, we don't need a new revision.
982             // This was called previously "is identical to current version %d - skipped"
983             // which is wrong, since the pagedata was stored, not skipped.
984             $mesg->pushContent(' ',
985                                fmt("content is identical to current version %d - no new revision created",
986                                    $current->getVersion()));
987             $skip = true;
988         }
989         $isnew = false;
990     }
991
992     if (! $skip ) {
993         // in case of failures print the culprit:
994         if (!isa($request,'MockRequest')) {
995             PrintXML(HTML::dt(WikiLink($pagename))); flush();
996         }
997         $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
998         $dbi->touch();
999         $mesg->pushContent(' ', fmt("- saved to database as version %d",
1000                                     $new->getVersion()));
1001     }
1002     if ($needs_merge) {
1003         $f = $source;
1004         // hackish, $source contains needed path+filename
1005         $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
1006         $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
1007         $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
1008         //check if uploaded file? they pass just the content, but the file is gone
1009         if (@stat($f)) {
1010             global $WikiTheme;
1011             $meb = Button(array('action' => 'loadfile',
1012                                 'merge'=> true,
1013                                 'source'=> $f),
1014                           _("Merge Edit"),
1015                           _("PhpWikiAdministration"),
1016                           'wikiadmin');
1017             $owb = Button(array('action' => 'loadfile',
1018                                 'overwrite'=> true,
1019                                 'source'=> $f),
1020                           _("Restore Anyway"),
1021                           _("PhpWikiAdministration"),
1022                           'wikiunsafe');
1023             $mesg->pushContent(' ', $meb, " ", $owb);
1024             if (!$overwite_all) {
1025                 $args = $request->getArgs();
1026                 $args['overwrite'] = 1;
1027                 $owb = Button($args,
1028                               _("Overwrite All"),
1029                               _("PhpWikiAdministration"),
1030                               'wikiunsafe');
1031                 $mesg->pushContent(HTML::div(array('class' => 'hint'), $owb));
1032                 $overwite_all = true;
1033             }
1034         } else {
1035             $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
1036         }
1037     }
1038
1039     if (!isa($request,'MockRequest')) {
1040       if ($skip)
1041         PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
1042       else
1043         PrintXML($mesg);
1044       flush();
1045     }
1046 }
1047
1048 // action=revert (by diff)
1049 function RevertPage (&$request)
1050 {
1051     $mesg = HTML::dd();
1052     $pagename = $request->getArg('pagename');
1053     $version = $request->getArg('version');
1054     if (!$version) {
1055         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1056                  HTML::dd(_("missing required version argument")));
1057         return;
1058     }
1059     $dbi =& $request->_dbi;
1060     $page = $dbi->getPage($pagename);
1061     $current = $page->getCurrentRevision();
1062     $currversion = $current->getVersion();
1063     if ($currversion == 0) {
1064         $mesg->pushContent(' ', _("no page content"));
1065         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1066                  $mesg);
1067         flush();
1068         return;
1069     }
1070     if ($currversion == $version) {
1071         $mesg->pushContent(' ', _("same version page"));
1072         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1073                  $mesg);
1074         flush();
1075         return;
1076     }
1077     if ($request->getArg('cancel')) {
1078         $mesg->pushContent(' ', _("Cancelled"));
1079         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1080                  $mesg);
1081         flush();
1082         return;
1083     }
1084     if (!$request->getArg('verify')) {
1085         $mesg->pushContent(HTML::br(),
1086                            _("Are you sure?"),
1087                            HTML::br(),
1088                            HTML::form(array('action' => $request->getPostURL(),
1089                                             'method' => 'post'),
1090                                       HiddenInputs($request->getArgs(), false, array('verify')),
1091                                       HiddenInputs(array('verify' => 1)),
1092                                       Button('submit:verify', _("Yes"), 'button'),
1093                                       HTML::Raw('&nbsp;'),
1094                                       Button('submit:cancel', _("Cancel"), 'button')),
1095                            HTML::hr());
1096         $rev = $page->getRevision($version);
1097         $html = HTML(HTML::dt(fmt("Revert %s to version $version", WikiLink($pagename))), 
1098                      $mesg,
1099                      $rev->getTransformedContent()); 
1100         $template = Template('browse', 
1101                              array('CONTENT' => $html));
1102         GeneratePage($template, $pagename, $rev);
1103         $request->checkValidators();
1104         flush();
1105         return;
1106     }
1107     $rev = $page->getRevision($version);
1108     $content = $rev->getPackedContent();
1109     $versiondata = $rev->_data;
1110     $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
1111     $new = $page->save($content, $currversion + 1, $versiondata);
1112     $dbi->touch();
1113     
1114     $pagelink = WikiLink($pagename);
1115     $mesg->pushContent(fmt("Revert: %s", $pagelink), 
1116                        fmt("- version %d saved to database as version %d",
1117                            $version, $new->getVersion()));
1118     // Force browse of current page version.
1119     $request->setArg('version', false);
1120     $template = Template('savepage', array());
1121     $template->replace('CONTENT', $new->getTransformedContent());
1122     
1123     GeneratePage($template, $mesg, $new);
1124     flush();
1125 }
1126
1127 function _tryinsertInterWikiMap($content) {
1128     $goback = false;
1129     if (strpos($content, "<verbatim>")) {
1130         //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
1131         $goback = true;
1132     }
1133     if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
1134         $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
1135         $goback = true;
1136     }
1137     $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
1138     if (!$goback && !file_exists($mapfile)) {
1139         $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
1140         $goback = true;
1141     }
1142
1143     if (!empty($error_html))
1144         trigger_error(_("Default InterWiki map file not loaded.")
1145                       . $error_html, E_USER_NOTICE);
1146     if ($goback)
1147         return $content;
1148
1149     // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
1150     if (!isa($GLOBALS['request'], 'MockRequest'))
1151         echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
1152
1153     $fd = fopen ($mapfile, "rb");
1154     $data = fread ($fd, filesize($mapfile));
1155     fclose ($fd);
1156     $content = $content . "\n<verbatim>\n$data</verbatim>\n";
1157     return $content;
1158 }
1159
1160 function ParseSerializedPage($text, $default_pagename, $user)
1161 {
1162     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
1163         return false;
1164
1165     $pagehash = unserialize($text);
1166
1167     // Split up pagehash into four parts:
1168     //   pagename
1169     //   content
1170     //   page-level meta-data
1171     //   revision-level meta-data
1172
1173     if (!defined('FLAG_PAGE_LOCKED'))
1174         define('FLAG_PAGE_LOCKED', 1);
1175     $pageinfo = array('pagedata'    => array(),
1176                       'versiondata' => array());
1177
1178     $pagedata = &$pageinfo['pagedata'];
1179     $versiondata = &$pageinfo['versiondata'];
1180
1181     // Fill in defaults.
1182     if (empty($pagehash['pagename']))
1183         $pagehash['pagename'] = $default_pagename;
1184     if (empty($pagehash['author'])) {
1185         $pagehash['author'] = $user->getId();
1186     }
1187
1188     foreach ($pagehash as $key => $value) {
1189         switch($key) {
1190             case 'pagename':
1191             case 'version':
1192             case 'hits':
1193                 $pageinfo[$key] = $value;
1194                 break;
1195             case 'content':
1196                 $pageinfo[$key] = join("\n", $value);
1197                 break;
1198             case 'flags':
1199                 if (($value & FLAG_PAGE_LOCKED) != 0)
1200                     $pagedata['locked'] = 'yes';
1201                 break;
1202             case 'owner':
1203             case 'created':
1204                 $pagedata[$key] = $value;
1205                 break;
1206             case 'acl':
1207             case 'perm':
1208                 $pagedata['perm'] = ParseMimeifiedPerm($value);
1209                 break;
1210             case 'lastmodified':
1211                 $versiondata['mtime'] = $value;
1212                 break;
1213             case 'author':
1214             case 'author_id':
1215             case 'summary':
1216                 $versiondata[$key] = $value;
1217                 break;
1218         }
1219     }
1220     if (empty($pagehash['charset']))
1221         $pagehash['charset'] = 'iso-8859-1';
1222     // compare to target charset
1223     if (strtolower($pagehash['charset']) != strtolower($GLOBALS['charset'])) {
1224         $pageinfo['content'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['content']);
1225         $pageinfo['pagename'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['pagename']);
1226     }
1227     return $pageinfo;
1228 }
1229
1230 function SortByPageVersion ($a, $b) {
1231     return $a['version'] - $b['version'];
1232 }
1233
1234 /**
1235  * Security alert! We should not allow to import config.ini into our wiki (or from a sister wiki?)
1236  * because the sql passwords are in plaintext there. And the webserver must be able to read it.
1237  * Detected by Santtu Jarvi.
1238  */
1239 function LoadFile (&$request, $filename, $text = false, $mtime = false)
1240 {
1241     if (preg_match("/config$/", dirname($filename))             // our or other config
1242         and preg_match("/config.*\.ini/", basename($filename))) // backups and other versions also
1243     {
1244         trigger_error(sprintf("Refused to load %s", $filename), E_USER_WARNING);
1245         return;
1246     }
1247     if (!is_string($text)) {
1248         // Read the file.
1249         $stat  = stat($filename);
1250         $mtime = $stat[9];
1251         $text  = implode("", file($filename));
1252     }
1253
1254     if (! $request->getArg('start_debug')) @set_time_limit(30); // Reset watchdog
1255     else @set_time_limit(240);
1256
1257     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
1258     $basename = basename("/dummy/" . $filename);
1259
1260     if (!$mtime)
1261         $mtime = time();    // Last resort.
1262
1263     // DONE: check source - target charset for content and pagename
1264     // but only for pgsrc'ed content, not from the browser.
1265
1266     $default_pagename = rawurldecode($basename);
1267     if ( ($parts = ParseMimeifiedPages($text)) ) {
1268         if (count($parts) > 1)
1269             $overwrite = $request->getArg('overwrite');
1270         usort($parts, 'SortByPageVersion');
1271         foreach ($parts as $pageinfo) {
1272             // force overwrite
1273             if (count($parts) > 1)
1274                 $request->setArg('overwrite', 1);
1275             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
1276                                                   $filename), $basename);
1277     }
1278         if (count($parts) > 1)
1279             if ($overwrite) 
1280                 $request->setArg('overwrite', $overwrite);
1281             else     
1282                 unset($request->_args['overwrite']);
1283     }
1284     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
1285                                                $request->getUser())) ) {
1286         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
1287                                               $filename), $basename);
1288     }
1289     else {
1290         // plain old file
1291         $user = $request->getUser();
1292
1293         $file_charset = 'iso-8859-1';
1294         // compare to target charset
1295         if ($file_charset != strtolower($GLOBALS['charset'])) {
1296             $text = charset_convert($file_charset, $GLOBALS['charset'], $text);
1297             $default_pagename = charset_convert($file_charset, $GLOBALS['charset'], $default_pagename);
1298         }
1299
1300         // Assume plain text file.
1301         $pageinfo = array('pagename' => $default_pagename,
1302                           'pagedata' => array(),
1303                           'versiondata'
1304                           => array('author' => $user->getId()),
1305                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
1306                                                      chop($text))
1307                           );
1308         SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
1309                  $basename);
1310     }
1311 }
1312
1313 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
1314     $zip = new ZipReader($zipfile);
1315     $timeout = (! $request->getArg('start_debug')) ? 20 : 120;
1316     while (list ($fn, $data, $attrib) = $zip->readFile()) {
1317         // FIXME: basename("filewithnoslashes") seems to return
1318         // garbage sometimes.
1319         $fn = basename("/dummy/" . $fn);
1320         if ( ($files && !in_array($fn, $files))
1321              || ($exclude && in_array($fn, $exclude)) ) {
1322             PrintXML(HTML::dt(WikiLink($fn)),
1323                      HTML::dd(_("Skipping")));
1324             flush();
1325             continue;
1326         }
1327         longer_timeout($timeout);       // longer timeout per page
1328         LoadFile($request, $fn, $data, $attrib['mtime']);
1329     }
1330 }
1331
1332 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
1333     $fileset = new LimitedFileSet($dirname, $files, $exclude);
1334
1335     if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
1336         PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
1337         $list = HTML::ul();
1338         foreach ($skiplist as $file)
1339             $list->pushContent(HTML::li(WikiLink($file)));
1340         PrintXML(HTML::dd($list));
1341     }
1342
1343     // Defer HomePage loading until the end. If anything goes wrong
1344     // the pages can still be loaded again.
1345     $files = $fileset->getFiles();
1346     if (in_array(HOME_PAGE, $files)) {
1347         $files = array_diff($files, array(HOME_PAGE));
1348         $files[] = HOME_PAGE;
1349     }
1350     $timeout = (! $request->getArg('start_debug')) ? 20 : 120;
1351     foreach ($files as $file) {
1352         longer_timeout($timeout);       // longer timeout per page
1353         if (substr($file,-1,1) != '~')  // refuse to load backup files
1354             LoadFile($request, "$dirname/$file");
1355     }
1356 }
1357
1358 class LimitedFileSet extends FileSet {
1359     function LimitedFileSet($dirname, $_include, $exclude) {
1360         $this->_includefiles = $_include;
1361         $this->_exclude = $exclude;
1362         $this->_skiplist = array();
1363         parent::FileSet($dirname);
1364     }
1365
1366     function _filenameSelector($fn) {
1367         $incl = &$this->_includefiles;
1368         $excl = &$this->_exclude;
1369
1370         if ( ($incl && !in_array($fn, $incl))
1371              || ($excl && in_array($fn, $excl)) ) {
1372             $this->_skiplist[] = $fn;
1373             return false;
1374         } else {
1375             return true;
1376         }
1377     }
1378
1379     function getSkippedFiles () {
1380         return $this->_skiplist;
1381     }
1382 }
1383
1384
1385 function IsZipFile ($filename_or_fd)
1386 {
1387     // See if it looks like zip file
1388     if (is_string($filename_or_fd))
1389     {
1390         $fd    = fopen($filename_or_fd, "rb");
1391         $magic = fread($fd, 4);
1392         fclose($fd);
1393     }
1394     else
1395     {
1396         $fpos  = ftell($filename_or_fd);
1397         $magic = fread($filename_or_fd, 4);
1398         fseek($filename_or_fd, $fpos);
1399     }
1400
1401     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1402 }
1403
1404
1405 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
1406 {
1407     // Try urlencoded filename for accented characters.
1408     if (!file_exists($file_or_dir)) {
1409         // Make sure there are slashes first to avoid confusing phps
1410         // with broken dirname or basename functions.
1411         // FIXME: windows uses \ and :
1412         if (is_integer(strpos($file_or_dir, "/"))) {
1413             $newfile = FindFile($file_or_dir, true);
1414             // Panic. urlencoded by the browser (e.g. San%20Diego => San Diego)
1415             if (!$newfile)
1416                 $file_or_dir = dirname($file_or_dir) . "/"
1417                     . rawurlencode(basename($file_or_dir));
1418         } else {
1419             // This is probably just a file.
1420             $file_or_dir = rawurlencode($file_or_dir);
1421         }
1422     }
1423
1424     $type = filetype($file_or_dir);
1425     if ($type == 'link') {
1426         // For symbolic links, use stat() to determine
1427         // the type of the underlying file.
1428         list(,,$mode) = stat($file_or_dir);
1429         $type = ($mode >> 12) & 017;
1430         if ($type == 010)
1431             $type = 'file';
1432         elseif ($type == 004)
1433             $type = 'dir';
1434     }
1435
1436     if (! $type) {
1437         $request->finish(fmt("Empty or not existing source. Unable to load: %s", $file_or_dir));
1438     }
1439     else if ($type == 'dir') {
1440         LoadDir($request, $file_or_dir, $files, $exclude);
1441     }
1442     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
1443     {
1444         $request->finish(fmt("Bad file type: %s", $type));
1445     }
1446     else if (IsZipFile($file_or_dir)) {
1447         LoadZip($request, $file_or_dir, $files, $exclude);
1448     }
1449     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
1450     {
1451         LoadFile($request, $file_or_dir);
1452     }
1453 }
1454
1455 function LoadFileOrDir (&$request)
1456 {
1457     $source = $request->getArg('source');
1458     $finder = new FileFinder;
1459     $source = $finder->slashifyPath($source);
1460     $page = rawurldecode(basename($source));
1461     StartLoadDump($request, fmt("Loading '%s'", 
1462         HTML(dirname($source),
1463              dirname($source) ? "/" : "",
1464              WikiLink($page,'auto'))));
1465     echo "<dl>\n";
1466     LoadAny($request, $source);
1467     echo "</dl>\n";
1468     EndLoadDump($request);
1469 }
1470
1471 /**
1472  * HomePage was not found so first-time install is supposed to run.
1473  * - import all pgsrc pages.
1474  * - Todo: installer interface to edit config/config.ini settings
1475  * - Todo: ask for existing old index.php to convert to config/config.ini
1476  * - Todo: theme-specific pages: 
1477  *   blog - HomePage, ADMIN_USER/Blogs
1478  */
1479 function SetupWiki (&$request)
1480 {
1481     global $GenericPages, $LANG;
1482
1483     //FIXME: This is a hack (err, "interim solution")
1484     // This is a bogo-bogo-login:  Login without
1485     // saving login information in session state.
1486     // This avoids logging in the unsuspecting
1487     // visitor as "The PhpWiki programming team".
1488     //
1489     // This really needs to be cleaned up...
1490     // (I'm working on it.)
1491     $real_user = $request->_user;
1492     if (ENABLE_USER_NEW)
1493         $request->_user = new _BogoUser(_("The PhpWiki programming team"));
1494
1495     else
1496         $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
1497                                        WIKIAUTH_BOGO);
1498
1499     StartLoadDump($request, _("Loading up virgin wiki"));
1500     echo "<dl>\n";
1501
1502     $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1503     $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1504
1505     $request->setArg('overwrite', true);
1506     if ($default_pgsrc != $pgsrc) {
1507         LoadAny($request, $default_pgsrc, $GenericPages);
1508     }
1509     $request->setArg('overwrite', false);
1510     LoadAny($request, $pgsrc);
1511     $dbi =& $request->_dbi;
1512
1513     // Ensure that all mandatory pages are loaded
1514     $finder = new FileFinder;
1515     foreach (array_merge(explode(':','Help/OldTextFormattingRules:Help/TextFormattingRules:PhpWikiAdministration'),
1516                          $GLOBALS['AllActionPages'],
1517                          array(constant('HOME_PAGE'))) as $f) 
1518     {
1519         $page = gettext($f);
1520         $epage = urlencode($page);
1521         if (! $dbi->isWikiPage($page) ) {
1522             // translated version provided?
1523             if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $epage, 1)) {
1524                 LoadAny($request, $lf);
1525             } else { // load english version of required action page
1526                 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1527                 $page = $f;
1528             }
1529         }
1530         if (! $dbi->isWikiPage($page)) {
1531             trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1532                           E_USER_WARNING);
1533         }
1534     }
1535     echo "</dl>\n";
1536     
1537     $pagename = _("InterWikiMap");
1538     $map = $dbi->getPage($pagename);
1539     $map->set('locked', true);
1540     PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), HTML::dd("locked"));
1541     EndLoadDump($request);
1542 }
1543
1544 function LoadPostFile (&$request)
1545 {
1546     $upload = $request->getUploadedFile('file');
1547
1548     if (!$upload)
1549         $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1550
1551
1552     // Dump http headers.
1553     StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1554     echo "<dl>\n";
1555
1556     $fd = $upload->open();
1557     if (IsZipFile($fd))
1558         LoadZip($request, $fd, false, array(_("RecentChanges")));
1559     else
1560         LoadFile($request, $upload->getName(), $upload->getContents());
1561
1562     echo "</dl>\n";
1563     EndLoadDump($request);
1564 }
1565
1566 /**
1567  $Log: not supported by cvs2svn $
1568  Revision 1.155  2007/09/12 19:40:41  rurban
1569  Copy locally uploaded images also
1570
1571  Revision 1.154  2007/08/10 22:00:43  rurban
1572  FilenameForPage:
1573  We have to apply a different "/" logic for dumpserial, htmldump and
1574  zipdump. dirs are allowed for zipdump and htmldump, not for dumpserial.
1575
1576  Revision 1.153  2007/05/28 20:54:40  rurban
1577  fix DumpToHtml creating dirs
1578
1579  Revision 1.152  2007/05/01 16:22:41  rurban
1580  lock InterWikiMap on init
1581
1582  Revision 1.151  2007/02/17 14:17:34  rurban
1583  only media=print css for htmldump and pdf
1584
1585  Revision 1.150  2007/01/20 15:53:42  rurban
1586  Use WikiPagename treatment for imported pagenames
1587
1588  Revision 1.149  2007/01/03 21:25:10  rurban
1589  Use convert_charset()
1590
1591  Revision 1.148  2007/01/02 13:21:57  rurban
1592  omit want_content if not necessary. support keep_old and overwrite buttons
1593
1594  Revision 1.147  2006/12/22 17:44:15  rurban
1595  support importing foreign charsets. e.g latin1 => utf8
1596
1597  Revision 1.146  2006/12/17 18:35:23  rurban
1598  Create the right subdirectory name, urlencoded.
1599
1600  Revision 1.145  2006/09/06 06:01:18  rurban
1601  support loadfile multipart archives automatically
1602
1603  Revision 1.144  2006/08/25 22:06:13  rurban
1604  args fix to pass $args to the template
1605
1606  Revision 1.143  2006/08/25 21:48:39  rurban
1607  dumphtml subpages
1608
1609  Revision 1.142  2006/03/19 17:16:32  rurban
1610  remove remaining cruft
1611
1612  Revision 1.141  2006/03/19 17:11:32  rurban
1613  add verify to RevertPage, display reverted page as template
1614
1615  Revision 1.140  2006/03/07 20:45:43  rurban
1616  wikihash for php-5.1
1617
1618  Revision 1.139  2005/08/27 18:02:43  rurban
1619  fix and expand pages
1620
1621  Revision 1.138  2005/08/27 09:39:10  rurban
1622  dumphtml when not at admin page: dump the current or given page
1623
1624  Revision 1.137  2005/01/30 23:14:38  rurban
1625  simplify page names
1626
1627  Revision 1.136  2005/01/25 07:07:24  rurban
1628  remove body tags in html dumps, add css and images to zipdumps, simplify printing
1629
1630  Revision 1.135  2004/12/26 17:17:25  rurban
1631  announce dumps - mult.requests to avoid request::finish, e.g. LinkDatabase, PdfOut, ...
1632
1633  Revision 1.134  2004/12/20 16:05:01  rurban
1634  gettext msg unification
1635
1636  Revision 1.133  2004/12/08 12:57:41  rurban
1637  page-specific timeouts for long multi-page requests
1638
1639  Revision 1.132  2004/12/08 01:18:33  rurban
1640  Disallow loading config*.ini files. Detected by Santtu Jarvi.
1641
1642  Revision 1.131  2004/11/30 17:48:38  rurban
1643  just comments
1644
1645  Revision 1.130  2004/11/25 08:28:12  rurban
1646  dont fatal on missing css or imgfiles and actually print the miss
1647
1648  Revision 1.129  2004/11/25 08:11:40  rurban
1649  pass exclude to the get_all_pages backend
1650
1651  Revision 1.128  2004/11/16 16:16:44  rurban
1652  enable Overwrite All for upgrade
1653
1654  Revision 1.127  2004/11/01 10:43:57  rurban
1655  seperate PassUser methods into seperate dir (memory usage)
1656  fix WikiUser (old) overlarge data session
1657  remove wikidb arg from various page class methods, use global ->_dbi instead
1658  ...
1659
1660  Revision 1.126  2004/10/16 15:13:39  rurban
1661  new [Overwrite All] button
1662
1663  Revision 1.125  2004/10/14 19:19:33  rurban
1664  loadsave: check if the dumped file will be accessible from outside.
1665  and some other minor fixes. (cvsclient native not yet ready)
1666
1667  Revision 1.124  2004/10/04 23:44:28  rurban
1668  for older or CGI phps
1669
1670  Revision 1.123  2004/09/25 16:26:54  rurban
1671  deferr notifies (to be improved)
1672
1673  Revision 1.122  2004/09/17 14:25:45  rurban
1674  update comments
1675
1676  Revision 1.121  2004/09/08 13:38:00  rurban
1677  improve loadfile stability by using markup=2 as default for undefined markup-style.
1678  use more refs for huge objects.
1679  fix debug=static issue in WikiPluginCached
1680
1681  Revision 1.120  2004/07/08 19:04:42  rurban
1682  more unittest fixes (file backend, metadata RatingsDb)
1683
1684  Revision 1.119  2004/07/08 15:23:59  rurban
1685  less verbose for tests
1686
1687  Revision 1.118  2004/07/08 13:50:32  rurban
1688  various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
1689
1690  Revision 1.117  2004/07/02 09:55:58  rurban
1691  more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
1692
1693  Revision 1.116  2004/07/01 09:05:41  rurban
1694  support pages and exclude arguments for all 4 dump methods
1695
1696  Revision 1.115  2004/07/01 08:51:22  rurban
1697  dumphtml: added exclude, print pagename before processing
1698
1699  Revision 1.114  2004/06/28 12:51:41  rurban
1700  improved dumphtml and virgin setup
1701
1702  Revision 1.113  2004/06/27 10:26:02  rurban
1703  oci8 patch by Philippe Vanhaesendonck + some ADODB notes+fixes
1704
1705  Revision 1.112  2004/06/25 14:29:20  rurban
1706  WikiGroup refactoring:
1707    global group attached to user, code for not_current user.
1708    improved helpers for special groups (avoid double invocations)
1709  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
1710  fixed a XHTML validation error on userprefs.tmpl
1711
1712  Revision 1.111  2004/06/21 16:38:55  rurban
1713  fixed the StartLoadDump html argument hack.
1714
1715  Revision 1.110  2004/06/21 16:22:30  rurban
1716  add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1717  fixed dumping buttons locally (images/buttons/),
1718  support pages arg for dumphtml,
1719  optional directory arg for dumpserial + dumphtml,
1720  fix a AllPages warning,
1721  show dump warnings/errors on DEBUG,
1722  don't warn just ignore on wikilens pagelist columns, if not loaded.
1723  RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1724
1725  Revision 1.109  2004/06/17 11:31:05  rurban
1726  jump back to label after dump/upgrade
1727
1728  Revision 1.108  2004/06/16 12:43:01  rurban
1729  4.0.6 cannot use this errorhandler (not found)
1730
1731  Revision 1.107  2004/06/14 11:31:37  rurban
1732  renamed global $Theme to $WikiTheme (gforge nameclash)
1733  inherit PageList default options from PageList
1734    default sortby=pagename
1735  use options in PageList_Selectable (limit, sortby, ...)
1736  added action revert, with button at action=diff
1737  added option regex to WikiAdminSearchReplace
1738
1739  Revision 1.106  2004/06/13 13:54:25  rurban
1740  Catch fatals on the four dump calls (as file and zip, as html and mimified)
1741  FoafViewer: Check against external requirements, instead of fatal.
1742  Change output for xhtmldumps: using file:// urls to the local fs.
1743  Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1744  Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1745
1746  Revision 1.105  2004/06/08 19:48:16  rurban
1747  fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1748
1749  Revision 1.104  2004/06/08 13:51:57  rurban
1750  some comments only
1751
1752  Revision 1.103  2004/06/08 10:54:46  rurban
1753  better acl dump representation, read back acl and owner
1754
1755  Revision 1.102  2004/06/06 16:58:51  rurban
1756  added more required ActionPages for foreign languages
1757  install now english ActionPages if no localized are found. (again)
1758  fixed default anon user level to be 0, instead of -1
1759    (wrong "required administrator to view this page"...)
1760
1761  Revision 1.101  2004/06/04 20:32:53  rurban
1762  Several locale related improvements suggested by Pierrick Meignen
1763  LDAP fix by John Cole
1764  reenable admin check without ENABLE_PAGEPERM in the admin plugins
1765
1766  Revision 1.100  2004/05/02 21:26:38  rurban
1767  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1768    because they will not survive db sessions, if too large.
1769  extended action=upgrade
1770  some WikiTranslation button work
1771  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1772  some temp. session debug statements
1773
1774  Revision 1.99  2004/05/02 15:10:07  rurban
1775  new finally reliable way to detect if /index.php is called directly
1776    and if to include lib/main.php
1777  new global AllActionPages
1778  SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1779  WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1780  PageGroupTestOne => subpages
1781  renamed PhpWikiRss to PhpWikiRecentChanges
1782  more docs, default configs, ...
1783
1784  Revision 1.98  2004/04/29 23:25:12  rurban
1785  re-ordered locale init (as in 1.3.9)
1786  fixed loadfile with subpages, and merge/restore anyway
1787    (sf.net bug #844188)
1788
1789  Revision 1.96  2004/04/19 23:13:03  zorloc
1790  Connect the rest of PhpWiki to the IniConfig system.  Also the keyword regular expression is not a config setting
1791
1792  Revision 1.95  2004/04/18 01:11:52  rurban
1793  more numeric pagename fixes.
1794  fixed action=upload with merge conflict warnings.
1795  charset changed from constant to global (dynamic utf-8 switching)
1796
1797  Revision 1.94  2004/03/14 16:36:37  rurban
1798  dont load backup files
1799
1800  Revision 1.93  2004/02/26 03:22:05  rurban
1801  also copy css and images with XHTML Dump
1802
1803  Revision 1.92  2004/02/26 02:25:54  rurban
1804  fix empty and #-anchored links in XHTML Dumps
1805
1806  Revision 1.91  2004/02/24 17:19:37  rurban
1807  debugging helpers only
1808
1809  Revision 1.90  2004/02/24 17:09:24  rurban
1810  fixed \r\r\n with dumping on windows
1811
1812  Revision 1.88  2004/02/22 23:20:31  rurban
1813  fixed DumpHtmlToDir,
1814  enhanced sortby handling in PageList
1815    new button_heading th style (enabled),
1816  added sortby and limit support to the db backends and plugins
1817    for paging support (<<prev, next>> links on long lists)
1818
1819  Revision 1.87  2004/01/26 09:17:49  rurban
1820  * changed stored pref representation as before.
1821    the array of objects is 1) bigger and 2)
1822    less portable. If we would import packed pref
1823    objects and the object definition was changed, PHP would fail.
1824    This doesn't happen with an simple array of non-default values.
1825  * use $prefs->retrieve and $prefs->store methods, where retrieve
1826    understands the interim format of array of objects also.
1827  * simplified $prefs->get() and fixed $prefs->set()
1828  * added $user->_userid and class '_WikiUser' portability functions
1829  * fixed $user object ->_level upgrading, mostly using sessions.
1830    this fixes yesterdays problems with loosing authorization level.
1831  * fixed WikiUserNew::checkPass to return the _level
1832  * fixed WikiUserNew::isSignedIn
1833  * added explodePageList to class PageList, support sortby arg
1834  * fixed UserPreferences for WikiUserNew
1835  * fixed WikiPlugin for empty defaults array
1836  * UnfoldSubpages: added pagename arg, renamed pages arg,
1837    removed sort arg, support sortby arg
1838
1839  Revision 1.86  2003/12/02 16:18:26  carstenklapp
1840  Minor enhancement: Provide more meaningful filenames for WikiDB zip
1841  dumps & snapshots.
1842
1843  Revision 1.85  2003/11/30 18:18:13  carstenklapp
1844  Minor code optimization: use include_once instead of require_once
1845  inside functions that might not always called.
1846
1847  Revision 1.84  2003/11/26 20:47:47  carstenklapp
1848  Redo bugfix: My last refactoring broke merge-edit & overwrite
1849  functionality again, should be fixed now. Sorry.
1850
1851  Revision 1.83  2003/11/20 22:18:54  carstenklapp
1852  New feature: h1 during merge-edit displays WikiLink to original page.
1853  Internal changes: Replaced some hackish url-generation code in
1854  function SavePage (for pgsrc merge-edit) with appropriate Button()
1855  calls.
1856
1857  Revision 1.82  2003/11/18 19:48:01  carstenklapp
1858  Fixed missing gettext _() for button name.
1859
1860  Revision 1.81  2003/11/18 18:28:35  carstenklapp
1861  Bugfix: In the Load File function of PhpWikiAdministration: When doing
1862  a "Merge Edit" or "Restore Anyway", page names containing accented
1863  letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1864  found error (Use FilenameForPage funtion to urlencode page names).
1865
1866  Revision 1.80  2003/03/07 02:46:57  dairiki
1867  Omit checks for safe_mode before set_time_limit().  Just prefix the
1868  set_time_limit() calls with @ so that they fail silently if not
1869  supported.
1870
1871  Revision 1.79  2003/02/26 01:56:05  dairiki
1872  Only zip pages with legal pagenames.
1873
1874  Revision 1.78  2003/02/24 02:05:43  dairiki
1875  Fix "n bytes written" message when dumping HTML.
1876
1877  Revision 1.77  2003/02/21 04:12:05  dairiki
1878  Minor fixes for new cached markup.
1879
1880  Revision 1.76  2003/02/16 19:47:17  dairiki
1881  Update WikiDB timestamp when editing or deleting pages.
1882
1883  Revision 1.75  2003/02/15 03:04:30  dairiki
1884  Fix for WikiUser constructor API change.
1885
1886  Revision 1.74  2003/02/15 02:18:04  dairiki
1887  When default language was English (at least), pgsrc was being
1888  loaded twice.
1889
1890  LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1891
1892  SetupWiki(): Fix bugs in loading of $GenericPages.
1893
1894  Revision 1.73  2003/01/28 21:09:17  zorloc
1895  The get_cfg_var() function should only be used when one is
1896  interested in the value from php.ini or similar. Use ini_get()
1897  instead to get the effective value of a configuration variable.
1898  -- Martin Geisler
1899
1900  Revision 1.72  2003/01/03 22:25:53  carstenklapp
1901  Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1902  programming team" as author when loading from pgsrc. Source
1903  reformatting.
1904
1905  Revision 1.71  2003/01/03 02:48:05  carstenklapp
1906  function SavePage: Added loadfile options for overwriting or merge &
1907  compare a loaded pgsrc file with an existing page.
1908
1909  function LoadAny: Added a general error message when unable to load a
1910  file instead of defaulting to "Bad file type".
1911
1912  */
1913
1914 // For emacs users
1915 // Local Variables:
1916 // mode: php
1917 // tab-width: 8
1918 // c-basic-offset: 4
1919 // c-hanging-comment-ender-p: nil
1920 // indent-tabs-mode: nil
1921 // End:
1922 ?>