2 rcs_id('$Id: loadsave.php,v 1.111 2004-06-21 16:38:55 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 // FIXME: This is a hack
49 $html->pushContent('%BODY%');
50 $tmpl = Template('html', array('TITLE' => $title,
52 'CONTENT' => $html ? $html : '%BODY%'));
53 echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
55 /* Ignore fatals or warnings in any pagedumps (failing plugins).
56 * WikiFunctionCb() fails with 4.0.6, works ok with 4.1.1
58 if (!check_php_version(4,1) or DEBUG) return;
60 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
63 function EndLoadDump(&$request)
65 if (check_php_version(4,1)) {
67 $ErrorManager->popErrorHandler();
69 $action = $request->getArg('action');
72 case 'zip': $label = _("ZIP files of database"); break;
73 case 'dumpserial': $label = _("Dump to directory"); break;
74 case 'upload': $label = _("Upload File"); break;
75 case 'loadfile': $label = _("Load File"); break;
76 case 'upgrade': $label = _("Upgrade"); break;
78 case 'ziphtml': $label = _("Dump pages as XHTML"); break;
80 if ($label) $label = str_replace(" ","_",$label);
81 $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"),false,$label));
83 PrintXML(HTML::p(HTML::strong(_("Complete."))),
84 HTML::p(fmt("Return to %s", $pagelink)));
85 echo "</body></html>\n";
89 ////////////////////////////////////////////////////////////////
91 // Functions for dumping.
93 ////////////////////////////////////////////////////////////////
97 * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
98 * http://www.faqs.org/rfcs/rfc2045.html
99 * (RFC 1521 has been superceeded by RFC 2045 & others).
101 * Also see http://www.faqs.org/rfcs/rfc2822.html
103 function MailifyPage ($page, $nversions = 1)
105 $current = $page->getCurrentRevision();
108 if (STRICT_MAILABLE_PAGEDUMPS) {
109 $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
110 //This is for unix mailbox format: (not RFC (2)822)
111 // $head .= "From $from " . CTime(time()) . "\r\n";
112 $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
113 $head .= "From: $from (PhpWiki)\r\n";
114 // RFC 2822 requires only a Date: and originator (From:)
115 // field, however the obsolete standard RFC 822 also
116 // requires a destination field.
117 $head .= "To: $from (PhpWiki)\r\n";
119 $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
120 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
123 // This should just be entered by hand (or by script?)
124 // in the actual pgsrc files, since only they should have
126 //$head .= "X-Rcs-Id: \$Id\$\r\n";
128 $iter = $page->getAllRevisions();
130 while ($revision = $iter->next()) {
131 $parts[] = MimeifyPageRevision($revision);
132 if ($nversions > 0 && count($parts) >= $nversions)
135 if (count($parts) > 1)
136 return $head . MimeMultipart($parts);
138 return $head . $parts[0];
142 * Compute filename to used for storing contents of a wiki page.
144 * Basically we do a rawurlencode() which encodes everything except
145 * ASCII alphanumerics and '.', '-', and '_'.
147 * But we also want to encode leading dots to avoid filenames like
148 * '.', and '..'. (Also, there's no point in generating "hidden" file
149 * names, like '.foo'.)
151 * @param $pagename string Pagename.
152 * @return string Filename for page.
154 function FilenameForPage ($pagename)
156 $enc = rawurlencode($pagename);
157 return preg_replace('/^\./', '%2e', $enc);
161 * The main() function which generates a zip archive of a PhpWiki.
163 * If $include_archive is false, only the current version of each page
164 * is included in the zip file; otherwise all archived versions are
167 function MakeWikiZip (&$request)
169 if ($request->getArg('include') == 'all') {
170 $zipname = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
171 $include_archive = true;
174 $zipname = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
175 $include_archive = false;
179 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
181 /* ignore fatals in plugins */
182 if (check_php_version(4,1)) {
183 global $ErrorManager;
184 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
187 $dbi = $request->getDbh();
188 $pages = $dbi->getAllPages();
189 while ($page = $pages->next()) {
190 if (! $request->getArg('start_debug'))
191 @set_time_limit(30); // Reset watchdog
193 $current = $page->getCurrentRevision();
194 if ($current->getVersion() == 0)
197 $wpn = new WikiPageName($page->getName());
198 if (!$wpn->isValid())
201 $attrib = array('mtime' => $current->get('mtime'),
203 if ($page->get('locked'))
204 $attrib['write_protected'] = 1;
206 if ($include_archive)
207 $content = MailifyPage($page, 0);
209 $content = MailifyPage($page);
211 $zip->addRegularFile( FilenameForPage($page->getName()),
215 if (check_php_version(4,1)) {
216 $ErrorManager->popErrorHandler();
220 function DumpToDir (&$request)
222 $directory = $request->getArg('directory');
223 if (empty($directory))
224 $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
225 if (empty($directory))
226 $request->finish(_("You must specify a directory to dump to"));
228 // see if we can access the directory the user wants us to use
229 if (! file_exists($directory)) {
230 if (! mkdir($directory, 0755))
231 $request->finish(fmt("Cannot create directory '%s'", $directory));
233 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
236 $html = HTML::p(fmt("Using directory '%s'", $directory));
239 StartLoadDump($request, _("Dumping Pages"), $html);
241 $dbi = $request->getDbh();
242 $pages = $dbi->getAllPages();
244 while ($page = $pages->next()) {
245 if (! $request->getArg('start_debug'))
246 @set_time_limit(30); // Reset watchdog.
248 $filename = FilenameForPage($page->getName());
250 $msg = HTML(HTML::br(), $page->getName(), ' ... ');
252 if($page->getName() != $filename) {
253 $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
257 if ($request->getArg('include') == 'all')
258 $data = MailifyPage($page, 0);
260 $data = MailifyPage($page);
262 if ( !($fd = fopen("$directory/$filename", "wb")) ) {
263 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
264 "$directory/$filename")));
265 $request->finish($msg);
268 $num = fwrite($fd, $data, strlen($data));
269 $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
273 assert($num == strlen($data));
277 EndLoadDump($request);
281 function DumpHtmlToDir (&$request)
283 $directory = $request->getArg('directory');
284 if (empty($directory))
285 $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
286 if (empty($directory))
287 $request->finish(_("You must specify a directory to dump to"));
289 // see if we can access the directory the user wants us to use
290 if (! file_exists($directory)) {
291 if (! mkdir($directory, 0755))
292 $request->finish(fmt("Cannot create directory '%s'", $directory));
294 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
297 $html = HTML::p(fmt("Using directory '%s'", $directory));
300 StartLoadDump($request, _("Dumping Pages"), $html);
301 $thispage = $request->getArg('pagename'); // for "Return to ..."
303 $dbi = $request->getDbh();
304 if ($whichpages = $request->getArg('pages')) { // which pagenames
305 if ($whichpages == '[]') // current page
306 $whichpages = $thispage;
307 $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
309 $pages = $dbi->getAllPages();
313 if (defined('HTML_DUMP_SUFFIX'))
314 $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
315 $WikiTheme->DUMP_MODE = 'HTML';
317 while ($page = $pages->next()) {
318 if (! $request->getArg('start_debug'))
319 @set_time_limit(30); // Reset watchdog.
321 $pagename = $page->getName();
322 $request->setArg('pagename',$pagename); // Template::_basepage fix
323 $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
325 $msg = HTML(HTML::br(), $pagename, ' ... ');
327 $revision = $page->getCurrentRevision();
328 $transformedContent = $revision->getTransformedContent();
329 $template = new Template('browse', $request,
330 array('revision' => $revision,
331 'CONTENT' => $transformedContent));
333 $data = GeneratePageasXML($template, $pagename);
335 if ( !($fd = fopen("$directory/$filename", "wb")) ) {
336 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
337 "$directory/$filename")));
338 $request->finish($msg);
340 $num = fwrite($fd, $data, strlen($data));
341 if($page->getName() != $filename) {
344 // drive where apache is installed
345 $prefix = '/' . substr($_SERVER["DOCUMENT_ROOT"],0,2);
347 $link = LinkURL("file://".$prefix.$directory."/".$filename,
349 $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
351 $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
355 assert($num == strlen($data));
359 if (is_array($WikiTheme->dumped_images)) {
360 @mkdir("$directory/images");
361 foreach ($WikiTheme->dumped_images as $img_file) {
362 if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
363 $target = "$directory/images/".basename($img_file);
364 if (copy($WikiTheme->_path . $from, $target)) {
365 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
369 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
374 if (is_array($WikiTheme->dumped_buttons)) {
376 @mkdir("$directory/images/buttons");
377 foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
378 if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
379 $target = "$directory/images/buttons/".basename($img_file);
380 if (copy($WikiTheme->_path . $from, $target)) {
381 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
385 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
390 if (is_array($WikiTheme->dumped_css)) {
391 foreach ($WikiTheme->dumped_css as $css_file) {
392 if (($from = $WikiTheme->_findFile(basename($css_file))) and basename($from)) {
393 $target = "$directory/" . basename($css_file);
394 if (copy($WikiTheme->_path . $from, $target)) {
395 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
399 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
404 $WikiTheme->HTML_DUMP_SUFFIX = '';
405 $WikiTheme->DUMP_MODE = false;
407 $request->setArg('pagename',$thispage); // Template::_basepage fix
408 EndLoadDump($request);
411 /* Known problem: any plugins or other code which echo()s text will
412 * lead to a corrupted html zip file which may produce the following
413 * errors upon unzipping:
415 * warning [wikihtml.zip]: 2401 extra bytes at beginning or within zipfile
416 * file #58: bad zipfile offset (local header sig): 177561
417 * (attempting to re-compensate)
419 * However, the actual wiki page data should be unaffected.
421 function MakeWikiZipHtml (&$request)
423 $zipname = "wikihtml.zip";
424 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
425 $dbi = $request->getDbh();
426 $pages = $dbi->getAllPages();
429 if (defined('HTML_DUMP_SUFFIX'))
430 $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
432 /* ignore fatals in plugins */
433 if (check_php_version(4,1)) {
434 global $ErrorManager;
435 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
438 while ($page = $pages->next()) {
439 if (! $request->getArg('start_debug'))
440 @set_time_limit(30); // Reset watchdog.
442 $current = $page->getCurrentRevision();
443 if ($current->getVersion() == 0)
446 $attrib = array('mtime' => $current->get('mtime'),
448 if ($page->get('locked'))
449 $attrib['write_protected'] = 1;
451 $pagename = $page->getName();
452 $request->setArg('pagename',$pagename); // Template::_basepage fix
453 $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
454 $revision = $page->getCurrentRevision();
456 $transformedContent = $revision->getTransformedContent();
458 $template = new Template('browse', $request,
459 array('revision' => $revision,
460 'CONTENT' => $transformedContent));
462 $data = GeneratePageasXML($template, $pagename);
464 $zip->addRegularFile( $filename, $data, $attrib);
466 // FIXME: Deal with images here.
468 if (check_php_version(4,1)) {
469 $ErrorManager->popErrorHandler();
471 $WikiTheme->$HTML_DUMP_SUFFIX = '';
475 ////////////////////////////////////////////////////////////////
477 // Functions for restoring.
479 ////////////////////////////////////////////////////////////////
481 function SavePage (&$request, $pageinfo, $source, $filename)
483 $pagedata = $pageinfo['pagedata']; // Page level meta-data.
484 $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
486 if (empty($pageinfo['pagename'])) {
487 PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
491 if (empty($versiondata['author_id']))
492 $versiondata['author_id'] = $versiondata['author'];
494 $pagename = $pageinfo['pagename'];
495 $content = $pageinfo['content'];
497 if ($pagename ==_("InterWikiMap"))
498 $content = _tryinsertInterWikiMap($content);
500 $dbi = $request->getDbh();
501 $page = $dbi->getPage($pagename);
503 $current = $page->getCurrentRevision();
504 // Try to merge if updated pgsrc contents are different. This
505 // whole thing is hackish
507 // TODO: try merge unless:
508 // if (current contents = default contents && pgsrc_version >=
509 // pgsrc_version) then just upgrade this pgsrc
510 $needs_merge = false;
514 if ($request->getArg('merge')) {
517 else if ($request->getArg('overwrite')) {
521 if ( (! $current->hasDefaultContents())
522 && ($current->getPackedContent() != $content)
523 && ($merging == true) ) {
524 include_once('lib/editpage.php');
525 $request->setArg('pagename', $pagename);
526 $r = $current->getVersion();
527 $request->setArg('revision', $current->getVersion());
528 $p = new LoadFileConflictPageEditor($request);
529 $p->_content = $content;
530 $p->_currentVersion = $r - 1;
531 $p->editPage($saveFailed = true);
532 return; //early return
535 foreach ($pagedata as $key => $value) {
537 $page->set($key, $value);
543 $mesg->pushContent(' ', fmt("from %s", $source));
546 $current = $page->getCurrentRevision();
547 if ($current->getVersion() == 0) {
548 $mesg->pushContent(' ', _("new page"));
552 if ( (! $current->hasDefaultContents())
553 && ($current->getPackedContent() != $content) ) {
555 $mesg->pushContent(' ',
556 fmt("has edit conflicts - overwriting anyway"));
558 if (substr_count($source, 'pgsrc')) {
559 $versiondata['author'] = _("The PhpWiki programming team");
560 // but leave authorid as userid who loaded the file
564 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
565 $needs_merge = true; // hackish
569 else if ($current->getPackedContent() == $content
570 && $current->get('author') == $versiondata['author']) {
571 // The page metadata is already changed, we don't need a new revision.
572 // This was called previously "is identical to current version %d - skipped"
573 // which is wrong, since the pagedata was stored, not skipped.
574 $mesg->pushContent(' ',
575 fmt("content is identical to current version %d - no new revision created",
576 $current->getVersion()));
583 $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
585 $mesg->pushContent(' ', fmt("- saved to database as version %d",
586 $new->getVersion()));
590 // hackish, $source contains needed path+filename
591 $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
592 $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
593 $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
594 //check if uploaded file? they pass just the content, but the file is gone
597 $meb = Button(array('action' => 'loadfile',
601 _("PhpWikiAdministration"),
603 $owb = Button(array('action' => 'loadfile',
607 _("PhpWikiAdministration"),
609 $mesg->pushContent(' ', $meb, " ", $owb);
611 $mesg->pushContent(HTML::em(_(" Sorry, cannot merge uploaded files.")));
616 PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
618 PrintXML(HTML::dt(WikiLink($pagename)), $mesg);
622 // action=revert (by diff)
623 function RevertPage (&$request)
626 $pagename = $request->getArg('pagename');
627 $version = $request->getArg('version');
629 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
630 HTML::dd(_("missing required version argument")));
633 $dbi = $request->getDbh();
634 $page = $dbi->getPage($pagename);
635 $current = $page->getCurrentRevision();
636 if ($current->getVersion() == 0) {
637 $mesg->pushContent(' ', _("no page content"));
638 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
642 if ($current->getVersion() == $version) {
643 $mesg->pushContent(' ', _("same version page"));
646 $rev = $page->getRevision($version);
647 $content = $rev->getPackedContent();
648 $versiondata = $rev->_data;
649 $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
650 $new = $page->save($content, $current->getVersion() + 1, $versiondata);
652 $mesg->pushContent(' ', fmt("- version %d saved to database as version %d",
653 $version, $new->getVersion()));
654 PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
659 function _tryinsertInterWikiMap($content) {
661 if (strpos($content, "<verbatim>")) {
662 //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
665 if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
666 $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
669 $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
670 if (!$goback && !file_exists($mapfile)) {
671 $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
675 if (!empty($error_html))
676 trigger_error(_("Default InterWiki map file not loaded.")
677 . $error_html, E_USER_NOTICE);
681 // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
682 echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
684 $fd = fopen ($mapfile, "rb");
685 $data = fread ($fd, filesize($mapfile));
687 $content = $content . "\n<verbatim>\n$data</verbatim>\n";
691 function ParseSerializedPage($text, $default_pagename, $user)
693 if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
696 $pagehash = unserialize($text);
698 // Split up pagehash into four parts:
701 // page-level meta-data
702 // revision-level meta-data
704 if (!defined('FLAG_PAGE_LOCKED'))
705 define('FLAG_PAGE_LOCKED', 1);
706 $pageinfo = array('pagedata' => array(),
707 'versiondata' => array());
709 $pagedata = &$pageinfo['pagedata'];
710 $versiondata = &$pageinfo['versiondata'];
713 if (empty($pagehash['pagename']))
714 $pagehash['pagename'] = $default_pagename;
715 if (empty($pagehash['author'])) {
716 $pagehash['author'] = $user->getId();
719 foreach ($pagehash as $key => $value) {
724 $pageinfo[$key] = $value;
727 $pageinfo[$key] = join("\n", $value);
730 if (($value & FLAG_PAGE_LOCKED) != 0)
731 $pagedata['locked'] = 'yes';
735 $pagedata[$key] = $value;
739 $pagedata['perm'] = ParseMimeifiedPerm($value);
742 $versiondata['mtime'] = $value;
747 $versiondata[$key] = $value;
754 function SortByPageVersion ($a, $b) {
755 return $a['version'] - $b['version'];
758 function LoadFile (&$request, $filename, $text = false, $mtime = false)
760 if (!is_string($text)) {
762 $stat = stat($filename);
764 $text = implode("", file($filename));
767 if (! $request->getArg('start_debug'))
768 @set_time_limit(30); // Reset watchdog.
770 // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
771 $basename = basename("/dummy/" . $filename);
774 $mtime = time(); // Last resort.
776 $default_pagename = rawurldecode($basename);
778 if ( ($parts = ParseMimeifiedPages($text)) ) {
779 usort($parts, 'SortByPageVersion');
780 foreach ($parts as $pageinfo)
781 SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
782 $filename), $basename);
784 else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
785 $request->getUser())) ) {
786 SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
787 $filename), $basename);
790 $user = $request->getUser();
792 // Assume plain text file.
793 $pageinfo = array('pagename' => $default_pagename,
794 'pagedata' => array(),
796 => array('author' => $user->getId()),
797 'content' => preg_replace('/[ \t\r]*\n/', "\n",
800 SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
805 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
806 $zip = new ZipReader($zipfile);
807 while (list ($fn, $data, $attrib) = $zip->readFile()) {
808 // FIXME: basename("filewithnoslashes") seems to return
809 // garbage sometimes.
810 $fn = basename("/dummy/" . $fn);
811 if ( ($files && !in_array($fn, $files))
812 || ($exclude && in_array($fn, $exclude)) ) {
813 PrintXML(HTML::dt(WikiLink($fn)),
814 HTML::dd(_("Skipping")));
818 LoadFile($request, $fn, $data, $attrib['mtime']);
822 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
823 $fileset = new LimitedFileSet($dirname, $files, $exclude);
825 if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
826 PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
828 foreach ($skiplist as $file)
829 $list->pushContent(HTML::li(WikiLink($file)));
830 PrintXML(HTML::dd($list));
833 // Defer HomePage loading until the end. If anything goes wrong
834 // the pages can still be loaded again.
835 $files = $fileset->getFiles();
836 if (in_array(HOME_PAGE, $files)) {
837 $files = array_diff($files, array(HOME_PAGE));
838 $files[] = HOME_PAGE;
840 foreach ($files as $file) {
841 if (substr($file,-1,1) != '~') // refuse to load backup files
842 LoadFile($request, "$dirname/$file");
846 class LimitedFileSet extends FileSet {
847 function LimitedFileSet($dirname, $_include, $exclude) {
848 $this->_includefiles = $_include;
849 $this->_exclude = $exclude;
850 $this->_skiplist = array();
851 parent::FileSet($dirname);
854 function _filenameSelector($fn) {
855 $incl = &$this->_includefiles;
856 $excl = &$this->_exclude;
858 if ( ($incl && !in_array($fn, $incl))
859 || ($excl && in_array($fn, $excl)) ) {
860 $this->_skiplist[] = $fn;
867 function getSkippedFiles () {
868 return $this->_skiplist;
873 function IsZipFile ($filename_or_fd)
875 // See if it looks like zip file
876 if (is_string($filename_or_fd))
878 $fd = fopen($filename_or_fd, "rb");
879 $magic = fread($fd, 4);
884 $fpos = ftell($filename_or_fd);
885 $magic = fread($filename_or_fd, 4);
886 fseek($filename_or_fd, $fpos);
889 return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
893 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
895 // Try urlencoded filename for accented characters.
896 if (!file_exists($file_or_dir)) {
897 // Make sure there are slashes first to avoid confusing phps
898 // with broken dirname or basename functions.
899 // FIXME: windows uses \ and :
900 if (is_integer(strpos($file_or_dir, "/"))) {
901 $file_or_dir = FindFile($file_or_dir);
903 if (!file_exists($file_or_dir))
904 $file_or_dir = dirname($file_or_dir) . "/"
905 . urlencode(basename($file_or_dir));
907 // This is probably just a file.
908 $file_or_dir = urlencode($file_or_dir);
912 $type = filetype($file_or_dir);
913 if ($type == 'link') {
914 // For symbolic links, use stat() to determine
915 // the type of the underlying file.
916 list(,,$mode) = stat($file_or_dir);
917 $type = ($mode >> 12) & 017;
920 elseif ($type == 004)
925 $request->finish(fmt("Unable to load: %s", $file_or_dir));
927 else if ($type == 'dir') {
928 LoadDir($request, $file_or_dir, $files, $exclude);
930 else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
932 $request->finish(fmt("Bad file type: %s", $type));
934 else if (IsZipFile($file_or_dir)) {
935 LoadZip($request, $file_or_dir, $files, $exclude);
937 else /* if (!$files || in_array(basename($file_or_dir), $files)) */
939 LoadFile($request, $file_or_dir);
943 function LoadFileOrDir (&$request)
945 $source = $request->getArg('source');
946 $finder = new FileFinder;
947 $source = $finder->slashifyPath($source);
948 $page = rawurldecode(basename($source));
949 StartLoadDump($request, fmt("Loading '%s'",
950 HTML(dirname($source),
951 dirname($source) ? "/" : "",
952 WikiLink($page,'auto'))));
954 LoadAny($request, $source);
956 EndLoadDump($request);
959 function SetupWiki (&$request)
961 global $GenericPages, $LANG;
964 //FIXME: This is a hack (err, "interim solution")
965 // This is a bogo-bogo-login: Login without
966 // saving login information in session state.
967 // This avoids logging in the unsuspecting
968 // visitor as "The PhpWiki programming team".
970 // This really needs to be cleaned up...
971 // (I'm working on it.)
972 $real_user = $request->_user;
974 $request->_user = new _BogoUser(_("The PhpWiki programming team"));
977 $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
980 StartLoadDump($request, _("Loading up virgin wiki"));
983 $pgsrc = FindLocalizedFile(WIKI_PGSRC);
984 $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
986 $request->setArg('overwrite',true);
987 if ($default_pgsrc != $pgsrc) {
988 LoadAny($request, $default_pgsrc, $GenericPages);
990 $request->setArg('overwrite',false);
991 LoadAny($request, $pgsrc);
993 // Ensure that all mandatory pages are loaded
994 $finder = new FileFinder;
995 foreach (array_merge(explode(':','OldTextFormattingRules:TextFormattingRules:PhpWikiAdministration'),
996 $GLOBALS['AllActionPages'],
997 array(constant('HOME_PAGE'))) as $f) {
999 if (isSubPage($page))
1000 $page = urlencode($page);
1001 if (! $request->_dbi->isWikiPage(urldecode($page)) ) {
1002 // translated version provided?
1003 if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $page, 1))
1004 LoadAny($request, $lf);
1005 else { // load english version of required action page
1006 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1010 if (!$request->_dbi->isWikiPage(urldecode($page))) {
1011 trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1017 EndLoadDump($request);
1020 function LoadPostFile (&$request)
1022 $upload = $request->getUploadedFile('file');
1025 $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1028 // Dump http headers.
1029 StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1032 $fd = $upload->open();
1034 LoadZip($request, $fd, false, array(_("RecentChanges")));
1036 LoadFile($request, $upload->getName(), $upload->getContents());
1039 EndLoadDump($request);
1043 $Log: not supported by cvs2svn $
1044 Revision 1.110 2004/06/21 16:22:30 rurban
1045 add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1046 fixed dumping buttons locally (images/buttons/),
1047 support pages arg for dumphtml,
1048 optional directory arg for dumpserial + dumphtml,
1049 fix a AllPages warning,
1050 show dump warnings/errors on DEBUG,
1051 don't warn just ignore on wikilens pagelist columns, if not loaded.
1052 RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1054 Revision 1.109 2004/06/17 11:31:05 rurban
1055 jump back to label after dump/upgrade
1057 Revision 1.108 2004/06/16 12:43:01 rurban
1058 4.0.6 cannot use this errorhandler (not found)
1060 Revision 1.107 2004/06/14 11:31:37 rurban
1061 renamed global $Theme to $WikiTheme (gforge nameclash)
1062 inherit PageList default options from PageList
1063 default sortby=pagename
1064 use options in PageList_Selectable (limit, sortby, ...)
1065 added action revert, with button at action=diff
1066 added option regex to WikiAdminSearchReplace
1068 Revision 1.106 2004/06/13 13:54:25 rurban
1069 Catch fatals on the four dump calls (as file and zip, as html and mimified)
1070 FoafViewer: Check against external requirements, instead of fatal.
1071 Change output for xhtmldumps: using file:// urls to the local fs.
1072 Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1073 Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1075 Revision 1.105 2004/06/08 19:48:16 rurban
1076 fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1078 Revision 1.104 2004/06/08 13:51:57 rurban
1081 Revision 1.103 2004/06/08 10:54:46 rurban
1082 better acl dump representation, read back acl and owner
1084 Revision 1.102 2004/06/06 16:58:51 rurban
1085 added more required ActionPages for foreign languages
1086 install now english ActionPages if no localized are found. (again)
1087 fixed default anon user level to be 0, instead of -1
1088 (wrong "required administrator to view this page"...)
1090 Revision 1.101 2004/06/04 20:32:53 rurban
1091 Several locale related improvements suggested by Pierrick Meignen
1092 LDAP fix by John Cole
1093 reanable admin check without ENABLE_PAGEPERM in the admin plugins
1095 Revision 1.100 2004/05/02 21:26:38 rurban
1096 limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1097 because they will not survive db sessions, if too large.
1098 extended action=upgrade
1099 some WikiTranslation button work
1100 revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1101 some temp. session debug statements
1103 Revision 1.99 2004/05/02 15:10:07 rurban
1104 new finally reliable way to detect if /index.php is called directly
1105 and if to include lib/main.php
1106 new global AllActionPages
1107 SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1108 WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1109 PageGroupTestOne => subpages
1110 renamed PhpWikiRss to PhpWikiRecentChanges
1111 more docs, default configs, ...
1113 Revision 1.98 2004/04/29 23:25:12 rurban
1114 re-ordered locale init (as in 1.3.9)
1115 fixed loadfile with subpages, and merge/restore anyway
1116 (sf.net bug #844188)
1118 Revision 1.96 2004/04/19 23:13:03 zorloc
1119 Connect the rest of PhpWiki to the IniConfig system. Also the keyword regular expression is not a config setting
1121 Revision 1.95 2004/04/18 01:11:52 rurban
1122 more numeric pagename fixes.
1123 fixed action=upload with merge conflict warnings.
1124 charset changed from constant to global (dynamic utf-8 switching)
1126 Revision 1.94 2004/03/14 16:36:37 rurban
1127 dont load backup files
1129 Revision 1.93 2004/02/26 03:22:05 rurban
1130 also copy css and images with XHTML Dump
1132 Revision 1.92 2004/02/26 02:25:54 rurban
1133 fix empty and #-anchored links in XHTML Dumps
1135 Revision 1.91 2004/02/24 17:19:37 rurban
1136 debugging helpers only
1138 Revision 1.90 2004/02/24 17:09:24 rurban
1139 fixed \r\r\n with dumping on windows
1141 Revision 1.88 2004/02/22 23:20:31 rurban
1142 fixed DumpHtmlToDir,
1143 enhanced sortby handling in PageList
1144 new button_heading th style (enabled),
1145 added sortby and limit support to the db backends and plugins
1146 for paging support (<<prev, next>> links on long lists)
1148 Revision 1.87 2004/01/26 09:17:49 rurban
1149 * changed stored pref representation as before.
1150 the array of objects is 1) bigger and 2)
1151 less portable. If we would import packed pref
1152 objects and the object definition was changed, PHP would fail.
1153 This doesn't happen with an simple array of non-default values.
1154 * use $prefs->retrieve and $prefs->store methods, where retrieve
1155 understands the interim format of array of objects also.
1156 * simplified $prefs->get() and fixed $prefs->set()
1157 * added $user->_userid and class '_WikiUser' portability functions
1158 * fixed $user object ->_level upgrading, mostly using sessions.
1159 this fixes yesterdays problems with loosing authorization level.
1160 * fixed WikiUserNew::checkPass to return the _level
1161 * fixed WikiUserNew::isSignedIn
1162 * added explodePageList to class PageList, support sortby arg
1163 * fixed UserPreferences for WikiUserNew
1164 * fixed WikiPlugin for empty defaults array
1165 * UnfoldSubpages: added pagename arg, renamed pages arg,
1166 removed sort arg, support sortby arg
1168 Revision 1.86 2003/12/02 16:18:26 carstenklapp
1169 Minor enhancement: Provide more meaningful filenames for WikiDB zip
1172 Revision 1.85 2003/11/30 18:18:13 carstenklapp
1173 Minor code optimization: use include_once instead of require_once
1174 inside functions that might not always called.
1176 Revision 1.84 2003/11/26 20:47:47 carstenklapp
1177 Redo bugfix: My last refactoring broke merge-edit & overwrite
1178 functionality again, should be fixed now. Sorry.
1180 Revision 1.83 2003/11/20 22:18:54 carstenklapp
1181 New feature: h1 during merge-edit displays WikiLink to original page.
1182 Internal changes: Replaced some hackish url-generation code in
1183 function SavePage (for pgsrc merge-edit) with appropriate Button()
1186 Revision 1.82 2003/11/18 19:48:01 carstenklapp
1187 Fixed missing gettext _() for button name.
1189 Revision 1.81 2003/11/18 18:28:35 carstenklapp
1190 Bugfix: In the Load File function of PhpWikiAdministration: When doing
1191 a "Merge Edit" or "Restore Anyway", page names containing accented
1192 letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1193 found error (Use FilenameForPage funtion to urlencode page names).
1195 Revision 1.80 2003/03/07 02:46:57 dairiki
1196 Omit checks for safe_mode before set_time_limit(). Just prefix the
1197 set_time_limit() calls with @ so that they fail silently if not
1200 Revision 1.79 2003/02/26 01:56:05 dairiki
1201 Only zip pages with legal pagenames.
1203 Revision 1.78 2003/02/24 02:05:43 dairiki
1204 Fix "n bytes written" message when dumping HTML.
1206 Revision 1.77 2003/02/21 04:12:05 dairiki
1207 Minor fixes for new cached markup.
1209 Revision 1.76 2003/02/16 19:47:17 dairiki
1210 Update WikiDB timestamp when editing or deleting pages.
1212 Revision 1.75 2003/02/15 03:04:30 dairiki
1213 Fix for WikiUser constructor API change.
1215 Revision 1.74 2003/02/15 02:18:04 dairiki
1216 When default language was English (at least), pgsrc was being
1219 LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1221 SetupWiki(): Fix bugs in loading of $GenericPages.
1223 Revision 1.73 2003/01/28 21:09:17 zorloc
1224 The get_cfg_var() function should only be used when one is
1225 interested in the value from php.ini or similar. Use ini_get()
1226 instead to get the effective value of a configuration variable.
1229 Revision 1.72 2003/01/03 22:25:53 carstenklapp
1230 Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1231 programming team" as author when loading from pgsrc. Source
1234 Revision 1.71 2003/01/03 02:48:05 carstenklapp
1235 function SavePage: Added loadfile options for overwriting or merge &
1236 compare a loaded pgsrc file with an existing page.
1238 function LoadAny: Added a general error message when unable to load a
1239 file instead of defaulting to "Bad file type".
1247 // c-basic-offset: 4
1248 // c-hanging-comment-ender-p: nil
1249 // indent-tabs-mode: nil