]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
better pageset detection: format=
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php //-*-php-*-
2 rcs_id('$Id: loadsave.php,v 1.157 2007-09-19 18:01:27 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     $WikiTheme->VALID_LINKS = array();
514     if ($request->getArg('format')) { // pagelist
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')) ? 60 : 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                 if (array_key_exists($img_file, $already_images))
639                     continue;
640                 $already_images[$img_file] = 1;
641                 // resolve src from webdata to file
642                 $src = $doc_root . $img_file;
643                 if (file_exists($src) and $base) {
644                     $target = "$directory/images/$base";
645                     if ($directory) {
646                         if (copy($src, $target)) {
647                             if (!$silent)
648                                 _copyMsg($img_file, fmt("... copied to %s", $target));
649                         } else {
650                             if (!$silent)
651                                 _copyMsg($img_file, fmt("... not copied to %s", $target));
652                         }
653                     } else {
654                         if (!array_key_exists($img_file, $already_images)) {
655                             $already_images[$img_file] = 1;
656                             if (check_php_version(4,3))
657                                 $zip->addRegularFile($target, file_get_contents($src), $attrib);
658                             else
659                                 $zip->addRegularFile($target, join('', file($src)), $attrib);
660                         }
661                     }
662                 }
663             }
664         }
665         
666         if ($directory) {
667             $outfile = $directory."/".$filename;
668             if ( !($fd = fopen($outfile, "wb")) ) {
669                 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
670                                                    $outfile)));
671                 $request->finish($msg);
672             }
673             $len = strlen($data);
674             $num = fwrite($fd, $data, $len);
675             if ($pagename != $filename) {
676                 $link = LinkURL($link_prefix.$filename, $filename);
677                 $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
678             }
679             $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
680             if (!$silent) {
681                 if (!isa($request, 'MockRequest')) {
682                     PrintXML($msg);
683                 }
684                 flush();
685                 $request->chunkOutput();
686             }
687             assert($num == $len);
688             fclose($fd);
689             $outfiles[] = $outfile;
690         } else {
691             $zip->addRegularFile($filename, $data, $attrib);
692         }
693
694         if (USECACHE) {
695             $request->_dbi->_cache->invalidate_cache($pagename);
696             unset ($request->_dbi->_cache->_pagedata_cache);
697             unset ($request->_dbi->_cache->_versiondata_cache);
698             unset ($request->_dbi->_cache->_glv_cache);
699         }
700         unset ($request->_dbi->_cache->_backend->_page_data);
701
702         unset($msg);
703         unset($current->_transformedContent);
704         unset($current);
705         unset($template->_request);
706         unset($template);
707         unset($data);
708         if (DEBUG)
709             $GLOBALS['RCS_IDS'] = $SAVE_RCS_IDS;
710     }
711     $page_iter->free();
712
713     if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
714         // @mkdir("$directory/images");
715         foreach ($WikiTheme->dumped_images as $img_file) {
716             if (array_key_exists($img_file, $already_images))
717                 continue;
718             $already_images[$img_file] = 1;
719             if ($img_file 
720                 and ($from = $WikiTheme->_findFile($img_file, true)) 
721                 and basename($from)) 
722             {
723                 if ($directory) {
724                     $target = "$directory/images/".basename($from);
725                     if ($silent)
726                         copy($WikiTheme->_path . $from, $target);
727                     else {
728                         if (copy($WikiTheme->_path . $from, $target)) {
729                             _copyMsg($from, fmt("... copied to %s", $target));
730                         } else {
731                             _copyMsg($from, fmt("... not copied to %s", $target));
732                         }
733                     }
734                 } else {
735                     $target = "images/".basename($from);
736                     if (check_php_version(4,3))
737                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
738                     else
739                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
740                 }
741             } elseif (!$silent) {
742                 _copyMsg($from, _("... not found"));
743             }
744         }
745     }
746
747     if (!empty($WikiTheme->dumped_buttons) 
748          and is_array($WikiTheme->dumped_buttons)) 
749     {
750         // Buttons also
751         if ($directory)
752             @mkdir("$directory/images/buttons");
753         foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
754             if (array_key_exists($img_file, $already_images))
755                 continue;
756             $already_images[$img_file] = 1;
757             if ($img_file 
758                 and ($from = $WikiTheme->_findFile($img_file, true)) 
759                 and basename($from)) 
760             {
761                 if ($directory) {
762                     $target = "$directory/images/buttons/".basename($from);
763                     if ($silent)
764                         copy($WikiTheme->_path . $from, $target);
765                     else {
766                         if (copy($WikiTheme->_path . $from, $target)) {
767                             _copyMsg($from, fmt("... copied to %s", $target));
768                         } else {
769                             _copyMsg($from, fmt("... not copied to %s", $target));
770                         }
771                     }
772                 } else {
773                     $target = "images/buttons/".basename($from);
774                     if (check_php_version(4,3))
775                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
776                     else
777                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
778                 }
779             } elseif (!$silent) {
780                 _copyMsg($from, _("... not found"));
781             }
782         }
783     }
784     if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
785         foreach ($WikiTheme->dumped_css as $css_file) {
786             if (array_key_exists($css_file, $already_images))
787                 continue;
788             $already_images[$css_file] = 1;
789             if ($css_file 
790                 and ($from = $WikiTheme->_findFile(basename($css_file), true)) 
791                 and basename($from)) 
792             {
793                 // TODO: fix @import url(main.css);
794                 if ($directory) {
795                     $target = "$directory/" . basename($css_file);
796                     if ($silent)
797                         copy($WikiTheme->_path . $from, $target);
798                     else {
799                         if (copy($WikiTheme->_path . $from, $target)) {
800                             _copyMsg($from, fmt("... copied to %s", $target));
801                         } else {
802                             _copyMsg($from, fmt("... not copied to %s", $target));
803                         }
804                     }
805                 } else {
806                     $target = basename($css_file);
807                     if (check_php_version(4,3))
808                         $zip->addRegularFile($target, file_get_contents($WikiTheme->_path . $from), $attrib);
809                     else
810                         $zip->addRegularFile($target, join('', file($WikiTheme->_path . $from)), $attrib);
811                 }
812             } elseif (!$silent) {
813                 _copyMsg($from, _("... not found"));
814             }
815         }
816     }
817
818     if ($zip) 
819         $zip->finish();
820
821     if ($WikiTheme->DUMP_MODE == 'PDFHTML') {
822         if (USE_EXTERNAL_HTML2PDF and $outfiles) {
823             $cmd = EXTERNAL_HTML2PDF_PAGELIST.' "'.join('" "', $outfiles).'"';
824             $filename = FilenameForPage($firstpage);
825             if (DEBUG) {
826                 $tmpfile = $directory . "/createpdf.bat";
827                 $fp = fopen($tmpfile, "wb");
828                 fwrite($fp, $cmd . " > $filename.pdf");
829                 fclose($fp);
830             }
831             if (!headers_sent()) {
832                 Header('Content-Type: application/pdf');
833                 passthru($cmd);
834             }
835             else {
836                 $tmpdir = getUploadFilePath();
837                 $s = passthru($cmd . " > $tmpdir/$filename.pdf");
838                 $errormsg = "<br />\nGenerated <a href=\"".getUploadDataPath()."$filename.pdf\">Upload:$filename.pdf</a>\n";
839                 $errormsg .= $s;
840                 echo $errormsg;
841             }
842             if (!DEBUG) {
843                 foreach($outfiles as $f) unlink($f);
844             }
845         }
846         if (!empty($errormsg)) {
847             $request->discardOutput();
848             $GLOBALS['ErrorManager']->_postponed_errors = array();
849         }
850     }
851
852     if (check_php_version(4,1)) {
853         global $ErrorManager;
854         $ErrorManager->popErrorHandler();
855     }
856
857     $WikiTheme->HTML_DUMP_SUFFIX = '';
858     $WikiTheme->DUMP_MODE = false;
859     $WikiTheme->_MoreAttr['body'] = $_bodyAttr;
860 }
861
862
863 ////////////////////////////////////////////////////////////////
864 //
865 //  Functions for restoring.
866 //
867 ////////////////////////////////////////////////////////////////
868
869 function SavePage (&$request, &$pageinfo, $source, $filename)
870 {
871     static $overwite_all = false;
872     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
873     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
874
875     if (empty($pageinfo['pagename'])) {
876         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
877         return;
878     }
879
880     if (empty($versiondata['author_id']))
881         $versiondata['author_id'] = $versiondata['author'];
882
883     // remove invalid backend specific chars. utf8 issues mostly
884     $pagename_check = new WikiPagename($pageinfo['pagename']);
885     if (!$pagename_check->isValid()) {
886         PrintXML(HTML::dt(HTML::strong(_("Invalid pagename!")." ".$pageinfo['pagename'])));
887         return;
888     }
889     $pagename = $pagename_check->getName();
890     $content  = $pageinfo['content'];
891
892     if ($pagename == _("InterWikiMap"))
893         $content = _tryinsertInterWikiMap($content);
894
895     $dbi =& $request->_dbi;
896     $page = $dbi->getPage($pagename);
897
898     // Try to merge if updated pgsrc contents are different. This
899     // whole thing is hackish
900     //
901     // TODO: try merge unless:
902     // if (current contents = default contents && pgsrc_version >=
903     // pgsrc_version) then just upgrade this pgsrc
904     $needs_merge = false;
905     $merging = false;
906     $overwrite = false;
907
908     if ($request->getArg('merge')) {
909         $merging = true;
910     }
911     else if ($request->getArg('overwrite')) {
912         $overwrite = true;
913     }
914
915     $current = $page->getCurrentRevision();
916     $skip = false;
917     $edit = $request->getArg('edit');
918     if ($merging) { 
919         if (isset($edit['keep_old'])) {
920             $merging = false;
921             $skip = true;
922         }
923         elseif (isset($edit['overwrite'])) {
924             $merging = false;
925             $overwrite = true;
926         }
927         elseif ( $current and (! $current->hasDefaultContents())
928          && ($current->getPackedContent() != $content) ) 
929         {
930             include_once('lib/editpage.php');
931             $request->setArg('pagename', $pagename);
932             $v = $current->getVersion();
933             $request->setArg('revision', $current->getVersion());
934             $p = new LoadFileConflictPageEditor($request);
935             $p->_content = $content;
936             $p->_currentVersion = $v - 1;
937             $p->editPage($saveFailed = true);
938             return; //early return
939        }
940     }
941     if (!$skip)
942       foreach ($pagedata as $key => $value) {
943         if (!empty($value))
944             $page->set($key, $value);
945       }
946
947     $mesg = HTML::dd();
948     if ($source)
949         $mesg->pushContent(' ', fmt("from %s", $source));
950
951
952     if (!$current) {
953         //FIXME: This should not happen! (empty vdata, corrupt cache or db)
954         $current = $page->getCurrentRevision();
955     }
956     if ($current->getVersion() == 0) {
957         $mesg->pushContent(' - ', _("New page"));
958         $isnew = true;
959     }
960     else {
961         if ( (! $current->hasDefaultContents())
962              && ($current->getPackedContent() != $content) ) {
963             if ($overwrite) {
964                 $mesg->pushContent(' ',
965                                    fmt("has edit conflicts - overwriting anyway"));
966                 $skip = false;
967                 if (substr_count($source, 'pgsrc')) {
968                     $versiondata['author'] = _("The PhpWiki programming team");
969                     // but leave authorid as userid who loaded the file
970                 }
971             }
972             else {
973                 if (isset($edit['keep_old'])) {
974                     $mesg->pushContent(' ', fmt("keep old"));
975                 } else {
976                     $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
977                     $needs_merge = true; // hackish, to display the buttons
978                 }
979                 $skip = true;
980             }
981         }
982         else if ($current->getPackedContent() == $content
983                  && $current->get('author') == $versiondata['author']) {
984             // The page metadata is already changed, we don't need a new revision.
985             // This was called previously "is identical to current version %d - skipped"
986             // which is wrong, since the pagedata was stored, not skipped.
987             $mesg->pushContent(' ',
988                                fmt("content is identical to current version %d - no new revision created",
989                                    $current->getVersion()));
990             $skip = true;
991         }
992         $isnew = false;
993     }
994
995     if (! $skip ) {
996         // in case of failures print the culprit:
997         if (!isa($request,'MockRequest')) {
998             PrintXML(HTML::dt(WikiLink($pagename))); flush();
999         }
1000         $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
1001         $dbi->touch();
1002         $mesg->pushContent(' ', fmt("- saved to database as version %d",
1003                                     $new->getVersion()));
1004     }
1005     if ($needs_merge) {
1006         $f = $source;
1007         // hackish, $source contains needed path+filename
1008         $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
1009         $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
1010         $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
1011         //check if uploaded file? they pass just the content, but the file is gone
1012         if (@stat($f)) {
1013             global $WikiTheme;
1014             $meb = Button(array('action' => 'loadfile',
1015                                 'merge'=> true,
1016                                 'source'=> $f),
1017                           _("Merge Edit"),
1018                           _("PhpWikiAdministration"),
1019                           'wikiadmin');
1020             $owb = Button(array('action' => 'loadfile',
1021                                 'overwrite'=> true,
1022                                 'source'=> $f),
1023                           _("Restore Anyway"),
1024                           _("PhpWikiAdministration"),
1025                           'wikiunsafe');
1026             $mesg->pushContent(' ', $meb, " ", $owb);
1027             if (!$overwite_all) {
1028                 $args = $request->getArgs();
1029                 $args['overwrite'] = 1;
1030                 $owb = Button($args,
1031                               _("Overwrite All"),
1032                               _("PhpWikiAdministration"),
1033                               'wikiunsafe');
1034                 $mesg->pushContent(HTML::div(array('class' => 'hint'), $owb));
1035                 $overwite_all = true;
1036             }
1037         } else {
1038             $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
1039         }
1040     }
1041
1042     if (!isa($request,'MockRequest')) {
1043       if ($skip)
1044         PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
1045       else
1046         PrintXML($mesg);
1047       flush();
1048     }
1049 }
1050
1051 // action=revert (by diff)
1052 function RevertPage (&$request)
1053 {
1054     $mesg = HTML::dd();
1055     $pagename = $request->getArg('pagename');
1056     $version = $request->getArg('version');
1057     if (!$version) {
1058         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1059                  HTML::dd(_("missing required version argument")));
1060         return;
1061     }
1062     $dbi =& $request->_dbi;
1063     $page = $dbi->getPage($pagename);
1064     $current = $page->getCurrentRevision();
1065     $currversion = $current->getVersion();
1066     if ($currversion == 0) {
1067         $mesg->pushContent(' ', _("no page content"));
1068         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1069                  $mesg);
1070         flush();
1071         return;
1072     }
1073     if ($currversion == $version) {
1074         $mesg->pushContent(' ', _("same version page"));
1075         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1076                  $mesg);
1077         flush();
1078         return;
1079     }
1080     if ($request->getArg('cancel')) {
1081         $mesg->pushContent(' ', _("Cancelled"));
1082         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
1083                  $mesg);
1084         flush();
1085         return;
1086     }
1087     if (!$request->getArg('verify')) {
1088         $mesg->pushContent(HTML::br(),
1089                            _("Are you sure?"),
1090                            HTML::br(),
1091                            HTML::form(array('action' => $request->getPostURL(),
1092                                             'method' => 'post'),
1093                                       HiddenInputs($request->getArgs(), false, array('verify')),
1094                                       HiddenInputs(array('verify' => 1)),
1095                                       Button('submit:verify', _("Yes"), 'button'),
1096                                       HTML::Raw('&nbsp;'),
1097                                       Button('submit:cancel', _("Cancel"), 'button')),
1098                            HTML::hr());
1099         $rev = $page->getRevision($version);
1100         $html = HTML(HTML::dt(fmt("Revert %s to version $version", WikiLink($pagename))), 
1101                      $mesg,
1102                      $rev->getTransformedContent()); 
1103         $template = Template('browse', 
1104                              array('CONTENT' => $html));
1105         GeneratePage($template, $pagename, $rev);
1106         $request->checkValidators();
1107         flush();
1108         return;
1109     }
1110     $rev = $page->getRevision($version);
1111     $content = $rev->getPackedContent();
1112     $versiondata = $rev->_data;
1113     $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
1114     $new = $page->save($content, $currversion + 1, $versiondata);
1115     $dbi->touch();
1116     
1117     $pagelink = WikiLink($pagename);
1118     $mesg->pushContent(fmt("Revert: %s", $pagelink), 
1119                        fmt("- version %d saved to database as version %d",
1120                            $version, $new->getVersion()));
1121     // Force browse of current page version.
1122     $request->setArg('version', false);
1123     $template = Template('savepage', array());
1124     $template->replace('CONTENT', $new->getTransformedContent());
1125     
1126     GeneratePage($template, $mesg, $new);
1127     flush();
1128 }
1129
1130 function _tryinsertInterWikiMap($content) {
1131     $goback = false;
1132     if (strpos($content, "<verbatim>")) {
1133         //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
1134         $goback = true;
1135     }
1136     if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
1137         $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
1138         $goback = true;
1139     }
1140     $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
1141     if (!$goback && !file_exists($mapfile)) {
1142         $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
1143         $goback = true;
1144     }
1145
1146     if (!empty($error_html))
1147         trigger_error(_("Default InterWiki map file not loaded.")
1148                       . $error_html, E_USER_NOTICE);
1149     if ($goback)
1150         return $content;
1151
1152     // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
1153     if (!isa($GLOBALS['request'], 'MockRequest'))
1154         echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
1155
1156     $fd = fopen ($mapfile, "rb");
1157     $data = fread ($fd, filesize($mapfile));
1158     fclose ($fd);
1159     $content = $content . "\n<verbatim>\n$data</verbatim>\n";
1160     return $content;
1161 }
1162
1163 function ParseSerializedPage($text, $default_pagename, $user)
1164 {
1165     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
1166         return false;
1167
1168     $pagehash = unserialize($text);
1169
1170     // Split up pagehash into four parts:
1171     //   pagename
1172     //   content
1173     //   page-level meta-data
1174     //   revision-level meta-data
1175
1176     if (!defined('FLAG_PAGE_LOCKED'))
1177         define('FLAG_PAGE_LOCKED', 1);
1178     $pageinfo = array('pagedata'    => array(),
1179                       'versiondata' => array());
1180
1181     $pagedata = &$pageinfo['pagedata'];
1182     $versiondata = &$pageinfo['versiondata'];
1183
1184     // Fill in defaults.
1185     if (empty($pagehash['pagename']))
1186         $pagehash['pagename'] = $default_pagename;
1187     if (empty($pagehash['author'])) {
1188         $pagehash['author'] = $user->getId();
1189     }
1190
1191     foreach ($pagehash as $key => $value) {
1192         switch($key) {
1193             case 'pagename':
1194             case 'version':
1195             case 'hits':
1196                 $pageinfo[$key] = $value;
1197                 break;
1198             case 'content':
1199                 $pageinfo[$key] = join("\n", $value);
1200                 break;
1201             case 'flags':
1202                 if (($value & FLAG_PAGE_LOCKED) != 0)
1203                     $pagedata['locked'] = 'yes';
1204                 break;
1205             case 'owner':
1206             case 'created':
1207                 $pagedata[$key] = $value;
1208                 break;
1209             case 'acl':
1210             case 'perm':
1211                 $pagedata['perm'] = ParseMimeifiedPerm($value);
1212                 break;
1213             case 'lastmodified':
1214                 $versiondata['mtime'] = $value;
1215                 break;
1216             case 'author':
1217             case 'author_id':
1218             case 'summary':
1219                 $versiondata[$key] = $value;
1220                 break;
1221         }
1222     }
1223     if (empty($pagehash['charset']))
1224         $pagehash['charset'] = 'iso-8859-1';
1225     // compare to target charset
1226     if (strtolower($pagehash['charset']) != strtolower($GLOBALS['charset'])) {
1227         $pageinfo['content'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['content']);
1228         $pageinfo['pagename'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['pagename']);
1229     }
1230     return $pageinfo;
1231 }
1232
1233 function SortByPageVersion ($a, $b) {
1234     return $a['version'] - $b['version'];
1235 }
1236
1237 /**
1238  * Security alert! We should not allow to import config.ini into our wiki (or from a sister wiki?)
1239  * because the sql passwords are in plaintext there. And the webserver must be able to read it.
1240  * Detected by Santtu Jarvi.
1241  */
1242 function LoadFile (&$request, $filename, $text = false, $mtime = false)
1243 {
1244     if (preg_match("/config$/", dirname($filename))             // our or other config
1245         and preg_match("/config.*\.ini/", basename($filename))) // backups and other versions also
1246     {
1247         trigger_error(sprintf("Refused to load %s", $filename), E_USER_WARNING);
1248         return;
1249     }
1250     if (!is_string($text)) {
1251         // Read the file.
1252         $stat  = stat($filename);
1253         $mtime = $stat[9];
1254         $text  = implode("", file($filename));
1255     }
1256
1257     if (! $request->getArg('start_debug')) @set_time_limit(30); // Reset watchdog
1258     else @set_time_limit(240);
1259
1260     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
1261     $basename = basename("/dummy/" . $filename);
1262
1263     if (!$mtime)
1264         $mtime = time();    // Last resort.
1265
1266     // DONE: check source - target charset for content and pagename
1267     // but only for pgsrc'ed content, not from the browser.
1268
1269     $default_pagename = rawurldecode($basename);
1270     if ( ($parts = ParseMimeifiedPages($text)) ) {
1271         if (count($parts) > 1)
1272             $overwrite = $request->getArg('overwrite');
1273         usort($parts, 'SortByPageVersion');
1274         foreach ($parts as $pageinfo) {
1275             // force overwrite
1276             if (count($parts) > 1)
1277                 $request->setArg('overwrite', 1);
1278             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
1279                                                   $filename), $basename);
1280     }
1281         if (count($parts) > 1)
1282             if ($overwrite) 
1283                 $request->setArg('overwrite', $overwrite);
1284             else     
1285                 unset($request->_args['overwrite']);
1286     }
1287     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
1288                                                $request->getUser())) ) {
1289         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
1290                                               $filename), $basename);
1291     }
1292     else {
1293         // plain old file
1294         $user = $request->getUser();
1295
1296         $file_charset = 'iso-8859-1';
1297         // compare to target charset
1298         if ($file_charset != strtolower($GLOBALS['charset'])) {
1299             $text = charset_convert($file_charset, $GLOBALS['charset'], $text);
1300             $default_pagename = charset_convert($file_charset, $GLOBALS['charset'], $default_pagename);
1301         }
1302
1303         // Assume plain text file.
1304         $pageinfo = array('pagename' => $default_pagename,
1305                           'pagedata' => array(),
1306                           'versiondata'
1307                           => array('author' => $user->getId()),
1308                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
1309                                                      chop($text))
1310                           );
1311         SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
1312                  $basename);
1313     }
1314 }
1315
1316 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
1317     $zip = new ZipReader($zipfile);
1318     $timeout = (! $request->getArg('start_debug')) ? 20 : 120;
1319     while (list ($fn, $data, $attrib) = $zip->readFile()) {
1320         // FIXME: basename("filewithnoslashes") seems to return
1321         // garbage sometimes.
1322         $fn = basename("/dummy/" . $fn);
1323         if ( ($files && !in_array($fn, $files))
1324              || ($exclude && in_array($fn, $exclude)) ) {
1325             PrintXML(HTML::dt(WikiLink($fn)),
1326                      HTML::dd(_("Skipping")));
1327             flush();
1328             continue;
1329         }
1330         longer_timeout($timeout);       // longer timeout per page
1331         LoadFile($request, $fn, $data, $attrib['mtime']);
1332     }
1333 }
1334
1335 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
1336     $fileset = new LimitedFileSet($dirname, $files, $exclude);
1337
1338     if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
1339         PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
1340         $list = HTML::ul();
1341         foreach ($skiplist as $file)
1342             $list->pushContent(HTML::li(WikiLink($file)));
1343         PrintXML(HTML::dd($list));
1344     }
1345
1346     // Defer HomePage loading until the end. If anything goes wrong
1347     // the pages can still be loaded again.
1348     $files = $fileset->getFiles();
1349     if (in_array(HOME_PAGE, $files)) {
1350         $files = array_diff($files, array(HOME_PAGE));
1351         $files[] = HOME_PAGE;
1352     }
1353     $timeout = (! $request->getArg('start_debug')) ? 20 : 120;
1354     foreach ($files as $file) {
1355         longer_timeout($timeout);       // longer timeout per page
1356         if (substr($file,-1,1) != '~')  // refuse to load backup files
1357             LoadFile($request, "$dirname/$file");
1358     }
1359 }
1360
1361 class LimitedFileSet extends FileSet {
1362     function LimitedFileSet($dirname, $_include, $exclude) {
1363         $this->_includefiles = $_include;
1364         $this->_exclude = $exclude;
1365         $this->_skiplist = array();
1366         parent::FileSet($dirname);
1367     }
1368
1369     function _filenameSelector($fn) {
1370         $incl = &$this->_includefiles;
1371         $excl = &$this->_exclude;
1372
1373         if ( ($incl && !in_array($fn, $incl))
1374              || ($excl && in_array($fn, $excl)) ) {
1375             $this->_skiplist[] = $fn;
1376             return false;
1377         } else {
1378             return true;
1379         }
1380     }
1381
1382     function getSkippedFiles () {
1383         return $this->_skiplist;
1384     }
1385 }
1386
1387
1388 function IsZipFile ($filename_or_fd)
1389 {
1390     // See if it looks like zip file
1391     if (is_string($filename_or_fd))
1392     {
1393         $fd    = fopen($filename_or_fd, "rb");
1394         $magic = fread($fd, 4);
1395         fclose($fd);
1396     }
1397     else
1398     {
1399         $fpos  = ftell($filename_or_fd);
1400         $magic = fread($filename_or_fd, 4);
1401         fseek($filename_or_fd, $fpos);
1402     }
1403
1404     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1405 }
1406
1407
1408 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
1409 {
1410     // Try urlencoded filename for accented characters.
1411     if (!file_exists($file_or_dir)) {
1412         // Make sure there are slashes first to avoid confusing phps
1413         // with broken dirname or basename functions.
1414         // FIXME: windows uses \ and :
1415         if (is_integer(strpos($file_or_dir, "/"))) {
1416             $newfile = FindFile($file_or_dir, true);
1417             // Panic. urlencoded by the browser (e.g. San%20Diego => San Diego)
1418             if (!$newfile)
1419                 $file_or_dir = dirname($file_or_dir) . "/"
1420                     . rawurlencode(basename($file_or_dir));
1421         } else {
1422             // This is probably just a file.
1423             $file_or_dir = rawurlencode($file_or_dir);
1424         }
1425     }
1426
1427     $type = filetype($file_or_dir);
1428     if ($type == 'link') {
1429         // For symbolic links, use stat() to determine
1430         // the type of the underlying file.
1431         list(,,$mode) = stat($file_or_dir);
1432         $type = ($mode >> 12) & 017;
1433         if ($type == 010)
1434             $type = 'file';
1435         elseif ($type == 004)
1436             $type = 'dir';
1437     }
1438
1439     if (! $type) {
1440         $request->finish(fmt("Empty or not existing source. Unable to load: %s", $file_or_dir));
1441     }
1442     else if ($type == 'dir') {
1443         LoadDir($request, $file_or_dir, $files, $exclude);
1444     }
1445     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
1446     {
1447         $request->finish(fmt("Bad file type: %s", $type));
1448     }
1449     else if (IsZipFile($file_or_dir)) {
1450         LoadZip($request, $file_or_dir, $files, $exclude);
1451     }
1452     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
1453     {
1454         LoadFile($request, $file_or_dir);
1455     }
1456 }
1457
1458 function LoadFileOrDir (&$request)
1459 {
1460     $source = $request->getArg('source');
1461     $finder = new FileFinder;
1462     $source = $finder->slashifyPath($source);
1463     $page = rawurldecode(basename($source));
1464     StartLoadDump($request, fmt("Loading '%s'", 
1465         HTML(dirname($source),
1466              dirname($source) ? "/" : "",
1467              WikiLink($page,'auto'))));
1468     echo "<dl>\n";
1469     LoadAny($request, $source);
1470     echo "</dl>\n";
1471     EndLoadDump($request);
1472 }
1473
1474 /**
1475  * HomePage was not found so first-time install is supposed to run.
1476  * - import all pgsrc pages.
1477  * - Todo: installer interface to edit config/config.ini settings
1478  * - Todo: ask for existing old index.php to convert to config/config.ini
1479  * - Todo: theme-specific pages: 
1480  *   blog - HomePage, ADMIN_USER/Blogs
1481  */
1482 function SetupWiki (&$request)
1483 {
1484     global $GenericPages, $LANG;
1485
1486     //FIXME: This is a hack (err, "interim solution")
1487     // This is a bogo-bogo-login:  Login without
1488     // saving login information in session state.
1489     // This avoids logging in the unsuspecting
1490     // visitor as "The PhpWiki programming team".
1491     //
1492     // This really needs to be cleaned up...
1493     // (I'm working on it.)
1494     $real_user = $request->_user;
1495     if (ENABLE_USER_NEW)
1496         $request->_user = new _BogoUser(_("The PhpWiki programming team"));
1497
1498     else
1499         $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
1500                                        WIKIAUTH_BOGO);
1501
1502     StartLoadDump($request, _("Loading up virgin wiki"));
1503     echo "<dl>\n";
1504
1505     $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1506     $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1507
1508     $request->setArg('overwrite', true);
1509     if ($default_pgsrc != $pgsrc) {
1510         LoadAny($request, $default_pgsrc, $GenericPages);
1511     }
1512     $request->setArg('overwrite', false);
1513     LoadAny($request, $pgsrc);
1514     $dbi =& $request->_dbi;
1515
1516     // Ensure that all mandatory pages are loaded
1517     $finder = new FileFinder;
1518     foreach (array_merge(explode(':','Help/OldTextFormattingRules:Help/TextFormattingRules:PhpWikiAdministration'),
1519                          $GLOBALS['AllActionPages'],
1520                          array(constant('HOME_PAGE'))) as $f) 
1521     {
1522         $page = gettext($f);
1523         $epage = urlencode($page);
1524         if (! $dbi->isWikiPage($page) ) {
1525             // translated version provided?
1526             if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $epage, 1)) {
1527                 LoadAny($request, $lf);
1528             } else { // load english version of required action page
1529                 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1530                 $page = $f;
1531             }
1532         }
1533         if (! $dbi->isWikiPage($page)) {
1534             trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1535                           E_USER_WARNING);
1536         }
1537     }
1538     echo "</dl>\n";
1539     
1540     $pagename = _("InterWikiMap");
1541     $map = $dbi->getPage($pagename);
1542     $map->set('locked', true);
1543     PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), HTML::dd("locked"));
1544     EndLoadDump($request);
1545 }
1546
1547 function LoadPostFile (&$request)
1548 {
1549     $upload = $request->getUploadedFile('file');
1550
1551     if (!$upload)
1552         $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1553
1554
1555     // Dump http headers.
1556     StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1557     echo "<dl>\n";
1558
1559     $fd = $upload->open();
1560     if (IsZipFile($fd))
1561         LoadZip($request, $fd, false, array(_("RecentChanges")));
1562     else
1563         LoadFile($request, $upload->getName(), $upload->getContents());
1564
1565     echo "</dl>\n";
1566     EndLoadDump($request);
1567 }
1568
1569 /**
1570  $Log: not supported by cvs2svn $
1571  Revision 1.156  2007/09/15 12:32:50  rurban
1572  Improve multi-page format handling: abstract _DumpHtmlToDir. get rid of non-external pdf, non-global VALID_LINKS
1573
1574  Revision 1.155  2007/09/12 19:40:41  rurban
1575  Copy locally uploaded images also
1576
1577  Revision 1.154  2007/08/10 22:00:43  rurban
1578  FilenameForPage:
1579  We have to apply a different "/" logic for dumpserial, htmldump and
1580  zipdump. dirs are allowed for zipdump and htmldump, not for dumpserial.
1581
1582  Revision 1.153  2007/05/28 20:54:40  rurban
1583  fix DumpToHtml creating dirs
1584
1585  Revision 1.152  2007/05/01 16:22:41  rurban
1586  lock InterWikiMap on init
1587
1588  Revision 1.151  2007/02/17 14:17:34  rurban
1589  only media=print css for htmldump and pdf
1590
1591  Revision 1.150  2007/01/20 15:53:42  rurban
1592  Use WikiPagename treatment for imported pagenames
1593
1594  Revision 1.149  2007/01/03 21:25:10  rurban
1595  Use convert_charset()
1596
1597  Revision 1.148  2007/01/02 13:21:57  rurban
1598  omit want_content if not necessary. support keep_old and overwrite buttons
1599
1600  Revision 1.147  2006/12/22 17:44:15  rurban
1601  support importing foreign charsets. e.g latin1 => utf8
1602
1603  Revision 1.146  2006/12/17 18:35:23  rurban
1604  Create the right subdirectory name, urlencoded.
1605
1606  Revision 1.145  2006/09/06 06:01:18  rurban
1607  support loadfile multipart archives automatically
1608
1609  Revision 1.144  2006/08/25 22:06:13  rurban
1610  args fix to pass $args to the template
1611
1612  Revision 1.143  2006/08/25 21:48:39  rurban
1613  dumphtml subpages
1614
1615  Revision 1.142  2006/03/19 17:16:32  rurban
1616  remove remaining cruft
1617
1618  Revision 1.141  2006/03/19 17:11:32  rurban
1619  add verify to RevertPage, display reverted page as template
1620
1621  Revision 1.140  2006/03/07 20:45:43  rurban
1622  wikihash for php-5.1
1623
1624  Revision 1.139  2005/08/27 18:02:43  rurban
1625  fix and expand pages
1626
1627  Revision 1.138  2005/08/27 09:39:10  rurban
1628  dumphtml when not at admin page: dump the current or given page
1629
1630  Revision 1.137  2005/01/30 23:14:38  rurban
1631  simplify page names
1632
1633  Revision 1.136  2005/01/25 07:07:24  rurban
1634  remove body tags in html dumps, add css and images to zipdumps, simplify printing
1635
1636  Revision 1.135  2004/12/26 17:17:25  rurban
1637  announce dumps - mult.requests to avoid request::finish, e.g. LinkDatabase, PdfOut, ...
1638
1639  Revision 1.134  2004/12/20 16:05:01  rurban
1640  gettext msg unification
1641
1642  Revision 1.133  2004/12/08 12:57:41  rurban
1643  page-specific timeouts for long multi-page requests
1644
1645  Revision 1.132  2004/12/08 01:18:33  rurban
1646  Disallow loading config*.ini files. Detected by Santtu Jarvi.
1647
1648  Revision 1.131  2004/11/30 17:48:38  rurban
1649  just comments
1650
1651  Revision 1.130  2004/11/25 08:28:12  rurban
1652  dont fatal on missing css or imgfiles and actually print the miss
1653
1654  Revision 1.129  2004/11/25 08:11:40  rurban
1655  pass exclude to the get_all_pages backend
1656
1657  Revision 1.128  2004/11/16 16:16:44  rurban
1658  enable Overwrite All for upgrade
1659
1660  Revision 1.127  2004/11/01 10:43:57  rurban
1661  seperate PassUser methods into seperate dir (memory usage)
1662  fix WikiUser (old) overlarge data session
1663  remove wikidb arg from various page class methods, use global ->_dbi instead
1664  ...
1665
1666  Revision 1.126  2004/10/16 15:13:39  rurban
1667  new [Overwrite All] button
1668
1669  Revision 1.125  2004/10/14 19:19:33  rurban
1670  loadsave: check if the dumped file will be accessible from outside.
1671  and some other minor fixes. (cvsclient native not yet ready)
1672
1673  Revision 1.124  2004/10/04 23:44:28  rurban
1674  for older or CGI phps
1675
1676  Revision 1.123  2004/09/25 16:26:54  rurban
1677  deferr notifies (to be improved)
1678
1679  Revision 1.122  2004/09/17 14:25:45  rurban
1680  update comments
1681
1682  Revision 1.121  2004/09/08 13:38:00  rurban
1683  improve loadfile stability by using markup=2 as default for undefined markup-style.
1684  use more refs for huge objects.
1685  fix debug=static issue in WikiPluginCached
1686
1687  Revision 1.120  2004/07/08 19:04:42  rurban
1688  more unittest fixes (file backend, metadata RatingsDb)
1689
1690  Revision 1.119  2004/07/08 15:23:59  rurban
1691  less verbose for tests
1692
1693  Revision 1.118  2004/07/08 13:50:32  rurban
1694  various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
1695
1696  Revision 1.117  2004/07/02 09:55:58  rurban
1697  more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
1698
1699  Revision 1.116  2004/07/01 09:05:41  rurban
1700  support pages and exclude arguments for all 4 dump methods
1701
1702  Revision 1.115  2004/07/01 08:51:22  rurban
1703  dumphtml: added exclude, print pagename before processing
1704
1705  Revision 1.114  2004/06/28 12:51:41  rurban
1706  improved dumphtml and virgin setup
1707
1708  Revision 1.113  2004/06/27 10:26:02  rurban
1709  oci8 patch by Philippe Vanhaesendonck + some ADODB notes+fixes
1710
1711  Revision 1.112  2004/06/25 14:29:20  rurban
1712  WikiGroup refactoring:
1713    global group attached to user, code for not_current user.
1714    improved helpers for special groups (avoid double invocations)
1715  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
1716  fixed a XHTML validation error on userprefs.tmpl
1717
1718  Revision 1.111  2004/06/21 16:38:55  rurban
1719  fixed the StartLoadDump html argument hack.
1720
1721  Revision 1.110  2004/06/21 16:22:30  rurban
1722  add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1723  fixed dumping buttons locally (images/buttons/),
1724  support pages arg for dumphtml,
1725  optional directory arg for dumpserial + dumphtml,
1726  fix a AllPages warning,
1727  show dump warnings/errors on DEBUG,
1728  don't warn just ignore on wikilens pagelist columns, if not loaded.
1729  RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1730
1731  Revision 1.109  2004/06/17 11:31:05  rurban
1732  jump back to label after dump/upgrade
1733
1734  Revision 1.108  2004/06/16 12:43:01  rurban
1735  4.0.6 cannot use this errorhandler (not found)
1736
1737  Revision 1.107  2004/06/14 11:31:37  rurban
1738  renamed global $Theme to $WikiTheme (gforge nameclash)
1739  inherit PageList default options from PageList
1740    default sortby=pagename
1741  use options in PageList_Selectable (limit, sortby, ...)
1742  added action revert, with button at action=diff
1743  added option regex to WikiAdminSearchReplace
1744
1745  Revision 1.106  2004/06/13 13:54:25  rurban
1746  Catch fatals on the four dump calls (as file and zip, as html and mimified)
1747  FoafViewer: Check against external requirements, instead of fatal.
1748  Change output for xhtmldumps: using file:// urls to the local fs.
1749  Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1750  Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1751
1752  Revision 1.105  2004/06/08 19:48:16  rurban
1753  fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1754
1755  Revision 1.104  2004/06/08 13:51:57  rurban
1756  some comments only
1757
1758  Revision 1.103  2004/06/08 10:54:46  rurban
1759  better acl dump representation, read back acl and owner
1760
1761  Revision 1.102  2004/06/06 16:58:51  rurban
1762  added more required ActionPages for foreign languages
1763  install now english ActionPages if no localized are found. (again)
1764  fixed default anon user level to be 0, instead of -1
1765    (wrong "required administrator to view this page"...)
1766
1767  Revision 1.101  2004/06/04 20:32:53  rurban
1768  Several locale related improvements suggested by Pierrick Meignen
1769  LDAP fix by John Cole
1770  reenable admin check without ENABLE_PAGEPERM in the admin plugins
1771
1772  Revision 1.100  2004/05/02 21:26:38  rurban
1773  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1774    because they will not survive db sessions, if too large.
1775  extended action=upgrade
1776  some WikiTranslation button work
1777  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1778  some temp. session debug statements
1779
1780  Revision 1.99  2004/05/02 15:10:07  rurban
1781  new finally reliable way to detect if /index.php is called directly
1782    and if to include lib/main.php
1783  new global AllActionPages
1784  SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1785  WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1786  PageGroupTestOne => subpages
1787  renamed PhpWikiRss to PhpWikiRecentChanges
1788  more docs, default configs, ...
1789
1790  Revision 1.98  2004/04/29 23:25:12  rurban
1791  re-ordered locale init (as in 1.3.9)
1792  fixed loadfile with subpages, and merge/restore anyway
1793    (sf.net bug #844188)
1794
1795  Revision 1.96  2004/04/19 23:13:03  zorloc
1796  Connect the rest of PhpWiki to the IniConfig system.  Also the keyword regular expression is not a config setting
1797
1798  Revision 1.95  2004/04/18 01:11:52  rurban
1799  more numeric pagename fixes.
1800  fixed action=upload with merge conflict warnings.
1801  charset changed from constant to global (dynamic utf-8 switching)
1802
1803  Revision 1.94  2004/03/14 16:36:37  rurban
1804  dont load backup files
1805
1806  Revision 1.93  2004/02/26 03:22:05  rurban
1807  also copy css and images with XHTML Dump
1808
1809  Revision 1.92  2004/02/26 02:25:54  rurban
1810  fix empty and #-anchored links in XHTML Dumps
1811
1812  Revision 1.91  2004/02/24 17:19:37  rurban
1813  debugging helpers only
1814
1815  Revision 1.90  2004/02/24 17:09:24  rurban
1816  fixed \r\r\n with dumping on windows
1817
1818  Revision 1.88  2004/02/22 23:20:31  rurban
1819  fixed DumpHtmlToDir,
1820  enhanced sortby handling in PageList
1821    new button_heading th style (enabled),
1822  added sortby and limit support to the db backends and plugins
1823    for paging support (<<prev, next>> links on long lists)
1824
1825  Revision 1.87  2004/01/26 09:17:49  rurban
1826  * changed stored pref representation as before.
1827    the array of objects is 1) bigger and 2)
1828    less portable. If we would import packed pref
1829    objects and the object definition was changed, PHP would fail.
1830    This doesn't happen with an simple array of non-default values.
1831  * use $prefs->retrieve and $prefs->store methods, where retrieve
1832    understands the interim format of array of objects also.
1833  * simplified $prefs->get() and fixed $prefs->set()
1834  * added $user->_userid and class '_WikiUser' portability functions
1835  * fixed $user object ->_level upgrading, mostly using sessions.
1836    this fixes yesterdays problems with loosing authorization level.
1837  * fixed WikiUserNew::checkPass to return the _level
1838  * fixed WikiUserNew::isSignedIn
1839  * added explodePageList to class PageList, support sortby arg
1840  * fixed UserPreferences for WikiUserNew
1841  * fixed WikiPlugin for empty defaults array
1842  * UnfoldSubpages: added pagename arg, renamed pages arg,
1843    removed sort arg, support sortby arg
1844
1845  Revision 1.86  2003/12/02 16:18:26  carstenklapp
1846  Minor enhancement: Provide more meaningful filenames for WikiDB zip
1847  dumps & snapshots.
1848
1849  Revision 1.85  2003/11/30 18:18:13  carstenklapp
1850  Minor code optimization: use include_once instead of require_once
1851  inside functions that might not always called.
1852
1853  Revision 1.84  2003/11/26 20:47:47  carstenklapp
1854  Redo bugfix: My last refactoring broke merge-edit & overwrite
1855  functionality again, should be fixed now. Sorry.
1856
1857  Revision 1.83  2003/11/20 22:18:54  carstenklapp
1858  New feature: h1 during merge-edit displays WikiLink to original page.
1859  Internal changes: Replaced some hackish url-generation code in
1860  function SavePage (for pgsrc merge-edit) with appropriate Button()
1861  calls.
1862
1863  Revision 1.82  2003/11/18 19:48:01  carstenklapp
1864  Fixed missing gettext _() for button name.
1865
1866  Revision 1.81  2003/11/18 18:28:35  carstenklapp
1867  Bugfix: In the Load File function of PhpWikiAdministration: When doing
1868  a "Merge Edit" or "Restore Anyway", page names containing accented
1869  letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1870  found error (Use FilenameForPage funtion to urlencode page names).
1871
1872  Revision 1.80  2003/03/07 02:46:57  dairiki
1873  Omit checks for safe_mode before set_time_limit().  Just prefix the
1874  set_time_limit() calls with @ so that they fail silently if not
1875  supported.
1876
1877  Revision 1.79  2003/02/26 01:56:05  dairiki
1878  Only zip pages with legal pagenames.
1879
1880  Revision 1.78  2003/02/24 02:05:43  dairiki
1881  Fix "n bytes written" message when dumping HTML.
1882
1883  Revision 1.77  2003/02/21 04:12:05  dairiki
1884  Minor fixes for new cached markup.
1885
1886  Revision 1.76  2003/02/16 19:47:17  dairiki
1887  Update WikiDB timestamp when editing or deleting pages.
1888
1889  Revision 1.75  2003/02/15 03:04:30  dairiki
1890  Fix for WikiUser constructor API change.
1891
1892  Revision 1.74  2003/02/15 02:18:04  dairiki
1893  When default language was English (at least), pgsrc was being
1894  loaded twice.
1895
1896  LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1897
1898  SetupWiki(): Fix bugs in loading of $GenericPages.
1899
1900  Revision 1.73  2003/01/28 21:09:17  zorloc
1901  The get_cfg_var() function should only be used when one is
1902  interested in the value from php.ini or similar. Use ini_get()
1903  instead to get the effective value of a configuration variable.
1904  -- Martin Geisler
1905
1906  Revision 1.72  2003/01/03 22:25:53  carstenklapp
1907  Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1908  programming team" as author when loading from pgsrc. Source
1909  reformatting.
1910
1911  Revision 1.71  2003/01/03 02:48:05  carstenklapp
1912  function SavePage: Added loadfile options for overwriting or merge &
1913  compare a loaded pgsrc file with an existing page.
1914
1915  function LoadAny: Added a general error message when unable to load a
1916  file instead of defaulting to "Bad file type".
1917
1918  */
1919
1920 // For emacs users
1921 // Local Variables:
1922 // mode: php
1923 // tab-width: 8
1924 // c-basic-offset: 4
1925 // c-hanging-comment-ender-p: nil
1926 // indent-tabs-mode: nil
1927 // End:
1928 ?>