]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
fixed DumpHtmlToDir,
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php //-*-php-*-
2 rcs_id('$Id: loadsave.php,v 1.88 2004-02-22 23:20:31 rurban Exp $');
3
4 /*
5  Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
6
7  This file is part of PhpWiki.
8
9  PhpWiki is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  PhpWiki is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with PhpWiki; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24
25 require_once("lib/ziplib.php");
26 require_once("lib/Template.php");
27
28 function StartLoadDump(&$request, $title, $html = '')
29 {
30     // FIXME: This is a hack
31     $tmpl = Template('html', array('TITLE' => $title,
32                                   'HEADER' => $title,
33                                   'CONTENT' => '%BODY%'));
34     echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
35 }
36
37 function EndLoadDump(&$request)
38 {
39     // FIXME: This is a hack
40     $pagelink = WikiLink($request->getPage());
41
42     PrintXML(HTML::p(HTML::strong(_("Complete."))),
43              HTML::p(fmt("Return to %s", $pagelink)));
44     echo "</body></html>\n";
45 }
46
47
48 ////////////////////////////////////////////////////////////////
49 //
50 //  Functions for dumping.
51 //
52 ////////////////////////////////////////////////////////////////
53
54 /**
55  * For reference see:
56  * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
57  * http://www.faqs.org/rfcs/rfc2045.html
58  * (RFC 1521 has been superceeded by RFC 2045 & others).
59  *
60  * Also see http://www.faqs.org/rfcs/rfc2822.html
61  */
62 function MailifyPage ($page, $nversions = 1)
63 {
64     $current = $page->getCurrentRevision();
65     $head = '';
66
67     if (STRICT_MAILABLE_PAGEDUMPS) {
68         $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
69         //This is for unix mailbox format: (not RFC (2)822)
70         // $head .= "From $from  " . CTime(time()) . "\r\n";
71         $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
72         $head .= "From: $from (PhpWiki)\r\n";
73         // RFC 2822 requires only a Date: and originator (From:)
74         // field, however the obsolete standard RFC 822 also
75         // requires a destination field.
76         $head .= "To: $from (PhpWiki)\r\n";
77     }
78     $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
79     $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
80                      PHPWIKI_VERSION);
81
82     // This should just be entered by hand (or by script?)
83     // in the actual pgsrc files, since only they should have
84     // RCS ids.
85     //$head .= "X-Rcs-Id: \$Id\$\r\n";
86
87     $iter = $page->getAllRevisions();
88     $parts = array();
89     while ($revision = $iter->next()) {
90         $parts[] = MimeifyPageRevision($revision);
91         if ($nversions > 0 && count($parts) >= $nversions)
92             break;
93     }
94     if (count($parts) > 1)
95         return $head . MimeMultipart($parts);
96     assert($parts);
97     return $head . $parts[0];
98 }
99
100 /***
101  * Compute filename to used for storing contents of a wiki page.
102  *
103  * Basically we do a rawurlencode() which encodes everything except
104  * ASCII alphanumerics and '.', '-', and '_'.
105  *
106  * But we also want to encode leading dots to avoid filenames like
107  * '.', and '..'. (Also, there's no point in generating "hidden" file
108  * names, like '.foo'.)
109  *
110  * @param $pagename string Pagename.
111  * @return string Filename for page.
112  */
113 function FilenameForPage ($pagename)
114 {
115     $enc = rawurlencode($pagename);
116     return preg_replace('/^\./', '%2e', $enc);
117 }
118
119 /**
120  * The main() function which generates a zip archive of a PhpWiki.
121  *
122  * If $include_archive is false, only the current version of each page
123  * is included in the zip file; otherwise all archived versions are
124  * included as well.
125  */
126 function MakeWikiZip (&$request)
127 {
128     if ($request->getArg('include') == 'all') {
129         $zipname         = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
130         $include_archive = true;
131     }
132     else {
133         $zipname         = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
134         $include_archive = false;
135     }
136
137
138
139     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
140
141     $dbi = $request->getDbh();
142     $pages = $dbi->getAllPages();
143     while ($page = $pages->next()) {
144         @set_time_limit(30); // Reset watchdog
145
146         $current = $page->getCurrentRevision();
147         if ($current->getVersion() == 0)
148             continue;
149
150         $wpn = new WikiPageName($page->getName());
151         if (!$wpn->isValid())
152             continue;
153
154         $attrib = array('mtime'    => $current->get('mtime'),
155                         'is_ascii' => 1);
156         if ($page->get('locked'))
157             $attrib['write_protected'] = 1;
158
159         if ($include_archive)
160             $content = MailifyPage($page, 0);
161         else
162             $content = MailifyPage($page);
163
164         $zip->addRegularFile( FilenameForPage($page->getName()),
165                               $content, $attrib);
166     }
167     $zip->finish();
168 }
169
170 function DumpToDir (&$request)
171 {
172     $directory = $request->getArg('directory');
173     if (empty($directory))
174         $request->finish(_("You must specify a directory to dump to"));
175
176     // see if we can access the directory the user wants us to use
177     if (! file_exists($directory)) {
178         if (! mkdir($directory, 0755))
179             $request->finish(fmt("Cannot create directory '%s'", $directory));
180         else
181             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
182                                 $directory));
183     } else {
184         $html = HTML::p(fmt("Using directory '%s'", $directory));
185     }
186
187     StartLoadDump($request, _("Dumping Pages"), $html);
188
189     $dbi = $request->getDbh();
190     $pages = $dbi->getAllPages();
191
192     while ($page = $pages->next()) {
193         @set_time_limit(30); // Reset watchdog.
194
195         $filename = FilenameForPage($page->getName());
196
197         $msg = HTML(HTML::br(), $page->getName(), ' ... ');
198
199         if($page->getName() != $filename) {
200             $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
201                               " ... ");
202         }
203
204         if ($request->getArg('include') == 'all')
205             $data = MailifyPage($page, 0);
206         else
207             $data = MailifyPage($page);
208
209         if ( !($fd = fopen("$directory/$filename", "w")) ) {
210             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
211                                                "$directory/$filename")));
212             $request->finish($msg);
213         }
214
215         $num = fwrite($fd, $data, strlen($data));
216         $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
217         PrintXML($msg);
218
219         flush();
220         assert($num == strlen($data));
221         fclose($fd);
222     }
223
224     EndLoadDump($request);
225 }
226
227
228 function DumpHtmlToDir (&$request)
229 {
230     $directory = $request->getArg('directory');
231     if (empty($directory))
232         $request->finish(_("You must specify a directory to dump to"));
233
234     // see if we can access the directory the user wants us to use
235     if (! file_exists($directory)) {
236         if (! mkdir($directory, 0755))
237             $request->finish(fmt("Cannot create directory '%s'", $directory));
238         else
239             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
240                                 $directory));
241     } else {
242         $html = HTML::p(fmt("Using directory '%s'", $directory));
243     }
244
245     StartLoadDump($request, _("Dumping Pages"), $html);
246     $thispage = $request->getArg('pagename'); // for "Return to ..."
247
248     $dbi = $request->getDbh();
249     $pages = $dbi->getAllPages();
250
251     global $HTML_DUMP_SUFFIX, $Theme;
252     if ($HTML_DUMP_SUFFIX)
253         $Theme->HTML_DUMP_SUFFIX = $HTML_DUMP_SUFFIX;
254
255     while ($page = $pages->next()) {
256         if (! $request->getArg('start_debug'))
257           @set_time_limit(30); // Reset watchdog.
258
259         $pagename = $page->getName();
260         $request->setArg('pagename',$pagename); // Template::_basepage fix
261         $filename = FilenameForPage($pagename) . $Theme->HTML_DUMP_SUFFIX;
262
263         $msg = HTML(HTML::br(), $pagename, ' ... ');
264
265         if($page->getName() != $filename) {
266             $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
267                               " ... ");
268         }
269
270         $revision = $page->getCurrentRevision();
271         $transformedContent = $revision->getTransformedContent();
272         $template = new Template('browse', $request,
273                                  array('revision' => $revision,
274                                        'CONTENT' => $transformedContent));
275
276         $data = GeneratePageasXML($template, $pagename);
277
278         if ( !($fd = fopen("$directory/$filename", "w")) ) {
279             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
280                                                "$directory/$filename")));
281             $request->finish($msg);
282         }
283
284         $num = fwrite($fd, $data, strlen($data));
285         $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
286         PrintXML($msg);
287
288         flush();
289         assert($num == strlen($data));
290         fclose($fd);
291     }
292
293     //CopyImageFiles() will go here;
294     $Theme->$HTML_DUMP_SUFFIX = '';
295
296     $request->setArg('pagename',$thispage); // Template::_basepage fix
297     EndLoadDump($request);
298 }
299
300 /* Known problem: any plugins or other code which echo()s text will
301  * lead to a corrupted html zip file which may produce the following
302  * errors upon unzipping:
303  *
304  * warning [wikihtml.zip]:  2401 extra bytes at beginning or within zipfile
305  * file #58:  bad zipfile offset (local header sig):  177561
306  *  (attempting to re-compensate)
307  *
308  * However, the actual wiki page data should be unaffected.
309  */
310 function MakeWikiZipHtml (&$request)
311 {
312     $zipname = "wikihtml.zip";
313     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
314     $dbi = $request->getDbh();
315     $pages = $dbi->getAllPages();
316
317     global $HTML_DUMP_SUFFIX, $Theme;
318     if ($HTML_DUMP_SUFFIX)
319         $Theme->HTML_DUMP_SUFFIX = $HTML_DUMP_SUFFIX;
320
321     while ($page = $pages->next()) {
322         @set_time_limit(30); // Reset watchdog.
323
324         $current = $page->getCurrentRevision();
325         if ($current->getVersion() == 0)
326             continue;
327
328         $attrib = array('mtime'    => $current->get('mtime'),
329                         'is_ascii' => 1);
330         if ($page->get('locked'))
331             $attrib['write_protected'] = 1;
332
333         $pagename = $page->getName();
334         $request->setArg('pagename',$pagename); // Template::_basepage fix
335         $filename = FilenameForPage($pagename) . $Theme->HTML_DUMP_SUFFIX;
336         $revision = $page->getCurrentRevision();
337
338         $transformedContent = $revision->getTransformedContent();
339
340         $template = new Template('browse', $request,
341                                  array('revision' => $revision,
342                                        'CONTENT' => $transformedContent));
343
344         $data = GeneratePageasXML($template, $pagename);
345
346         $zip->addRegularFile( $filename, $data, $attrib);
347     }
348     // FIXME: Deal with images here.
349     $zip->finish();
350     $Theme->$HTML_DUMP_SUFFIX = '';
351 }
352
353
354 ////////////////////////////////////////////////////////////////
355 //
356 //  Functions for restoring.
357 //
358 ////////////////////////////////////////////////////////////////
359
360 function SavePage (&$request, $pageinfo, $source, $filename)
361 {
362     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
363     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
364
365     if (empty($pageinfo['pagename'])) {
366         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
367         return;
368     }
369
370     if (empty($versiondata['author_id']))
371         $versiondata['author_id'] = $versiondata['author'];
372
373     $pagename = $pageinfo['pagename'];
374     $content  = $pageinfo['content'];
375
376     if ($pagename ==_("InterWikiMap"))
377         $content = _tryinsertInterWikiMap($content);
378
379     $dbi = $request->getDbh();
380     $page = $dbi->getPage($pagename);
381
382     $current = $page->getCurrentRevision();
383     // Try to merge if updated pgsrc contents are different. This
384     // whole thing is hackish
385     //
386     // TODO: try merge unless:
387     // if (current contents = default contents && pgsrc_version >=
388     // pgsrc_version) then just upgrade this pgsrc
389     $needs_merge = false;
390     $merging = false;
391     $overwrite = false;
392
393     if ($request->getArg('merge')) {
394         $merging = true;
395     }
396     else if ($request->getArg('overwrite')) {
397         $overwrite = true;
398     }
399
400     if ( (! $current->hasDefaultContents())
401          && ($current->getPackedContent() != $content)
402          && ($merging == true) ) {
403         include_once('lib/editpage.php');
404         $request->setArg('pagename', $pagename);
405         $r = $current->getVersion();
406         $request->setArg('revision', $current->getVersion());
407         $p = new LoadFileConflictPageEditor($request);
408         $p->_content = $content;
409         $p->_currentVersion = $r - 1;
410         $p->editPage($saveFailed = true);
411         return; //early return
412     }
413
414     foreach ($pagedata as $key => $value) {
415         if (!empty($value))
416             $page->set($key, $value);
417     }
418
419     $mesg = HTML::dd();
420     $skip = false;
421     if ($source)
422         $mesg->pushContent(' ', fmt("from %s", $source));
423
424
425     $current = $page->getCurrentRevision();
426     if ($current->getVersion() == 0) {
427         $mesg->pushContent(' ', _("new page"));
428         $isnew = true;
429     }
430     else {
431         if ( (! $current->hasDefaultContents())
432              && ($current->getPackedContent() != $content) ) {
433             if ($overwrite) {
434                 $mesg->pushContent(' ',
435                                    fmt("has edit conflicts - overwriting anyway"));
436                 $skip = false;
437                 if (substr_count($source, 'pgsrc')) {
438                     $versiondata['author'] = _("The PhpWiki programming team");
439                     // but leave authorid as userid who loaded the file
440                 }
441             }
442             else {
443                 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
444                 $needs_merge = true; // hackish
445                 $skip = true;
446             }
447         }
448         else if ($current->getPackedContent() == $content
449                  && $current->get('author') == $versiondata['author']) {
450             $mesg->pushContent(' ',
451                                fmt("is identical to current version %d - skipped",
452                                    $current->getVersion()));
453             $skip = true;
454         }
455         $isnew = false;
456     }
457
458     if (! $skip) {
459         $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
460         $dbi->touch();
461         $mesg->pushContent(' ', fmt("- saved to database as version %d",
462                                     $new->getVersion()));
463     }
464     if ($needs_merge) {
465         $f = $source;
466         // hackish, $source contains needed path+filename
467         $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
468         $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
469         $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
470         global $Theme;
471         $meb = Button(array('action' => 'loadfile',
472                             'merge'=> true,
473                             'source'=> dirname($f) . "/"
474                                        . basename($f)),
475                       _("Merge Edit"),
476                       _("PhpWikiAdministration"),
477                       'wikiadmin');
478         $owb = Button(array('action' => 'loadfile',
479                             'overwrite'=> true,
480                             'source'=> dirname($f) . "/"
481                                        . basename($f)),
482                       _("Restore Anyway"),
483                       _("PhpWikiAdministration"),
484                       'wikiunsafe');
485         $mesg->pushContent(' ', $meb, " ", $owb);
486     }
487
488     if ($skip)
489         PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
490     else
491         PrintXML(HTML::dt(WikiLink($pagename)), $mesg);
492     flush();
493 }
494
495 function _tryinsertInterWikiMap($content) {
496     $goback = false;
497     if (strpos($content, "<verbatim>")) {
498         //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
499         $goback = true;
500     }
501     if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
502         $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
503         $goback = true;
504     }
505     if (!$goback && !file_exists(INTERWIKI_MAP_FILE)) {
506         $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
507         $goback = true;
508     }
509
510     if (!empty($error_html))
511         trigger_error(_("Default InterWiki map file not loaded.")
512                       . $error_html, E_USER_NOTICE);
513
514     if ($goback)
515         return $content;
516
517     $filename = INTERWIKI_MAP_FILE;
518     trigger_error(sprintf(_("Loading InterWikiMap from external file %s."),
519                           $filename), E_USER_NOTICE);
520
521     $fd = fopen ($filename, "rb");
522     $data = fread ($fd, filesize($filename));
523     fclose ($fd);
524     $content = $content . "\n<verbatim>\n$data</verbatim>\n";
525     return $content;
526 }
527
528 function ParseSerializedPage($text, $default_pagename, $user)
529 {
530     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
531         return false;
532
533     $pagehash = unserialize($text);
534
535     // Split up pagehash into four parts:
536     //   pagename
537     //   content
538     //   page-level meta-data
539     //   revision-level meta-data
540
541     if (!defined('FLAG_PAGE_LOCKED'))
542         define('FLAG_PAGE_LOCKED', 1);
543     $pageinfo = array('pagedata'    => array(),
544                       'versiondata' => array());
545
546     $pagedata = &$pageinfo['pagedata'];
547     $versiondata = &$pageinfo['versiondata'];
548
549     // Fill in defaults.
550     if (empty($pagehash['pagename']))
551         $pagehash['pagename'] = $default_pagename;
552     if (empty($pagehash['author'])) {
553         $pagehash['author'] = $user->getId();
554     }
555
556     foreach ($pagehash as $key => $value) {
557         switch($key) {
558             case 'pagename':
559             case 'version':
560             case 'hits':
561                 $pageinfo[$key] = $value;
562                 break;
563             case 'content':
564                 $pageinfo[$key] = join("\n", $value);
565                 break;
566             case 'flags':
567                 if (($value & FLAG_PAGE_LOCKED) != 0)
568                     $pagedata['locked'] = 'yes';
569                 break;
570             case 'created':
571                 $pagedata[$key] = $value;
572                 break;
573             case 'lastmodified':
574                 $versiondata['mtime'] = $value;
575                 break;
576             case 'author':
577             case 'author_id':
578             case 'summary':
579                 $versiondata[$key] = $value;
580                 break;
581         }
582     }
583     return $pageinfo;
584 }
585
586 function SortByPageVersion ($a, $b) {
587     return $a['version'] - $b['version'];
588 }
589
590 function LoadFile (&$request, $filename, $text = false, $mtime = false)
591 {
592     if (!is_string($text)) {
593         // Read the file.
594         $stat  = stat($filename);
595         $mtime = $stat[9];
596         $text  = implode("", file($filename));
597     }
598
599     @set_time_limit(30); // Reset watchdog.
600
601     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
602     $basename = basename("/dummy/" . $filename);
603
604     if (!$mtime)
605         $mtime = time();    // Last resort.
606
607     $default_pagename = rawurldecode($basename);
608
609     if ( ($parts = ParseMimeifiedPages($text)) ) {
610         usort($parts, 'SortByPageVersion');
611         foreach ($parts as $pageinfo)
612             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
613                                                   $filename), $basename);
614     }
615     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
616                                                $request->getUser())) ) {
617         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
618                                               $filename), $basename);
619     }
620     else {
621         $user = $request->getUser();
622
623         // Assume plain text file.
624         $pageinfo = array('pagename' => $default_pagename,
625                           'pagedata' => array(),
626                           'versiondata'
627                           => array('author' => $user->getId()),
628                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
629                                                      chop($text))
630                           );
631         SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
632                  $basename);
633     }
634 }
635
636 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
637     $zip = new ZipReader($zipfile);
638     while (list ($fn, $data, $attrib) = $zip->readFile()) {
639         // FIXME: basename("filewithnoslashes") seems to return
640         // garbage sometimes.
641         $fn = basename("/dummy/" . $fn);
642         if ( ($files && !in_array($fn, $files))
643              || ($exclude && in_array($fn, $exclude)) ) {
644             PrintXML(HTML::dt(WikiLink($fn)),
645                      HTML::dd(_("Skipping")));
646             continue;
647         }
648
649         LoadFile($request, $fn, $data, $attrib['mtime']);
650     }
651 }
652
653 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
654     $fileset = new LimitedFileSet($dirname, $files, $exclude);
655
656     if (($skiplist = $fileset->getSkippedFiles())) {
657         PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
658         $list = HTML::ul();
659         foreach ($skiplist as $file)
660             $list->pushContent(HTML::li(WikiLink($file)));
661         PrintXML(HTML::dd($list));
662     }
663
664     // Defer HomePage loading until the end. If anything goes wrong
665     // the pages can still be loaded again.
666     $files = $fileset->getFiles();
667     if (in_array(HOME_PAGE, $files)) {
668         $files = array_diff($files, array(HOME_PAGE));
669         $files[] = HOME_PAGE;
670     }
671     foreach ($files as $file)
672         LoadFile($request, "$dirname/$file");
673 }
674
675 class LimitedFileSet extends FileSet {
676     function LimitedFileSet($dirname, $_include, $exclude) {
677         $this->_includefiles = $_include;
678         $this->_exclude = $exclude;
679         $this->_skiplist = array();
680         parent::FileSet($dirname);
681     }
682
683     function _filenameSelector($fn) {
684         $incl = &$this->_includefiles;
685         $excl = &$this->_exclude;
686
687         if ( ($incl && !in_array($fn, $incl))
688              || ($excl && in_array($fn, $excl)) ) {
689             $this->_skiplist[] = $fn;
690             return false;
691         } else {
692             return true;
693         }
694     }
695
696     function getSkippedFiles () {
697         return $this->_skiplist;
698     }
699 }
700
701
702 function IsZipFile ($filename_or_fd)
703 {
704     // See if it looks like zip file
705     if (is_string($filename_or_fd))
706     {
707         $fd    = fopen($filename_or_fd, "rb");
708         $magic = fread($fd, 4);
709         fclose($fd);
710     }
711     else
712     {
713         $fpos  = ftell($filename_or_fd);
714         $magic = fread($filename_or_fd, 4);
715         fseek($filename_or_fd, $fpos);
716     }
717
718     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
719 }
720
721
722 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
723 {
724     // Try urlencoded filename for accented characters.
725     if (!file_exists($file_or_dir)) {
726         // Make sure there are slashes first to avoid confusing phps
727         // with broken dirname or basename functions.
728         // FIXME: windows uses \ and :
729         if (is_integer(strpos($file_or_dir, "/"))) {
730             $file_or_dir = FindFile($file_or_dir);
731             // Panic
732             if (!file_exists($file_or_dir))
733                 $file_or_dir = dirname($file_or_dir) . "/"
734                     . urlencode(basename($file_or_dir));
735         } else {
736             // This is probably just a file.
737             $file_or_dir = urlencode($file_or_dir);
738         }
739     }
740
741     $type = filetype($file_or_dir);
742     if ($type == 'link') {
743         // For symbolic links, use stat() to determine
744         // the type of the underlying file.
745         list(,,$mode) = stat($file_or_dir);
746         $type = ($mode >> 12) & 017;
747         if ($type == 010)
748             $type = 'file';
749         elseif ($type == 004)
750             $type = 'dir';
751     }
752
753     if (! $type) {
754         $request->finish(fmt("Unable to load: %s", $file_or_dir));
755     }
756     else if ($type == 'dir') {
757         LoadDir($request, $file_or_dir, $files, $exclude);
758     }
759     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
760     {
761         $request->finish(fmt("Bad file type: %s", $type));
762     }
763     else if (IsZipFile($file_or_dir)) {
764         LoadZip($request, $file_or_dir, $files, $exclude);
765     }
766     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
767     {
768         LoadFile($request, $file_or_dir);
769     }
770 }
771
772 function LoadFileOrDir (&$request)
773 {
774     $source = $request->getArg('source');
775     StartLoadDump($request, fmt("Loading '%s'", HTML(dirname($source),
776                                                      "/",
777                                                      WikiLink(basename($source),
778                                                               'auto'))));
779     echo "<dl>\n";
780     LoadAny($request, $source);
781     echo "</dl>\n";
782     EndLoadDump($request);
783 }
784
785 function SetupWiki (&$request)
786 {
787     global $GenericPages, $LANG;
788
789
790     //FIXME: This is a hack (err, "interim solution")
791     // This is a bogo-bogo-login:  Login without
792     // saving login information in session state.
793     // This avoids logging in the unsuspecting
794     // visitor as "The PhpWiki programming team".
795     //
796     // This really needs to be cleaned up...
797     // (I'm working on it.)
798     $real_user = $request->_user;
799     if (ENABLE_USER_NEW)
800         $request->_user = new _BogoUser(_("The PhpWiki programming team"));
801
802     else
803         $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
804                                        WIKIAUTH_BOGO);
805
806     StartLoadDump($request, _("Loading up virgin wiki"));
807     echo "<dl>\n";
808
809     $pgsrc = FindLocalizedFile(WIKI_PGSRC);
810     $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
811     
812     if ($default_pgsrc != $pgsrc)
813         LoadAny($request, $default_pgsrc, $GenericPages);
814
815     LoadAny($request, $pgsrc);
816
817     echo "</dl>\n";
818     EndLoadDump($request);
819 }
820
821 function LoadPostFile (&$request)
822 {
823     $upload = $request->getUploadedFile('file');
824
825     if (!$upload)
826         $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
827
828
829     // Dump http headers.
830     StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
831     echo "<dl>\n";
832
833     $fd = $upload->open();
834     if (IsZipFile($fd))
835         LoadZip($request, $fd, false, array(_("RecentChanges")));
836     else
837         LoadFile($request, $upload->getName(), $upload->getContents());
838
839     echo "</dl>\n";
840     EndLoadDump($request);
841 }
842
843 /**
844  $Log: not supported by cvs2svn $
845  Revision 1.87  2004/01/26 09:17:49  rurban
846  * changed stored pref representation as before.
847    the array of objects is 1) bigger and 2)
848    less portable. If we would import packed pref
849    objects and the object definition was changed, PHP would fail.
850    This doesn't happen with an simple array of non-default values.
851  * use $prefs->retrieve and $prefs->store methods, where retrieve
852    understands the interim format of array of objects also.
853  * simplified $prefs->get() and fixed $prefs->set()
854  * added $user->_userid and class '_WikiUser' portability functions
855  * fixed $user object ->_level upgrading, mostly using sessions.
856    this fixes yesterdays problems with loosing authorization level.
857  * fixed WikiUserNew::checkPass to return the _level
858  * fixed WikiUserNew::isSignedIn
859  * added explodePageList to class PageList, support sortby arg
860  * fixed UserPreferences for WikiUserNew
861  * fixed WikiPlugin for empty defaults array
862  * UnfoldSubpages: added pagename arg, renamed pages arg,
863    removed sort arg, support sortby arg
864
865  Revision 1.86  2003/12/02 16:18:26  carstenklapp
866  Minor enhancement: Provide more meaningful filenames for WikiDB zip
867  dumps & snapshots.
868
869  Revision 1.85  2003/11/30 18:18:13  carstenklapp
870  Minor code optimization: use include_once instead of require_once
871  inside functions that might not always called.
872
873  Revision 1.84  2003/11/26 20:47:47  carstenklapp
874  Redo bugfix: My last refactoring broke merge-edit & overwrite
875  functionality again, should be fixed now. Sorry.
876
877  Revision 1.83  2003/11/20 22:18:54  carstenklapp
878  New feature: h1 during merge-edit displays WikiLink to original page.
879  Internal changes: Replaced some hackish url-generation code in
880  function SavePage (for pgsrc merge-edit) with appropriate Button()
881  calls.
882
883  Revision 1.82  2003/11/18 19:48:01  carstenklapp
884  Fixed missing gettext _() for button name.
885
886  Revision 1.81  2003/11/18 18:28:35  carstenklapp
887  Bugfix: In the Load File function of PhpWikiAdministration: When doing
888  a "Merge Edit" or "Restore Anyway", page names containing accented
889  letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
890  found error (Use FilenameForPage funtion to urlencode page names).
891
892  Revision 1.80  2003/03/07 02:46:57  dairiki
893  Omit checks for safe_mode before set_time_limit().  Just prefix the
894  set_time_limit() calls with @ so that they fail silently if not
895  supported.
896
897  Revision 1.79  2003/02/26 01:56:05  dairiki
898  Only zip pages with legal pagenames.
899
900  Revision 1.78  2003/02/24 02:05:43  dairiki
901  Fix "n bytes written" message when dumping HTML.
902
903  Revision 1.77  2003/02/21 04:12:05  dairiki
904  Minor fixes for new cached markup.
905
906  Revision 1.76  2003/02/16 19:47:17  dairiki
907  Update WikiDB timestamp when editing or deleting pages.
908
909  Revision 1.75  2003/02/15 03:04:30  dairiki
910  Fix for WikiUser constructor API change.
911
912  Revision 1.74  2003/02/15 02:18:04  dairiki
913  When default language was English (at least), pgsrc was being
914  loaded twice.
915
916  LimitedFileSet: Fix typo/bug. ($include was being ignored.)
917
918  SetupWiki(): Fix bugs in loading of $GenericPages.
919
920  Revision 1.73  2003/01/28 21:09:17  zorloc
921  The get_cfg_var() function should only be used when one is
922  interested in the value from php.ini or similar. Use ini_get()
923  instead to get the effective value of a configuration variable.
924  -- Martin Geisler
925
926  Revision 1.72  2003/01/03 22:25:53  carstenklapp
927  Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
928  programming team" as author when loading from pgsrc. Source
929  reformatting.
930
931  Revision 1.71  2003/01/03 02:48:05  carstenklapp
932  function SavePage: Added loadfile options for overwriting or merge &
933  compare a loaded pgsrc file with an existing page.
934
935  function LoadAny: Added a general error message when unable to load a
936  file instead of defaulting to "Bad file type".
937
938  */
939
940 // For emacs users
941 // Local Variables:
942 // mode: php
943 // tab-width: 8
944 // c-basic-offset: 4
945 // c-hanging-comment-ender-p: nil
946 // indent-tabs-mode: nil
947 // End:
948 ?>