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