2 rcs_id('$Id: loadsave.php,v 1.120 2004-07-08 19:04:42 rurban Exp $');
5 Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
7 This file is part of PhpWiki.
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.
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.
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
25 require_once("lib/ziplib.php");
26 require_once("lib/Template.php");
29 * ignore fatal errors during dump
31 function _dump_error_handler(&$error) {
32 if ($error->isFatal()) {
33 $error->errno = E_USER_WARNING;
36 return true; // Ignore error
38 if (preg_match('/Plugin/', $error->errstr))
41 // let the message come through: call the remaining handlers:
45 function StartLoadDump(&$request, $title, $html = '')
47 if (isa($request,'MockRequest'))
49 // FIXME: This is a hack
51 $html->pushContent('%BODY%');
52 $tmpl = Template('html', array('TITLE' => $title,
54 'CONTENT' => $html ? $html : '%BODY%'));
55 echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
57 /* Ignore fatals or warnings in any pagedumps (failing plugins).
58 * WikiFunctionCb() fails with 4.0.6, works ok with 4.1.1
60 if (!check_php_version(4,1) or (DEBUG & _DEBUG_VERBOSE)) return;
62 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
65 function EndLoadDump(&$request)
67 if (isa($request,'MockRequest'))
69 if (check_php_version(4,1)) {
71 $ErrorManager->popErrorHandler();
73 $action = $request->getArg('action');
76 case 'zip': $label = _("ZIP files of database"); break;
77 case 'dumpserial': $label = _("Dump to directory"); break;
78 case 'upload': $label = _("Upload File"); break;
79 case 'loadfile': $label = _("Load File"); break;
80 case 'upgrade': $label = _("Upgrade"); break;
82 case 'ziphtml': $label = _("Dump pages as XHTML"); break;
84 if ($label) $label = str_replace(" ","_",$label);
85 if ($action == 'browse') // loading virgin
86 $pagelink = WikiLink(HOME_PAGE);
88 $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"),false,$label));
90 PrintXML(HTML::p(HTML::strong(_("Complete."))),
91 HTML::p(fmt("Return to %s", $pagelink)));
92 echo "</body></html>\n";
96 ////////////////////////////////////////////////////////////////
98 // Functions for dumping.
100 ////////////////////////////////////////////////////////////////
104 * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
105 * http://www.faqs.org/rfcs/rfc2045.html
106 * (RFC 1521 has been superceeded by RFC 2045 & others).
108 * Also see http://www.faqs.org/rfcs/rfc2822.html
110 function MailifyPage ($page, $nversions = 1)
112 $current = $page->getCurrentRevision();
115 if (STRICT_MAILABLE_PAGEDUMPS) {
116 $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
117 //This is for unix mailbox format: (not RFC (2)822)
118 // $head .= "From $from " . CTime(time()) . "\r\n";
119 $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
120 $head .= "From: $from (PhpWiki)\r\n";
121 // RFC 2822 requires only a Date: and originator (From:)
122 // field, however the obsolete standard RFC 822 also
123 // requires a destination field.
124 $head .= "To: $from (PhpWiki)\r\n";
126 $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
127 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
130 // This should just be entered by hand (or by script?)
131 // in the actual pgsrc files, since only they should have
133 //$head .= "X-Rcs-Id: \$Id\$\r\n";
135 $iter = $page->getAllRevisions();
137 while ($revision = $iter->next()) {
138 $parts[] = MimeifyPageRevision($revision);
139 if ($nversions > 0 && count($parts) >= $nversions)
142 if (count($parts) > 1)
143 return $head . MimeMultipart($parts);
145 return $head . $parts[0];
149 * Compute filename to used for storing contents of a wiki page.
151 * Basically we do a rawurlencode() which encodes everything except
152 * ASCII alphanumerics and '.', '-', and '_'.
154 * But we also want to encode leading dots to avoid filenames like
155 * '.', and '..'. (Also, there's no point in generating "hidden" file
156 * names, like '.foo'.)
158 * @param $pagename string Pagename.
159 * @return string Filename for page.
161 function FilenameForPage ($pagename)
163 $enc = rawurlencode($pagename);
164 return preg_replace('/^\./', '%2e', $enc);
168 * The main() function which generates a zip archive of a PhpWiki.
170 * If $include_archive is false, only the current version of each page
171 * is included in the zip file; otherwise all archived versions are
174 function MakeWikiZip (&$request)
176 if ($request->getArg('include') == 'all') {
177 $zipname = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
178 $include_archive = true;
181 $zipname = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
182 $include_archive = false;
186 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
188 /* ignore fatals in plugins */
189 if (check_php_version(4,1)) {
190 global $ErrorManager;
191 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
194 $dbi = $request->getDbh();
195 $thispage = $request->getArg('pagename'); // for "Return to ..."
196 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
197 $excludeList = explodePageList($exclude);
199 $excludeList = array();
201 if ($whichpages = $request->getArg('pages')) { // which pagenames
202 if ($whichpages == '[]') // current page
203 $whichpages = $thispage;
204 $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
206 $pages = $dbi->getAllPages();
208 $request_args = $request->args;
210 while ($page = $pages->next()) {
211 $request->args = $request_args; // some plugins might change them (esp. on POST)
212 if (! $request->getArg('start_debug'))
213 @set_time_limit(30); // Reset watchdog
215 @set_time_limit(240);
217 $current = $page->getCurrentRevision();
218 if ($current->getVersion() == 0)
221 $pagename = $page->getName();
222 $wpn = new WikiPageName($pagename);
223 if (!$wpn->isValid())
225 if (in_array($page->getName(), $excludeList)) {
229 $attrib = array('mtime' => $current->get('mtime'),
231 if ($page->get('locked'))
232 $attrib['write_protected'] = 1;
234 if ($include_archive)
235 $content = MailifyPage($page, 0);
237 $content = MailifyPage($page);
239 $zip->addRegularFile( FilenameForPage($pagename),
243 if (check_php_version(4,1)) {
244 $ErrorManager->popErrorHandler();
248 function DumpToDir (&$request)
250 $directory = $request->getArg('directory');
251 if (empty($directory))
252 $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
253 if (empty($directory))
254 $request->finish(_("You must specify a directory to dump to"));
256 // see if we can access the directory the user wants us to use
257 if (! file_exists($directory)) {
258 if (! mkdir($directory, 0755))
259 $request->finish(fmt("Cannot create directory '%s'", $directory));
261 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
264 $html = HTML::p(fmt("Using directory '%s'", $directory));
267 StartLoadDump($request, _("Dumping Pages"), $html);
269 $dbi = $request->getDbh();
270 $thispage = $request->getArg('pagename'); // for "Return to ..."
271 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
272 $excludeList = explodePageList($exclude);
274 $excludeList = array();
276 if ($whichpages = $request->getArg('pages')) { // which pagenames
277 if ($whichpages == '[]') // current page
278 $whichpages = $thispage;
279 $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
281 $pages = $dbi->getAllPages();
284 $request_args = $request->args;
286 while ($page = $pages->next()) {
287 $request->args = $request_args; // some plugins might change them (esp. on POST)
288 if (! $request->getArg('start_debug'))
289 @set_time_limit(30); // Reset watchdog.
291 @set_time_limit(240);
293 $pagename = $page->getName();
294 if (!isa($request,'MockRequest')) {
295 PrintXML(HTML::br(), $pagename, ' ... ');
299 if (in_array($pagename, $excludeList)) {
300 if (!isa($request,'MockRequest')) {
301 PrintXML(_("Skipped."));
306 $filename = FilenameForPage($pagename);
308 if($page->getName() != $filename) {
309 $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
313 if ($request->getArg('include') == 'all')
314 $data = MailifyPage($page, 0);
316 $data = MailifyPage($page);
318 if ( !($fd = fopen("$directory/$filename", "wb")) ) {
319 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
320 "$directory/$filename")));
321 $request->finish($msg);
324 $num = fwrite($fd, $data, strlen($data));
325 $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
326 if (!isa($request,'MockRequest')) {
330 assert($num == strlen($data));
334 EndLoadDump($request);
338 * Dump all pages as XHTML to a directory, as pagename.html.
339 * Copies all used css files to the directory, all used images to a
340 * "images" subdirectory, and all used buttons to a "images/buttons" subdirectory.
341 * The webserver must have write permissions to these directories.
342 * chown httpd HTML_DUMP_DIR; chmod u+rwx HTML_DUMP_DIR
345 * @param string directory (optional) path to dump to. Default: HTML_DUMP_DIR
346 * @param string pages (optional) Comma-seperated of glob-style pagenames to dump
347 * @param string exclude (optional) Comma-seperated of glob-style pagenames to exclude
349 function DumpHtmlToDir (&$request)
351 $directory = $request->getArg('directory');
352 if (empty($directory))
353 $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
354 if (empty($directory))
355 $request->finish(_("You must specify a directory to dump to"));
357 // see if we can access the directory the user wants us to use
358 if (! file_exists($directory)) {
359 if (! mkdir($directory, 0755))
360 $request->finish(fmt("Cannot create directory '%s'", $directory));
362 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
365 $html = HTML::p(fmt("Using directory '%s'", $directory));
368 StartLoadDump($request, _("Dumping Pages"), $html);
369 $thispage = $request->getArg('pagename'); // for "Return to ..."
371 $dbi = $request->getDbh();
372 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
373 $excludeList = explodePageList($exclude);
375 $excludeList = array();
377 if ($whichpages = $request->getArg('pages')) { // which pagenames
378 if ($whichpages == '[]') // current page
379 $whichpages = $thispage;
380 $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
382 $pages = $dbi->getAllPages();
386 if (defined('HTML_DUMP_SUFFIX'))
387 $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
388 $WikiTheme->DUMP_MODE = 'HTML';
389 $request_args = $request->args;
391 while ($page = $pages->next()) {
392 $request->args = $request_args; // some plugins might change them (esp. on POST)
393 if (! $request->getArg('start_debug'))
394 @set_time_limit(30); // Reset watchdog.
396 @set_time_limit(240);
398 $pagename = $page->getName();
399 if (!isa($request,'MockRequest')) {
400 PrintXML(HTML::br(), $pagename, ' ... ');
403 if (in_array($pagename, $excludeList)) {
404 if (!isa($request,'MockRequest')) {
405 PrintXML(_("Skipped."));
411 $request->setArg('pagename', $pagename); // Template::_basepage fix
412 $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
415 $revision = $page->getCurrentRevision();
416 $transformedContent = $revision->getTransformedContent();
417 $template = new Template('browse', $request,
418 array('revision' => $revision,
419 'CONTENT' => $transformedContent));
421 $data = GeneratePageasXML($template, $pagename);
423 if ( !($fd = fopen("$directory/$filename", "wb")) ) {
424 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
425 "$directory/$filename")));
426 $request->finish($msg);
428 $num = fwrite($fd, $data, strlen($data));
429 if($page->getName() != $filename) {
432 // drive where apache is installed
433 $prefix = '/' . substr($_SERVER["DOCUMENT_ROOT"],0,2);
435 $link = LinkURL("file://".$prefix.$directory."/".$filename,
437 $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
439 $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
440 if (!isa($request,'MockRequest')) {
445 assert($num == strlen($data));
449 if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
450 @mkdir("$directory/images");
451 foreach ($WikiTheme->dumped_images as $img_file) {
452 if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
453 $target = "$directory/images/".basename($img_file);
454 if (copy($WikiTheme->_path . $from, $target)) {
455 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
456 if (!isa($request,'MockRequest'))
460 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
461 if (!isa($request,'MockRequest'))
466 if (!empty($WikiTheme->dumped_buttons) and is_array($WikiTheme->dumped_buttons)) {
468 @mkdir("$directory/images/buttons");
469 foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
470 if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
471 $target = "$directory/images/buttons/".basename($img_file);
472 if (copy($WikiTheme->_path . $from, $target)) {
473 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
474 if (!isa($request,'MockRequest'))
478 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
479 if (!isa($request,'MockRequest'))
484 if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
485 foreach ($WikiTheme->dumped_css as $css_file) {
486 if (($from = $WikiTheme->_findFile(basename($css_file))) and basename($from)) {
487 $target = "$directory/" . basename($css_file);
488 if (copy($WikiTheme->_path . $from, $target)) {
489 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
490 if (!isa($request,'MockRequest'))
494 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
495 if (!isa($request,'MockRequest'))
500 $WikiTheme->HTML_DUMP_SUFFIX = '';
501 $WikiTheme->DUMP_MODE = false;
503 $request->setArg('pagename',$thispage); // Template::_basepage fix
504 EndLoadDump($request);
507 /* Known problem: any plugins or other code which echo()s text will
508 * lead to a corrupted html zip file which may produce the following
509 * errors upon unzipping:
511 * warning [wikihtml.zip]: 2401 extra bytes at beginning or within zipfile
512 * file #58: bad zipfile offset (local header sig): 177561
513 * (attempting to re-compensate)
515 * However, the actual wiki page data should be unaffected.
517 function MakeWikiZipHtml (&$request)
519 $zipname = "wikihtml.zip";
520 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
521 $dbi = $request->getDbh();
522 $thispage = $request->getArg('pagename'); // for "Return to ..."
523 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
524 $excludeList = explodePageList($exclude);
526 $excludeList = array();
528 if ($whichpages = $request->getArg('pages')) { // which pagenames
529 if ($whichpages == '[]') // current page
530 $whichpages = $thispage;
531 $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
533 $pages = $dbi->getAllPages();
537 if (defined('HTML_DUMP_SUFFIX'))
538 $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
540 /* ignore fatals in plugins */
541 if (check_php_version(4,1)) {
542 global $ErrorManager;
543 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
546 $request_args = $request->args;
548 while ($page = $pages->next()) {
549 $request->args = $request_args; // some plugins might change them (esp. on POST)
550 if (! $request->getArg('start_debug'))
551 @set_time_limit(30); // Reset watchdog.
553 @set_time_limit(240);
555 $current = $page->getCurrentRevision();
556 if ($current->getVersion() == 0)
558 $pagename = $page->getName();
559 if (in_array($pagename, $excludeList)) {
563 $attrib = array('mtime' => $current->get('mtime'),
565 if ($page->get('locked'))
566 $attrib['write_protected'] = 1;
568 $request->setArg('pagename',$pagename); // Template::_basepage fix
569 $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
570 $revision = $page->getCurrentRevision();
572 $transformedContent = $revision->getTransformedContent();
574 $template = new Template('browse', $request,
575 array('revision' => $revision,
576 'CONTENT' => $transformedContent));
578 $data = GeneratePageasXML($template, $pagename);
580 $zip->addRegularFile( $filename, $data, $attrib);
582 // FIXME: Deal with images here.
584 if (check_php_version(4,1)) {
585 $ErrorManager->popErrorHandler();
587 $WikiTheme->$HTML_DUMP_SUFFIX = '';
591 ////////////////////////////////////////////////////////////////
593 // Functions for restoring.
595 ////////////////////////////////////////////////////////////////
597 function SavePage (&$request, $pageinfo, $source, $filename)
599 $pagedata = $pageinfo['pagedata']; // Page level meta-data.
600 $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
602 if (empty($pageinfo['pagename'])) {
603 PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
607 if (empty($versiondata['author_id']))
608 $versiondata['author_id'] = $versiondata['author'];
610 $pagename = $pageinfo['pagename'];
611 $content = $pageinfo['content'];
613 if ($pagename ==_("InterWikiMap"))
614 $content = _tryinsertInterWikiMap($content);
616 $dbi = $request->getDbh();
617 $page = $dbi->getPage($pagename);
619 // Try to merge if updated pgsrc contents are different. This
620 // whole thing is hackish
622 // TODO: try merge unless:
623 // if (current contents = default contents && pgsrc_version >=
624 // pgsrc_version) then just upgrade this pgsrc
625 $needs_merge = false;
629 if ($request->getArg('merge')) {
632 else if ($request->getArg('overwrite')) {
636 $current = $page->getCurrentRevision();
637 if ( $current and (! $current->hasDefaultContents())
638 && ($current->getPackedContent() != $content)
639 && ($merging == true) ) {
640 include_once('lib/editpage.php');
641 $request->setArg('pagename', $pagename);
642 $r = $current->getVersion();
643 $request->setArg('revision', $current->getVersion());
644 $p = new LoadFileConflictPageEditor($request);
645 $p->_content = $content;
646 $p->_currentVersion = $r - 1;
647 $p->editPage($saveFailed = true);
648 return; //early return
651 foreach ($pagedata as $key => $value) {
653 $page->set($key, $value);
659 $mesg->pushContent(' ', fmt("from %s", $source));
663 //FIXME: This should not happen! (empty vdata, corrupt cache or db)
664 $current = $page->getCurrentRevision();
666 if ($current->getVersion() == 0) {
667 $mesg->pushContent(' - ', _("new page"));
671 if ( (! $current->hasDefaultContents())
672 && ($current->getPackedContent() != $content) ) {
674 $mesg->pushContent(' ',
675 fmt("has edit conflicts - overwriting anyway"));
677 if (substr_count($source, 'pgsrc')) {
678 $versiondata['author'] = _("The PhpWiki programming team");
679 // but leave authorid as userid who loaded the file
683 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
684 $needs_merge = true; // hackish
688 else if ($current->getPackedContent() == $content
689 && $current->get('author') == $versiondata['author']) {
690 // The page metadata is already changed, we don't need a new revision.
691 // This was called previously "is identical to current version %d - skipped"
692 // which is wrong, since the pagedata was stored, not skipped.
693 $mesg->pushContent(' ',
694 fmt("content is identical to current version %d - no new revision created",
695 $current->getVersion()));
702 // in case of failures print the culprit:
703 if (!isa($request,'MockRequest')) {
704 PrintXML(HTML::dt(WikiLink($pagename))); flush();
706 $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
708 $mesg->pushContent(' ', fmt("- saved to database as version %d",
709 $new->getVersion()));
713 // hackish, $source contains needed path+filename
714 $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
715 $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
716 $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
717 //check if uploaded file? they pass just the content, but the file is gone
720 $meb = Button(array('action' => 'loadfile',
724 _("PhpWikiAdministration"),
726 $owb = Button(array('action' => 'loadfile',
730 _("PhpWikiAdministration"),
732 $mesg->pushContent(' ', $meb, " ", $owb);
734 $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
738 if (!isa($request,'MockRequest')) {
740 PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
747 // action=revert (by diff)
748 function RevertPage (&$request)
751 $pagename = $request->getArg('pagename');
752 $version = $request->getArg('version');
754 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
755 HTML::dd(_("missing required version argument")));
758 $dbi = $request->getDbh();
759 $page = $dbi->getPage($pagename);
760 $current = $page->getCurrentRevision();
761 if ($current->getVersion() == 0) {
762 $mesg->pushContent(' ', _("no page content"));
763 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
767 if ($current->getVersion() == $version) {
768 $mesg->pushContent(' ', _("same version page"));
771 $rev = $page->getRevision($version);
772 $content = $rev->getPackedContent();
773 $versiondata = $rev->_data;
774 $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
775 $new = $page->save($content, $current->getVersion() + 1, $versiondata);
777 $mesg->pushContent(' ', fmt("- version %d saved to database as version %d",
778 $version, $new->getVersion()));
779 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
784 function _tryinsertInterWikiMap($content) {
786 if (strpos($content, "<verbatim>")) {
787 //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
790 if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
791 $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
794 $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
795 if (!$goback && !file_exists($mapfile)) {
796 $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
800 if (!empty($error_html))
801 trigger_error(_("Default InterWiki map file not loaded.")
802 . $error_html, E_USER_NOTICE);
806 // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
807 if (!isa($GLOBALS['request'],'MockRequest'))
808 echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
810 $fd = fopen ($mapfile, "rb");
811 $data = fread ($fd, filesize($mapfile));
813 $content = $content . "\n<verbatim>\n$data</verbatim>\n";
817 function ParseSerializedPage($text, $default_pagename, $user)
819 if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
822 $pagehash = unserialize($text);
824 // Split up pagehash into four parts:
827 // page-level meta-data
828 // revision-level meta-data
830 if (!defined('FLAG_PAGE_LOCKED'))
831 define('FLAG_PAGE_LOCKED', 1);
832 $pageinfo = array('pagedata' => array(),
833 'versiondata' => array());
835 $pagedata = &$pageinfo['pagedata'];
836 $versiondata = &$pageinfo['versiondata'];
839 if (empty($pagehash['pagename']))
840 $pagehash['pagename'] = $default_pagename;
841 if (empty($pagehash['author'])) {
842 $pagehash['author'] = $user->getId();
845 foreach ($pagehash as $key => $value) {
850 $pageinfo[$key] = $value;
853 $pageinfo[$key] = join("\n", $value);
856 if (($value & FLAG_PAGE_LOCKED) != 0)
857 $pagedata['locked'] = 'yes';
861 $pagedata[$key] = $value;
865 $pagedata['perm'] = ParseMimeifiedPerm($value);
868 $versiondata['mtime'] = $value;
873 $versiondata[$key] = $value;
880 function SortByPageVersion ($a, $b) {
881 return $a['version'] - $b['version'];
884 function LoadFile (&$request, $filename, $text = false, $mtime = false)
886 if (!is_string($text)) {
888 $stat = stat($filename);
890 $text = implode("", file($filename));
893 if (! $request->getArg('start_debug'))
894 @set_time_limit(30); // Reset watchdog.
896 @set_time_limit(240);
898 // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
899 $basename = basename("/dummy/" . $filename);
902 $mtime = time(); // Last resort.
904 $default_pagename = rawurldecode($basename);
906 if ( ($parts = ParseMimeifiedPages($text)) ) {
907 usort($parts, 'SortByPageVersion');
908 foreach ($parts as $pageinfo)
909 SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
910 $filename), $basename);
912 else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
913 $request->getUser())) ) {
914 SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
915 $filename), $basename);
918 $user = $request->getUser();
920 // Assume plain text file.
921 $pageinfo = array('pagename' => $default_pagename,
922 'pagedata' => array(),
924 => array('author' => $user->getId()),
925 'content' => preg_replace('/[ \t\r]*\n/', "\n",
928 SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
933 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
934 $zip = new ZipReader($zipfile);
935 while (list ($fn, $data, $attrib) = $zip->readFile()) {
936 // FIXME: basename("filewithnoslashes") seems to return
937 // garbage sometimes.
938 $fn = basename("/dummy/" . $fn);
939 if ( ($files && !in_array($fn, $files))
940 || ($exclude && in_array($fn, $exclude)) ) {
941 PrintXML(HTML::dt(WikiLink($fn)),
942 HTML::dd(_("Skipping")));
947 LoadFile($request, $fn, $data, $attrib['mtime']);
951 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
952 $fileset = new LimitedFileSet($dirname, $files, $exclude);
954 if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
955 PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
957 foreach ($skiplist as $file)
958 $list->pushContent(HTML::li(WikiLink($file)));
959 PrintXML(HTML::dd($list));
962 // Defer HomePage loading until the end. If anything goes wrong
963 // the pages can still be loaded again.
964 $files = $fileset->getFiles();
965 if (in_array(HOME_PAGE, $files)) {
966 $files = array_diff($files, array(HOME_PAGE));
967 $files[] = HOME_PAGE;
969 foreach ($files as $file) {
970 if (substr($file,-1,1) != '~') // refuse to load backup files
971 LoadFile($request, "$dirname/$file");
975 class LimitedFileSet extends FileSet {
976 function LimitedFileSet($dirname, $_include, $exclude) {
977 $this->_includefiles = $_include;
978 $this->_exclude = $exclude;
979 $this->_skiplist = array();
980 parent::FileSet($dirname);
983 function _filenameSelector($fn) {
984 $incl = &$this->_includefiles;
985 $excl = &$this->_exclude;
987 if ( ($incl && !in_array($fn, $incl))
988 || ($excl && in_array($fn, $excl)) ) {
989 $this->_skiplist[] = $fn;
996 function getSkippedFiles () {
997 return $this->_skiplist;
1002 function IsZipFile ($filename_or_fd)
1004 // See if it looks like zip file
1005 if (is_string($filename_or_fd))
1007 $fd = fopen($filename_or_fd, "rb");
1008 $magic = fread($fd, 4);
1013 $fpos = ftell($filename_or_fd);
1014 $magic = fread($filename_or_fd, 4);
1015 fseek($filename_or_fd, $fpos);
1018 return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1022 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
1024 // Try urlencoded filename for accented characters.
1025 if (!file_exists($file_or_dir)) {
1026 // Make sure there are slashes first to avoid confusing phps
1027 // with broken dirname or basename functions.
1028 // FIXME: windows uses \ and :
1029 if (is_integer(strpos($file_or_dir, "/"))) {
1030 $file_or_dir = FindFile($file_or_dir);
1032 if (!file_exists($file_or_dir))
1033 $file_or_dir = dirname($file_or_dir) . "/"
1034 . urlencode(basename($file_or_dir));
1036 // This is probably just a file.
1037 $file_or_dir = urlencode($file_or_dir);
1041 $type = filetype($file_or_dir);
1042 if ($type == 'link') {
1043 // For symbolic links, use stat() to determine
1044 // the type of the underlying file.
1045 list(,,$mode) = stat($file_or_dir);
1046 $type = ($mode >> 12) & 017;
1049 elseif ($type == 004)
1054 $request->finish(fmt("Unable to load: %s", $file_or_dir));
1056 else if ($type == 'dir') {
1057 LoadDir($request, $file_or_dir, $files, $exclude);
1059 else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
1061 $request->finish(fmt("Bad file type: %s", $type));
1063 else if (IsZipFile($file_or_dir)) {
1064 LoadZip($request, $file_or_dir, $files, $exclude);
1066 else /* if (!$files || in_array(basename($file_or_dir), $files)) */
1068 LoadFile($request, $file_or_dir);
1072 function LoadFileOrDir (&$request)
1074 $source = $request->getArg('source');
1075 $finder = new FileFinder;
1076 $source = $finder->slashifyPath($source);
1077 $page = rawurldecode(basename($source));
1078 StartLoadDump($request, fmt("Loading '%s'",
1079 HTML(dirname($source),
1080 dirname($source) ? "/" : "",
1081 WikiLink($page,'auto'))));
1083 LoadAny($request, $source);
1085 EndLoadDump($request);
1088 function SetupWiki (&$request)
1090 global $GenericPages, $LANG;
1093 //FIXME: This is a hack (err, "interim solution")
1094 // This is a bogo-bogo-login: Login without
1095 // saving login information in session state.
1096 // This avoids logging in the unsuspecting
1097 // visitor as "The PhpWiki programming team".
1099 // This really needs to be cleaned up...
1100 // (I'm working on it.)
1101 $real_user = $request->_user;
1102 if (ENABLE_USER_NEW)
1103 $request->_user = new _BogoUser(_("The PhpWiki programming team"));
1106 $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
1109 StartLoadDump($request, _("Loading up virgin wiki"));
1112 $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1113 $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1115 $request->setArg('overwrite',true);
1116 if ($default_pgsrc != $pgsrc) {
1117 LoadAny($request, $default_pgsrc, $GenericPages);
1119 $request->setArg('overwrite',false);
1120 LoadAny($request, $pgsrc);
1122 // Ensure that all mandatory pages are loaded
1123 $finder = new FileFinder;
1124 foreach (array_merge(explode(':','OldTextFormattingRules:TextFormattingRules:PhpWikiAdministration'),
1125 $GLOBALS['AllActionPages'],
1126 array(constant('HOME_PAGE'))) as $f) {
1127 $page = gettext($f);
1128 if (isSubPage($page))
1129 $page = urlencode($page);
1130 if (! $request->_dbi->isWikiPage(urldecode($page)) ) {
1131 // translated version provided?
1132 if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $page, 1))
1133 LoadAny($request, $lf);
1134 else { // load english version of required action page
1135 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1139 if (!$request->_dbi->isWikiPage(urldecode($page))) {
1140 trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1146 EndLoadDump($request);
1149 function LoadPostFile (&$request)
1151 $upload = $request->getUploadedFile('file');
1154 $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1157 // Dump http headers.
1158 StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1161 $fd = $upload->open();
1163 LoadZip($request, $fd, false, array(_("RecentChanges")));
1165 LoadFile($request, $upload->getName(), $upload->getContents());
1168 EndLoadDump($request);
1172 $Log: not supported by cvs2svn $
1173 Revision 1.119 2004/07/08 15:23:59 rurban
1174 less verbose for tests
1176 Revision 1.118 2004/07/08 13:50:32 rurban
1177 various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
1179 Revision 1.117 2004/07/02 09:55:58 rurban
1180 more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
1182 Revision 1.116 2004/07/01 09:05:41 rurban
1183 support pages and exclude arguments for all 4 dump methods
1185 Revision 1.115 2004/07/01 08:51:22 rurban
1186 dumphtml: added exclude, print pagename before processing
1188 Revision 1.114 2004/06/28 12:51:41 rurban
1189 improved dumphtml and virgin setup
1191 Revision 1.113 2004/06/27 10:26:02 rurban
1192 oci8 patch by Philippe Vanhaesendonck + some ADODB notes+fixes
1194 Revision 1.112 2004/06/25 14:29:20 rurban
1195 WikiGroup refactoring:
1196 global group attached to user, code for not_current user.
1197 improved helpers for special groups (avoid double invocations)
1198 new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
1199 fixed a XHTML validation error on userprefs.tmpl
1201 Revision 1.111 2004/06/21 16:38:55 rurban
1202 fixed the StartLoadDump html argument hack.
1204 Revision 1.110 2004/06/21 16:22:30 rurban
1205 add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1206 fixed dumping buttons locally (images/buttons/),
1207 support pages arg for dumphtml,
1208 optional directory arg for dumpserial + dumphtml,
1209 fix a AllPages warning,
1210 show dump warnings/errors on DEBUG,
1211 don't warn just ignore on wikilens pagelist columns, if not loaded.
1212 RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1214 Revision 1.109 2004/06/17 11:31:05 rurban
1215 jump back to label after dump/upgrade
1217 Revision 1.108 2004/06/16 12:43:01 rurban
1218 4.0.6 cannot use this errorhandler (not found)
1220 Revision 1.107 2004/06/14 11:31:37 rurban
1221 renamed global $Theme to $WikiTheme (gforge nameclash)
1222 inherit PageList default options from PageList
1223 default sortby=pagename
1224 use options in PageList_Selectable (limit, sortby, ...)
1225 added action revert, with button at action=diff
1226 added option regex to WikiAdminSearchReplace
1228 Revision 1.106 2004/06/13 13:54:25 rurban
1229 Catch fatals on the four dump calls (as file and zip, as html and mimified)
1230 FoafViewer: Check against external requirements, instead of fatal.
1231 Change output for xhtmldumps: using file:// urls to the local fs.
1232 Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1233 Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1235 Revision 1.105 2004/06/08 19:48:16 rurban
1236 fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1238 Revision 1.104 2004/06/08 13:51:57 rurban
1241 Revision 1.103 2004/06/08 10:54:46 rurban
1242 better acl dump representation, read back acl and owner
1244 Revision 1.102 2004/06/06 16:58:51 rurban
1245 added more required ActionPages for foreign languages
1246 install now english ActionPages if no localized are found. (again)
1247 fixed default anon user level to be 0, instead of -1
1248 (wrong "required administrator to view this page"...)
1250 Revision 1.101 2004/06/04 20:32:53 rurban
1251 Several locale related improvements suggested by Pierrick Meignen
1252 LDAP fix by John Cole
1253 reanable admin check without ENABLE_PAGEPERM in the admin plugins
1255 Revision 1.100 2004/05/02 21:26:38 rurban
1256 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1257 because they will not survive db sessions, if too large.
1258 extended action=upgrade
1259 some WikiTranslation button work
1260 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1261 some temp. session debug statements
1263 Revision 1.99 2004/05/02 15:10:07 rurban
1264 new finally reliable way to detect if /index.php is called directly
1265 and if to include lib/main.php
1266 new global AllActionPages
1267 SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1268 WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1269 PageGroupTestOne => subpages
1270 renamed PhpWikiRss to PhpWikiRecentChanges
1271 more docs, default configs, ...
1273 Revision 1.98 2004/04/29 23:25:12 rurban
1274 re-ordered locale init (as in 1.3.9)
1275 fixed loadfile with subpages, and merge/restore anyway
1276 (sf.net bug #844188)
1278 Revision 1.96 2004/04/19 23:13:03 zorloc
1279 Connect the rest of PhpWiki to the IniConfig system. Also the keyword regular expression is not a config setting
1281 Revision 1.95 2004/04/18 01:11:52 rurban
1282 more numeric pagename fixes.
1283 fixed action=upload with merge conflict warnings.
1284 charset changed from constant to global (dynamic utf-8 switching)
1286 Revision 1.94 2004/03/14 16:36:37 rurban
1287 dont load backup files
1289 Revision 1.93 2004/02/26 03:22:05 rurban
1290 also copy css and images with XHTML Dump
1292 Revision 1.92 2004/02/26 02:25:54 rurban
1293 fix empty and #-anchored links in XHTML Dumps
1295 Revision 1.91 2004/02/24 17:19:37 rurban
1296 debugging helpers only
1298 Revision 1.90 2004/02/24 17:09:24 rurban
1299 fixed \r\r\n with dumping on windows
1301 Revision 1.88 2004/02/22 23:20:31 rurban
1302 fixed DumpHtmlToDir,
1303 enhanced sortby handling in PageList
1304 new button_heading th style (enabled),
1305 added sortby and limit support to the db backends and plugins
1306 for paging support (<<prev, next>> links on long lists)
1308 Revision 1.87 2004/01/26 09:17:49 rurban
1309 * changed stored pref representation as before.
1310 the array of objects is 1) bigger and 2)
1311 less portable. If we would import packed pref
1312 objects and the object definition was changed, PHP would fail.
1313 This doesn't happen with an simple array of non-default values.
1314 * use $prefs->retrieve and $prefs->store methods, where retrieve
1315 understands the interim format of array of objects also.
1316 * simplified $prefs->get() and fixed $prefs->set()
1317 * added $user->_userid and class '_WikiUser' portability functions
1318 * fixed $user object ->_level upgrading, mostly using sessions.
1319 this fixes yesterdays problems with loosing authorization level.
1320 * fixed WikiUserNew::checkPass to return the _level
1321 * fixed WikiUserNew::isSignedIn
1322 * added explodePageList to class PageList, support sortby arg
1323 * fixed UserPreferences for WikiUserNew
1324 * fixed WikiPlugin for empty defaults array
1325 * UnfoldSubpages: added pagename arg, renamed pages arg,
1326 removed sort arg, support sortby arg
1328 Revision 1.86 2003/12/02 16:18:26 carstenklapp
1329 Minor enhancement: Provide more meaningful filenames for WikiDB zip
1332 Revision 1.85 2003/11/30 18:18:13 carstenklapp
1333 Minor code optimization: use include_once instead of require_once
1334 inside functions that might not always called.
1336 Revision 1.84 2003/11/26 20:47:47 carstenklapp
1337 Redo bugfix: My last refactoring broke merge-edit & overwrite
1338 functionality again, should be fixed now. Sorry.
1340 Revision 1.83 2003/11/20 22:18:54 carstenklapp
1341 New feature: h1 during merge-edit displays WikiLink to original page.
1342 Internal changes: Replaced some hackish url-generation code in
1343 function SavePage (for pgsrc merge-edit) with appropriate Button()
1346 Revision 1.82 2003/11/18 19:48:01 carstenklapp
1347 Fixed missing gettext _() for button name.
1349 Revision 1.81 2003/11/18 18:28:35 carstenklapp
1350 Bugfix: In the Load File function of PhpWikiAdministration: When doing
1351 a "Merge Edit" or "Restore Anyway", page names containing accented
1352 letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1353 found error (Use FilenameForPage funtion to urlencode page names).
1355 Revision 1.80 2003/03/07 02:46:57 dairiki
1356 Omit checks for safe_mode before set_time_limit(). Just prefix the
1357 set_time_limit() calls with @ so that they fail silently if not
1360 Revision 1.79 2003/02/26 01:56:05 dairiki
1361 Only zip pages with legal pagenames.
1363 Revision 1.78 2003/02/24 02:05:43 dairiki
1364 Fix "n bytes written" message when dumping HTML.
1366 Revision 1.77 2003/02/21 04:12:05 dairiki
1367 Minor fixes for new cached markup.
1369 Revision 1.76 2003/02/16 19:47:17 dairiki
1370 Update WikiDB timestamp when editing or deleting pages.
1372 Revision 1.75 2003/02/15 03:04:30 dairiki
1373 Fix for WikiUser constructor API change.
1375 Revision 1.74 2003/02/15 02:18:04 dairiki
1376 When default language was English (at least), pgsrc was being
1379 LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1381 SetupWiki(): Fix bugs in loading of $GenericPages.
1383 Revision 1.73 2003/01/28 21:09:17 zorloc
1384 The get_cfg_var() function should only be used when one is
1385 interested in the value from php.ini or similar. Use ini_get()
1386 instead to get the effective value of a configuration variable.
1389 Revision 1.72 2003/01/03 22:25:53 carstenklapp
1390 Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1391 programming team" as author when loading from pgsrc. Source
1394 Revision 1.71 2003/01/03 02:48:05 carstenklapp
1395 function SavePage: Added loadfile options for overwriting or merge &
1396 compare a loaded pgsrc file with an existing page.
1398 function LoadAny: Added a general error message when unable to load a
1399 file instead of defaulting to "Bad file type".
1407 // c-basic-offset: 4
1408 // c-hanging-comment-ender-p: nil
1409 // indent-tabs-mode: nil