3 * Copyright 1999,2000,2001,2002,2004,2005,2006,2007 $ThePhpWikiProgrammingTeam
4 * Copyright 2008-2010 Marc-Etienne Vargenau, Alcatel-Lucent
6 * This file is part of PhpWiki.
8 * PhpWiki is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * PhpWiki is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 require_once 'lib/ziplib.php';
24 require_once 'lib/Template.php';
27 * ignore fatal errors during dump
29 function _dump_error_handler($error)
31 if ($error->isFatal()) {
32 $error->errno = E_USER_WARNING;
35 return true; // Ignore error
37 if (preg_match('/Plugin/', $error->errstr))
40 // let the message come through: call the remaining handlers:
44 function StartLoadDump(&$request, $title, $html = '')
46 // MockRequest is from the unit testsuite, a faked request. (may be cmd-line)
47 // We are silent on unittests.
48 if (isa($request, 'MockRequest'))
50 // FIXME: This is a hack. This really is the worst overall hack in phpwiki.
52 $html->pushContent('%BODY%');
53 $tmpl = Template('html', array('TITLE' => $title,
55 'CONTENT' => $html ? $html : '%BODY%'));
56 echo preg_replace('/%BODY%.*/s', '', $tmpl->getExpansion($html));
57 $request->chunkOutput();
59 // set marker for sendPageChangeNotification()
60 $request->_deferredPageChangeNotification = array();
63 function EndLoadDump(&$request)
67 if (isa($request, 'MockRequest'))
69 $action = $request->getArg('action');
73 $label = _("ZIP files of database");
76 $label = _("Dump to directory");
79 $label = _("Upload File");
82 $label = _("Load File");
85 $label = _("Upgrade");
89 $label = _("Dump pages as XHTML");
92 if ($label) $label = str_replace(" ", "_", $label);
93 if ($action == 'browse') // loading virgin
94 $pagelink = WikiLink(HOME_PAGE);
96 $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"), false, $label));
98 // do deferred sendPageChangeNotification()
99 if (!empty($request->_deferredPageChangeNotification)) {
100 $pages = $all_emails = $all_users = array();
101 foreach ($request->_deferredPageChangeNotification as $p) {
102 list($pagename, $emails, $userids) = $p;
103 $pages[] = $pagename;
104 $all_emails = array_unique(array_merge($all_emails, $emails));
105 $all_users = array_unique(array_merge($all_users, $userids));
107 $editedby = sprintf(_("Edited by: %s"), $request->_user->getId());
108 $content = "Loaded the following pages:\n" . join("\n", $pages);
109 if (mail(join(',', $all_emails), "[" . WIKI_NAME . "] " . _("LoadDump"),
110 _("LoadDump") . "\n" .
114 trigger_error(sprintf(_("PageChange Notification of %s sent to %s"),
115 join("\n", $pages), join(',', $all_users)), E_USER_NOTICE);
117 trigger_error(sprintf(_("PageChange Notification Error: Couldn't send %s to %s"),
118 join("\n", $pages), join(',', $all_users)), E_USER_WARNING);
123 unset($request->_deferredPageChangeNotification);
125 PrintXML(HTML::p(HTML::strong(_("Complete."))),
126 HTML::p(fmt("Return to %s", $pagelink)));
127 // Ugly hack to get valid XHTML code
128 if (isa($WikiTheme, 'WikiTheme_fusionforge')) {
133 } elseif (isa($WikiTheme, 'WikiTheme_Sidebar')
134 or isa($WikiTheme, 'WikiTheme_MonoBook')
140 } elseif (isa($WikiTheme, 'WikiTheme_wikilens')) {
145 } elseif (isa($WikiTheme, 'WikiTheme_blog')) {
148 } elseif (isa($WikiTheme, 'WikiTheme_Crao')
149 or isa($WikiTheme, 'WikiTheme_Hawaiian')
150 or isa($WikiTheme, 'WikiTheme_MacOSX')
151 or isa($WikiTheme, 'WikiTheme_shamino_com')
152 or isa($WikiTheme, 'WikiTheme_smaller')
156 echo "</body></html>\n";
159 ////////////////////////////////////////////////////////////////
161 // Functions for dumping.
163 ////////////////////////////////////////////////////////////////
167 * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
168 * http://www.faqs.org/rfcs/rfc2045.html
169 * (RFC 1521 has been superceeded by RFC 2045 & others).
171 * Also see http://www.faqs.org/rfcs/rfc2822.html
173 function MailifyPage($page, $nversions = 1)
175 $current = $page->getCurrentRevision(false);
178 if (STRICT_MAILABLE_PAGEDUMPS) {
179 $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
180 //This is for unix mailbox format: (not RFC (2)822)
181 // $head .= "From $from " . CTime(time()) . "\r\n";
182 $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
183 $head .= "From: $from (PhpWiki)\r\n";
184 // RFC 2822 requires only a Date: and originator (From:)
185 // field, however the obsolete standard RFC 822 also
186 // requires a destination field.
187 $head .= "To: $from (PhpWiki)\r\n";
189 $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
190 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
193 $iter = $page->getAllRevisions();
195 while ($revision = $iter->next()) {
196 $parts[] = MimeifyPageRevision($page, $revision);
197 if ($nversions > 0 && count($parts) >= $nversions)
200 if (count($parts) > 1)
201 return $head . MimeMultipart($parts);
203 return $head . $parts[0];
207 * Compute filename to used for storing contents of a wiki page.
209 * Basically we do a rawurlencode() which encodes everything except
210 * ASCII alphanumerics and '.', '-', and '_'.
212 * But we also want to encode leading dots to avoid filenames like
213 * '.', and '..'. (Also, there's no point in generating "hidden" file
214 * names, like '.foo'.)
216 * We have to apply a different "/" logic for dumpserial, htmldump and zipdump.
217 * dirs are allowed for zipdump and htmldump, not for dumpserial
220 * @param $pagename string Pagename.
221 * @return string Filename for page.
223 function FilenameForPage($pagename, $action = false)
225 $enc = rawurlencode($pagename);
228 $action = $request->getArg('action');
230 if ($action != 'dumpserial') { // zip, ziphtml, dumphtml
231 // For every %2F we will need to mkdir -p dirname($pagename)
232 $enc = preg_replace('/%2F/', '/', $enc);
234 $enc = preg_replace('/^\./', '%2E', $enc);
235 $enc = preg_replace('/%20/', ' ', $enc);
236 $enc = preg_replace('/\.$/', '%2E', $enc);
241 * The main() function which generates a zip archive of a PhpWiki.
243 * If $include_archive is false, only the current version of each page
244 * is included in the zip file; otherwise all archived versions are
247 function MakeWikiZip(&$request)
249 global $ErrorManager;
250 if ($request->getArg('include') == 'all') {
251 $zipname = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
252 $include_archive = true;
254 $zipname = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
255 $include_archive = false;
257 $include_empty = false;
258 if ($request->getArg('include') == 'empty') {
259 $include_empty = true;
262 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
264 /* ignore fatals in plugins */
265 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
267 $dbi =& $request->_dbi;
268 $thispage = $request->getArg('pagename'); // for "Return to ..."
269 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
270 $excludeList = explodePageList($exclude);
272 $excludeList = array();
274 if ($pages = $request->getArg('pages')) { // which pagenames
275 if ($pages == '[]') // current page
277 $page_iter = new WikiDB_Array_PageIterator(explodePageList($pages));
279 $page_iter = $dbi->getAllPages(false, false, false, $excludeList);
281 $request_args = $request->args;
282 $timeout = (!$request->getArg('start_debug')) ? 30 : 240;
284 while ($page = $page_iter->next()) {
285 $request->args = $request_args; // some plugins might change them (esp. on POST)
286 longer_timeout($timeout); // Reset watchdog
288 $current = $page->getCurrentRevision();
289 if ($current->getVersion() == 0)
292 $pagename = $page->getName();
293 $wpn = new WikiPageName($pagename);
294 if (!$wpn->isValid())
296 if (in_array($page->getName(), $excludeList)) {
300 $attrib = array('mtime' => $current->get('mtime'),
302 if ($page->get('locked'))
303 $attrib['write_protected'] = 1;
305 if ($include_archive)
306 $content = MailifyPage($page, 0);
308 $content = MailifyPage($page);
310 $zip->addRegularFile(FilenameForPage($pagename),
315 $ErrorManager->popErrorHandler();
318 function DumpToDir(&$request)
320 $directory = $request->getArg('directory');
321 if (empty($directory))
322 $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
323 if (empty($directory))
324 $request->finish(_("You must specify a directory to dump to"));
326 // see if we can access the directory the user wants us to use
327 if (!file_exists($directory)) {
328 if (!mkdir($directory, 0755))
329 $request->finish(fmt("Cannot create directory '%s'", $directory));
331 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
334 $html = HTML::p(fmt("Using directory '%s'", $directory));
337 StartLoadDump($request, _("Dumping Pages"), $html);
339 $dbi =& $request->_dbi;
340 $thispage = $request->getArg('pagename'); // for "Return to ..."
341 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
342 $excludeList = explodePageList($exclude);
344 $excludeList = array();
346 $include_empty = false;
347 if ($request->getArg('include') == 'empty') {
348 $include_empty = true;
350 if ($pages = $request->getArg('pages')) { // which pagenames
351 if ($pages == '[]') // current page
353 $page_iter = new WikiDB_Array_PageIterator(explodePageList($pages));
355 $page_iter = $dbi->getAllPages($include_empty, false, false, $excludeList);
358 $request_args = $request->args;
359 $timeout = (!$request->getArg('start_debug')) ? 30 : 240;
361 while ($page = $page_iter->next()) {
362 $request->args = $request_args; // some plugins might change them (esp. on POST)
363 longer_timeout($timeout); // Reset watchdog
365 $pagename = $page->getName();
366 if (!isa($request, 'MockRequest')) {
367 PrintXML(HTML::br(), $pagename, ' ... ');
371 if (in_array($pagename, $excludeList)) {
372 if (!isa($request, 'MockRequest')) {
373 PrintXML(_("Skipped."));
378 $filename = FilenameForPage($pagename);
380 if ($page->getName() != $filename) {
381 $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
385 if ($request->getArg('include') == 'all')
386 $data = MailifyPage($page, 0);
388 $data = MailifyPage($page);
390 if (!($fd = fopen($directory . "/" . $filename, "wb"))) {
391 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
392 "$directory/$filename")));
393 $request->finish($msg);
396 $num = fwrite($fd, $data, strlen($data));
397 $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
398 if (!isa($request, 'MockRequest')) {
402 assert($num == strlen($data));
406 EndLoadDump($request);
409 function _copyMsg($page, $smallmsg)
411 if (!isa($GLOBALS['request'], 'MockRequest')) {
412 if ($page) $msg = HTML(HTML::br(), HTML($page), HTML::small($smallmsg));
413 else $msg = HTML::small($smallmsg);
419 function mkdir_p($pathname, $permission = 0777)
421 $arr = explode("/", $pathname);
423 return mkdir($pathname, $permission);
425 $s = array_shift($arr);
427 foreach ($arr as $p) {
430 $ok = mkdir($curr, $permission);
432 if (!$ok) return FALSE;
438 * Dump all pages as XHTML to a directory, as pagename.html.
439 * Copies all used css files to the directory, all used images to a
440 * "images" subdirectory, and all used buttons to a "images/buttons" subdirectory.
441 * The webserver must have write permissions to these directories.
442 * chown httpd HTML_DUMP_DIR; chmod u+rwx HTML_DUMP_DIR
445 * @param string directory (optional) path to dump to. Default: HTML_DUMP_DIR
446 * @param string pages (optional) Comma-seperated of glob-style pagenames to dump.
447 * Also array of pagenames allowed.
448 * @param string exclude (optional) Comma-seperated of glob-style pagenames to exclude
450 function DumpHtmlToDir(&$request)
453 $directory = $request->getArg('directory');
454 if (empty($directory))
455 $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
456 if (empty($directory))
457 $request->finish(_("You must specify a directory to dump to"));
459 // See if we can access the directory the user wants us to use
460 if (!file_exists($directory)) {
461 if (!mkdir($directory, 0755))
462 $request->finish(fmt("Cannot create directory '%s'", $directory));
464 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
467 $html = HTML::p(fmt("Using directory '%s'", $directory));
469 StartLoadDump($request, _("Dumping Pages"), $html);
470 $thispage = $request->getArg('pagename'); // for "Return to ..."
472 $dbi =& $request->_dbi;
473 if ($exclude = $request->getArg('exclude')) { // exclude which pagenames
474 $excludeList = explodePageList($exclude);
476 $excludeList = array('DebugAuthInfo', 'DebugGroupInfo', 'AuthInfo');
478 if ($pages = $request->getArg('pages')) { // which pagenames
479 if ($pages == '[]') // current page
481 $page_iter = new WikiDB_Array_generic_iter(explodePageList($pages));
482 // not at admin page: dump only the current page
483 } elseif ($thispage != _("PhpWikiAdministration")) {
484 $page_iter = new WikiDB_Array_generic_iter(array($thispage));
486 $page_iter = $dbi->getAllPages(false, false, false, $excludeList);
489 $WikiTheme->DUMP_MODE = 'HTML';
490 _DumpHtmlToDir($directory, $page_iter, $request->getArg('exclude'));
491 $WikiTheme->DUMP_MODE = false;
493 $request->setArg('pagename', $thispage); // Template::_basepage fix
494 EndLoadDump($request);
497 /* Known problem: any plugins or other code which echo()s text will
498 * lead to a corrupted html zip file which may produce the following
499 * errors upon unzipping:
501 * warning [wikihtml.zip]: 2401 extra bytes at beginning or within zipfile
502 * file #58: bad zipfile offset (local header sig): 177561
503 * (attempting to re-compensate)
505 * However, the actual wiki page data should be unaffected.
507 function MakeWikiZipHtml(&$request)
510 if ($request->getArg('zipname')) {
511 $zipname = basename($request->getArg('zipname'));
512 if (!preg_match("/\.zip$/i", $zipname))
514 $request->setArg('zipname', false);
516 $zipname = "wikihtml.zip";
518 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
519 $dbi =& $request->_dbi;
520 $thispage = $request->getArg('pagename'); // for "Return to ..."
521 if ($pages = $request->getArg('pages')) { // which pagenames
522 if ($pages == '[]') // current page
524 $page_iter = new WikiDB_Array_generic_iter(explodePageList($pages));
526 $page_iter = $dbi->getAllPages(false, false, false, $request->getArg('exclude'));
529 $WikiTheme->DUMP_MODE = 'ZIPHTML';
530 _DumpHtmlToDir($zip, $page_iter, $request->getArg('exclude'));
531 $WikiTheme->DUMP_MODE = false;
535 * Internal html dumper. Used for dumphtml, ziphtml and pdf
537 function _DumpHtmlToDir($target, $page_iter, $exclude = false)
539 global $WikiTheme, $request, $ErrorManager;
543 if ($WikiTheme->DUMP_MODE == 'HTML') {
544 $directory = $target;
546 } elseif ($WikiTheme->DUMP_MODE == 'PDFHTML') {
547 $directory = $target;
548 } elseif (is_object($target)) { // $WikiTheme->DUMP_MODE == 'ZIPHTML'
552 $request->_TemplatesProcessed = array();
553 if ($exclude) { // exclude which pagenames
554 $excludeList = explodePageList($exclude);
556 $excludeList = array('DebugAuthInfo', 'DebugGroupInfo', 'AuthInfo');
558 $WikiTheme->VALID_LINKS = array();
559 if ($request->getArg('format')) { // pagelist
560 $page_iter_sav = $page_iter;
561 foreach ($page_iter_sav->asArray() as $handle) {
562 $WikiTheme->VALID_LINKS[] = is_string($handle) ? $handle : $handle->getName();
564 $page_iter_sav->reset();
567 if (defined('HTML_DUMP_SUFFIX')) {
568 $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
570 if (isset($WikiTheme->_MoreAttr['body'])) {
571 $_bodyAttr = $WikiTheme->_MoreAttr['body'];
572 unset($WikiTheme->_MoreAttr['body']);
575 $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
577 // check if the dumped file will be accessible from outside
578 $doc_root = $request->get("DOCUMENT_ROOT");
579 if ($WikiTheme->DUMP_MODE == 'HTML') {
580 $ldir = NormalizeLocalFileName($directory);
581 $wikiroot = NormalizeLocalFileName('');
582 if (string_starts_with($ldir, $doc_root)) {
583 $link_prefix = substr($directory, strlen($doc_root)) . "/";
584 } elseif (string_starts_with($ldir, $wikiroot)) {
585 $link_prefix = NormalizeWebFileName(substr($directory, strlen($wikiroot))) . "/";
589 $prefix = '/'; // . substr($doc_root,0,2); // add drive where apache is installed
591 $link_prefix = "file://" . $prefix . $directory . "/";
597 $request_args = $request->args;
598 $timeout = (!$request->getArg('start_debug')) ? 60 : 240;
601 $directory = str_replace("\\", "/", $directory); // no Win95 support.
602 if (!is_dir("$directory/images"))
603 mkdir("$directory/images");
607 $already_images = array();
609 while ($page = $page_iter->next()) {
610 if (is_string($page)) {
612 $page = $request->_dbi->getPage($pagename);
614 $pagename = $page->getName();
616 if (empty($firstpage)) $firstpage = $pagename;
617 if (array_key_exists($pagename, $already))
619 $already[$pagename] = 1;
620 $current = $page->getCurrentRevision();
621 //if ($current->getVersion() == 0)
624 $request->args = $request_args; // some plugins might change them (esp. on POST)
625 longer_timeout($timeout); // Reset watchdog
628 $attrib = array('mtime' => $current->get('mtime'),
630 if ($page->get('locked'))
631 $attrib['write_protected'] = 1;
632 } elseif (!$silent) {
633 if (!isa($request, 'MockRequest')) {
634 PrintXML(HTML::br(), $pagename, ' ... ');
638 if (in_array($pagename, $excludeList)) {
639 if (!$silent and !isa($request, 'MockRequest')) {
640 PrintXML(_("Skipped."));
646 if ($WikiTheme->DUMP_MODE == 'PDFHTML')
647 $request->setArg('action', 'pdf'); // to omit cache headers
648 $request->setArg('pagename', $pagename); // Template::_basepage fix
649 $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
650 $args = array('revision' => $current,
651 'CONTENT' => $current->getTransformedContent(),
652 'relative_base' => $relative_base);
653 // For every %2F will need to mkdir -p dirname($pagename)
654 if (preg_match("/(%2F|\/)/", $filename)) {
655 // mkdir -p and set relative base for subdir pages
656 $filename = preg_replace("/%2F/", "/", $filename);
657 $count = substr_count($filename, "/");
658 $dirname = dirname($filename);
660 mkdir_p($directory . "/" . $dirname);
661 // Fails with "XX / YY", "XX" is created, "XX / YY" cannot be written
662 // if (isWindows()) // interesting Windows bug: cannot mkdir "bla "
663 // Since dumps needs to be copied, we have to disallow this for all platforms.
664 $filename = preg_replace("/ \//", "/", $filename);
665 $relative_base = "../";
667 $relative_base .= "../";
670 $args['relative_base'] = $relative_base;
674 $DUMP_MODE = $WikiTheme->DUMP_MODE;
675 $data = GeneratePageasXML(new Template('browse', $request, $args),
676 $pagename, $current, $args);
677 $WikiTheme->DUMP_MODE = $DUMP_MODE;
679 if (preg_match_all("/<img .*?src=\"(\/.+?)\"/", $data, $m)) {
680 // fix to local relative path for uploaded images, so that pdf will work
681 foreach ($m[1] as $img_file) {
682 $base = basename($img_file);
683 $data = str_replace('src="' . $img_file . '"', 'src="images/' . $base . '"', $data);
684 if (array_key_exists($img_file, $already_images))
686 $already_images[$img_file] = 1;
687 // resolve src from webdata to file
688 $src = $doc_root . $img_file;
689 if (file_exists($src) and $base) {
691 $target = "$directory/images/$base";
692 if (copy($src, $target)) {
694 _copyMsg($img_file, fmt("... copied to %s", $target));
697 _copyMsg($img_file, fmt("... not copied to %s", $target));
700 $target = "images/$base";
701 $zip->addSrcFile($target, $src);
708 $outfile = $directory . "/" . $filename;
709 if (!($fd = fopen($outfile, "wb"))) {
710 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
712 $request->finish($msg);
714 $len = strlen($data);
715 $num = fwrite($fd, $data, $len);
716 if ($pagename != $filename) {
717 $link = LinkURL($link_prefix . $filename, $filename);
718 $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
720 $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
722 if (!isa($request, 'MockRequest')) {
726 $request->chunkOutput();
728 assert($num == $len);
730 $outfiles[] = $outfile;
732 $zip->addRegularFile($filename, $data, $attrib);
736 $request->_dbi->_cache->invalidate_cache($pagename);
737 unset ($request->_dbi->_cache->_pagedata_cache);
738 unset ($request->_dbi->_cache->_versiondata_cache);
739 unset ($request->_dbi->_cache->_glv_cache);
741 unset ($request->_dbi->_cache->_backend->_page_data);
744 unset($current->_transformedContent);
746 if (!empty($template)) {
747 unset($template->_request);
754 $attrib = false; //array('is_ascii' => 0);
755 if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
756 // @mkdir("$directory/images");
757 foreach ($WikiTheme->dumped_images as $img_file) {
758 if (array_key_exists($img_file, $already_images))
760 $already_images[$img_file] = 1;
762 and ($from = $WikiTheme->_findFile($img_file, true))
766 $target = "$directory/images/" . basename($from);
768 copy($WikiTheme->_path . $from, $target);
770 if (copy($WikiTheme->_path . $from, $target)) {
771 _copyMsg($from, fmt("... copied to %s", $target));
773 _copyMsg($from, fmt("... not copied to %s", $target));
777 $target = "images/" . basename($from);
778 $zip->addSrcFile($target, $WikiTheme->_path . $from);
780 } elseif (!$silent) {
781 _copyMsg($from, _("... not found"));
786 if (!empty($WikiTheme->dumped_buttons)
787 and is_array($WikiTheme->dumped_buttons)
790 if ($directory && !is_dir("$directory/images/buttons"))
791 mkdir("$directory/images/buttons");
792 foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
793 if (array_key_exists($img_file, $already_images))
795 $already_images[$img_file] = 1;
797 and ($from = $WikiTheme->_findFile($img_file, true))
801 $target = "$directory/images/buttons/" . basename($from);
803 copy($WikiTheme->_path . $from, $target);
805 if (copy($WikiTheme->_path . $from, $target)) {
806 _copyMsg($from, fmt("... copied to %s", $target));
808 _copyMsg($from, fmt("... not copied to %s", $target));
812 $target = "images/buttons/" . basename($from);
813 $zip->addSrcFile($target, $WikiTheme->_path . $from);
815 } elseif (!$silent) {
816 _copyMsg($from, _("... not found"));
820 if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
821 foreach ($WikiTheme->dumped_css as $css_file) {
822 if (array_key_exists($css_file, $already_images))
824 $already_images[$css_file] = 1;
826 and ($from = $WikiTheme->_findFile(basename($css_file), true))
829 // TODO: fix @import url(main.css);
831 $target = "$directory/" . basename($css_file);
833 copy($WikiTheme->_path . $from, $target);
835 if (copy($WikiTheme->_path . $from, $target)) {
836 _copyMsg($from, fmt("... copied to %s", $target));
838 _copyMsg($from, fmt("... not copied to %s", $target));
842 //$attrib = array('is_ascii' => 0);
843 $target = basename($css_file);
844 $zip->addSrcFile($target, $WikiTheme->_path . $from);
846 } elseif (!$silent) {
847 _copyMsg($from, _("... not found"));
855 if ($WikiTheme->DUMP_MODE == 'PDFHTML') {
856 if (USE_EXTERNAL_HTML2PDF and $outfiles) {
857 $cmd = EXTERNAL_HTML2PDF_PAGELIST . ' "' . join('" "', $outfiles) . '"';
858 $filename = FilenameForPage($firstpage);
860 $tmpfile = $directory . "/createpdf.bat";
861 $fp = fopen($tmpfile, "wb");
862 fwrite($fp, $cmd . " > $filename.pdf");
865 if (!headers_sent()) {
866 Header('Content-Type: application/pdf');
869 $tmpdir = getUploadFilePath();
870 $s = passthru($cmd . " > $tmpdir/$filename.pdf");
871 $errormsg = "<br />\nGenerated <a href=\"" . getUploadDataPath() . "$filename.pdf\">Upload:$filename.pdf</a>\n";
876 foreach ($outfiles as $f) unlink($f);
879 if (!empty($errormsg)) {
880 $request->discardOutput();
881 $GLOBALS['ErrorManager']->_postponed_errors = array();
885 $ErrorManager->popErrorHandler();
887 $WikiTheme->HTML_DUMP_SUFFIX = '';
888 $WikiTheme->DUMP_MODE = false;
889 $WikiTheme->_MoreAttr['body'] = isset($_bodyAttr) ? $_bodyAttr : '';
892 ////////////////////////////////////////////////////////////////
894 // Functions for restoring.
896 ////////////////////////////////////////////////////////////////
898 function SavePage(&$request, &$pageinfo, $source, $filename)
900 static $overwite_all = false;
901 $pagedata = $pageinfo['pagedata']; // Page level meta-data.
902 $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
904 if (empty($pageinfo['pagename'])) {
905 PrintXML(HTML::p(HTML::strong(_("Empty pagename!"))));
909 if (empty($versiondata['author_id']))
910 $versiondata['author_id'] = $versiondata['author'];
912 // remove invalid backend specific chars. utf8 issues mostly
913 $pagename_check = new WikiPagename($pageinfo['pagename']);
914 if (!$pagename_check->isValid()) {
915 PrintXML(HTML::p(HTML::strong(sprintf(_("'%s': Bad page name"), $pageinfo['pagename']))));
918 $pagename = $pagename_check->getName();
919 $content = $pageinfo['content'];
921 if ($pagename == _("InterWikiMap"))
922 $content = _tryinsertInterWikiMap($content);
924 $dbi =& $request->_dbi;
925 $page = $dbi->getPage($pagename);
927 // Try to merge if updated pgsrc contents are different. This
928 // whole thing is hackish
930 // TODO: try merge unless:
931 // if (current contents = default contents && pgsrc_version >=
932 // pgsrc_version) then just upgrade this pgsrc
933 $needs_merge = false;
937 if ($request->getArg('merge')) {
939 } else if ($request->getArg('overwrite')) {
943 $current = $page->getCurrentRevision();
945 $edit = $request->getArg('edit');
947 if (isset($edit['keep_old'])) {
950 } elseif (isset($edit['overwrite'])) {
953 } elseif ($current and (!$current->hasDefaultContents())
954 && ($current->getPackedContent() != $content)
956 include_once 'lib/editpage.php';
957 $request->setArg('pagename', $pagename);
958 $v = $current->getVersion();
959 $request->setArg('revision', $current->getVersion());
960 $p = new LoadFileConflictPageEditor($request);
961 $p->_content = $content;
962 $p->_currentVersion = $v - 1;
963 $p->editPage($saveFailed = true);
964 return; //early return
968 foreach ($pagedata as $key => $value) {
970 $page->set($key, $value);
975 $mesg->pushContent(' ', fmt("from %s", $source));
978 //FIXME: This should not happen! (empty vdata, corrupt cache or db)
979 $current = $page->getCurrentRevision();
981 if ($current->getVersion() == 0) {
982 $versiondata['author'] = ADMIN_USER;
983 $versiondata['author_id'] = ADMIN_USER;
984 $mesg->pushContent(' - ', _("New page"));
987 if ((!$current->hasDefaultContents())
988 && ($current->getPackedContent() != $content)
991 $mesg->pushContent(' ',
992 fmt("has edit conflicts - overwriting anyway"));
994 if (substr_count($source, 'pgsrc')) {
995 $versiondata['author'] = ADMIN_USER;
996 // but leave authorid as userid who loaded the file
999 if (isset($edit['keep_old'])) {
1000 $mesg->pushContent(' ', fmt("keep old"));
1002 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
1003 $needs_merge = true; // hackish, to display the buttons
1007 } else if ($current->getPackedContent() == $content) {
1008 // The page content is the same, we don't need a new revision.
1009 $mesg->pushContent(' ',
1010 fmt("content is identical to current version %d - no new revision created",
1011 $current->getVersion()));
1018 // in case of failures print the culprit:
1019 if (!isa($request, 'MockRequest')) {
1020 PrintXML(HTML::p(WikiLink($pagename)));
1023 $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
1025 $mesg->pushContent(' ', fmt("- saved to database as version %d",
1026 $new->getVersion()));
1030 // hackish, $source contains needed path+filename
1031 $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
1032 $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
1033 $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
1034 //check if uploaded file? they pass just the content, but the file is gone
1037 $meb = Button(array('action' => 'loadfile',
1041 _("PhpWikiAdministration"),
1043 $owb = Button(array('action' => 'loadfile',
1044 'overwrite' => true,
1046 _("Restore Anyway"),
1047 _("PhpWikiAdministration"),
1049 $mesg->pushContent(' ', $meb, " ", $owb);
1050 if (!$overwite_all) {
1051 $args = $request->getArgs();
1052 $args['overwrite'] = 1;
1053 $owb = Button($args,
1055 _("PhpWikiAdministration"),
1057 $mesg->pushContent(HTML::span(array('class' => 'hint'), $owb));
1058 $overwite_all = true;
1061 $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
1065 if (!isa($request, 'MockRequest')) {
1067 PrintXML(HTML::p(HTML::em(WikiLink($pagename))), $mesg);
1074 // action=revert (by diff)
1075 function RevertPage(&$request)
1077 $mesg = HTML::div();
1078 $pagename = $request->getArg('pagename');
1079 $version = $request->getArg('version');
1080 $dbi =& $request->_dbi;
1081 $page = $dbi->getPage($pagename);
1083 $request->redirect(WikiURL($page,
1084 array('warningmsg' => _('Revert: missing required version argument'))));
1087 $current = $page->getCurrentRevision();
1088 $currversion = $current->getVersion();
1089 if ($currversion == 0) {
1090 $request->redirect(WikiURL($page,
1091 array('errormsg' => _('No revert: no page content'))));
1094 if ($currversion == $version) {
1095 $request->redirect(WikiURL($page,
1096 array('warningmsg' => _('No revert: same version page'))));
1099 if ($request->getArg('cancel')) {
1100 $request->redirect(WikiURL($page,
1101 array('warningmsg' => _('Revert cancelled'))));
1104 if (!$request->getArg('verify')) {
1105 $mesg->pushContent(HTML::p(fmt("Are you sure to revert %s to version $version?", WikiLink($pagename))),
1106 HTML::form(array('action' => $request->getPostURL(),
1107 'method' => 'post'),
1108 HiddenInputs($request->getArgs(), false, array('verify')),
1109 HiddenInputs(array('verify' => 1)),
1110 Button('submit:verify', _("Yes"), 'button'),
1111 HTML::Raw(' '),
1112 Button('submit:cancel', _("Cancel"), 'button'))
1114 $rev = $page->getRevision($version);
1115 $html = HTML(HTML::fieldset($mesg), HTML::hr(), $rev->getTransformedContent());
1116 $template = Template('browse',
1117 array('CONTENT' => $html));
1118 GeneratePage($template, $pagename, $rev);
1119 $request->checkValidators();
1123 $rev = $page->getRevision($version);
1124 $content = $rev->getPackedContent();
1125 $versiondata = $rev->_data;
1126 $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
1127 $versiondata['mtime'] = time();
1128 $new = $page->save($content, $currversion + 1, $versiondata);
1131 $mesg = HTML::span();
1132 $pagelink = WikiLink($pagename);
1133 $mesg->pushContent(fmt("Revert: %s", $pagelink),
1134 fmt("- version %d saved to database as version %d",
1135 $version, $new->getVersion()));
1136 // Force browse of current page version.
1137 $request->setArg('version', false);
1138 $template = Template('savepage', array());
1139 $template->replace('CONTENT', $new->getTransformedContent());
1141 GeneratePage($template, $mesg, $new);
1145 function _tryinsertInterWikiMap($content)
1148 if (strpos($content, "<verbatim>")) {
1149 //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
1152 if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
1153 $error_html = sprintf(" " . _("%s: not defined"), "INTERWIKI_MAP_FILE");
1156 $mapfile = FindFile(INTERWIKI_MAP_FILE, 1);
1157 if (!$goback && !file_exists($mapfile)) {
1158 $error_html = sprintf(" " . _("%s: file not found"), INTERWIKI_MAP_FILE);
1162 if (!empty($error_html))
1163 trigger_error(_("Default InterWiki map file not loaded.")
1164 . $error_html, E_USER_NOTICE);
1168 // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
1169 if (!isa($GLOBALS['request'], 'MockRequest'))
1170 echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile), "<br />";
1172 $fd = fopen($mapfile, "rb");
1173 $data = fread($fd, filesize($mapfile));
1175 $content = $content . "\n<verbatim>\n$data</verbatim>\n";
1179 function ParseSerializedPage($text, $default_pagename, $user)
1181 if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
1184 $pagehash = unserialize($text);
1186 // Split up pagehash into four parts:
1189 // page-level meta-data
1190 // revision-level meta-data
1192 if (!defined('FLAG_PAGE_LOCKED'))
1193 define('FLAG_PAGE_LOCKED', 1);
1194 if (!defined('FLAG_PAGE_EXTERNAL'))
1195 define('FLAG_PAGE_EXTERNAL', 1);
1196 $pageinfo = array('pagedata' => array(),
1197 'versiondata' => array());
1199 $pagedata = &$pageinfo['pagedata'];
1200 $versiondata = &$pageinfo['versiondata'];
1202 // Fill in defaults.
1203 if (empty($pagehash['pagename']))
1204 $pagehash['pagename'] = $default_pagename;
1205 if (empty($pagehash['author'])) {
1206 $pagehash['author'] = $user->getId();
1209 foreach ($pagehash as $key => $value) {
1214 $pageinfo[$key] = $value;
1217 $pageinfo[$key] = join("\n", $value);
1220 if (($value & FLAG_PAGE_LOCKED) != 0)
1221 $pagedata['locked'] = 'yes';
1222 if (($value & FLAG_PAGE_EXTERNAL) != 0)
1223 $pagedata['external'] = 'yes';
1227 $pagedata[$key] = $value;
1231 $pagedata['perm'] = ParseMimeifiedPerm($value);
1233 case 'lastmodified':
1234 $versiondata['mtime'] = $value;
1239 $versiondata[$key] = $value;
1243 if (empty($pagehash['charset']))
1244 $pagehash['charset'] = 'utf-8';
1245 // compare to target charset
1246 if (strtolower($pagehash['charset']) != strtolower($GLOBALS['charset'])) {
1247 $pageinfo['content'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['content']);
1248 $pageinfo['pagename'] = charset_convert($params['charset'], $GLOBALS['charset'], $pageinfo['pagename']);
1253 function SortByPageVersion($a, $b)
1255 return $a['version'] - $b['version'];
1259 * Security alert! We should not allow to import config.ini into our wiki (or from a sister wiki?)
1260 * because the sql passwords are in plaintext there. And the webserver must be able to read it.
1261 * Detected by Santtu Jarvi.
1263 function LoadFile(&$request, $filename, $text = false, $mtime = false)
1265 if (preg_match("/config$/", dirname($filename)) // our or other config
1266 and preg_match("/config.*\.ini/", basename($filename))
1267 ) // backups and other versions also
1269 trigger_error(sprintf("Refused to load %s", $filename), E_USER_WARNING);
1272 if (!is_string($text)) {
1274 $stat = stat($filename);
1276 $text = implode("", file($filename));
1279 if (!$request->getArg('start_debug')) @set_time_limit(30); // Reset watchdog
1280 else @set_time_limit(240);
1282 // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
1283 $basename = basename("/dummy/" . $filename);
1286 $mtime = time(); // Last resort.
1288 // DONE: check source - target charset for content and pagename
1289 // but only for pgsrc'ed content, not from the browser.
1291 $default_pagename = rawurldecode($basename);
1292 if (($parts = ParseMimeifiedPages($text))) {
1293 if (count($parts) > 1)
1294 $overwrite = $request->getArg('overwrite');
1295 usort($parts, 'SortByPageVersion');
1296 foreach ($parts as $pageinfo) {
1298 if (count($parts) > 1)
1299 $request->setArg('overwrite', 1);
1300 SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
1301 $filename), $basename);
1303 if (count($parts) > 1)
1305 $request->setArg('overwrite', $overwrite);
1307 unset($request->_args['overwrite']);
1308 } else if (($pageinfo = ParseSerializedPage($text, $default_pagename,
1309 $request->getUser()))
1311 SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
1312 $filename), $basename);
1315 $user = $request->getUser();
1317 $file_charset = 'utf-8';
1318 // compare to target charset
1319 if ($file_charset != strtolower($GLOBALS['charset'])) {
1320 $text = charset_convert($file_charset, $GLOBALS['charset'], $text);
1321 $default_pagename = charset_convert($file_charset, $GLOBALS['charset'], $default_pagename);
1324 // Assume plain text file.
1325 $pageinfo = array('pagename' => $default_pagename,
1326 'pagedata' => array(),
1328 => array('author' => $user->getId()),
1329 'content' => preg_replace('/[ \t\r]*\n/', "\n",
1332 SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
1337 function LoadZip(&$request, $zipfile, $files = false, $exclude = false)
1339 $zip = new ZipReader($zipfile);
1340 $timeout = (!$request->getArg('start_debug')) ? 20 : 120;
1341 while (list ($fn, $data, $attrib) = $zip->readFile()) {
1342 // FIXME: basename("filewithnoslashes") seems to return
1343 // garbage sometimes.
1344 $fn = basename("/dummy/" . $fn);
1345 if (($files && !in_array($fn, $files))
1346 || ($exclude && in_array($fn, $exclude))
1348 PrintXML(HTML::p(WikiLink($fn)),
1349 HTML::p(_("Skipping")));
1353 longer_timeout($timeout); // longer timeout per page
1354 LoadFile($request, $fn, $data, $attrib['mtime']);
1358 function LoadDir(&$request, $dirname, $files = false, $exclude = false)
1360 $fileset = new LimitedFileSet($dirname, $files, $exclude);
1362 if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
1363 PrintXML(HTML::p(HTML::strong(_("Skipping"))));
1365 foreach ($skiplist as $file)
1366 $list->pushContent(HTML::li(WikiLink($file)));
1367 PrintXML(HTML::p($list));
1370 // Defer HomePage loading until the end. If anything goes wrong
1371 // the pages can still be loaded again.
1372 $files = $fileset->getFiles();
1373 if (in_array(HOME_PAGE, $files)) {
1374 $files = array_diff($files, array(HOME_PAGE));
1375 $files[] = HOME_PAGE;
1377 $timeout = (!$request->getArg('start_debug')) ? 20 : 120;
1378 foreach ($files as $file) {
1379 longer_timeout($timeout); // longer timeout per page
1380 if (substr($file, -1, 1) != '~') // refuse to load backup files
1381 LoadFile($request, "$dirname/$file");
1385 class LimitedFileSet extends FileSet
1387 function LimitedFileSet($dirname, $_include, $exclude)
1389 $this->_includefiles = $_include;
1390 $this->_exclude = $exclude;
1391 $this->_skiplist = array();
1392 parent::FileSet($dirname);
1395 function _filenameSelector($fn)
1397 $incl = &$this->_includefiles;
1398 $excl = &$this->_exclude;
1400 if (($incl && !in_array($fn, $incl))
1401 || ($excl && in_array($fn, $excl))
1403 $this->_skiplist[] = $fn;
1410 function getSkippedFiles()
1412 return $this->_skiplist;
1416 function IsZipFile($filename_or_fd)
1418 // See if it looks like zip file
1419 if (is_string($filename_or_fd)) {
1420 $fd = fopen($filename_or_fd, "rb");
1421 $magic = fread($fd, 4);
1424 $fpos = ftell($filename_or_fd);
1425 $magic = fread($filename_or_fd, 4);
1426 fseek($filename_or_fd, $fpos);
1429 return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1432 function LoadAny(&$request, $file_or_dir, $files = false, $exclude = false)
1434 // Try urlencoded filename for accented characters.
1435 if (!file_exists($file_or_dir)) {
1436 // Make sure there are slashes first to avoid confusing phps
1437 // with broken dirname or basename functions.
1438 // FIXME: windows uses \ and :
1439 if (is_integer(strpos($file_or_dir, "/"))) {
1440 $newfile = FindFile($file_or_dir, true);
1441 // Panic. urlencoded by the browser (e.g. San%20Diego => San Diego)
1443 $file_or_dir = dirname($file_or_dir) . "/"
1444 . rawurlencode(basename($file_or_dir));
1446 // This is probably just a file.
1447 $file_or_dir = rawurlencode($file_or_dir);
1451 $type = filetype($file_or_dir);
1452 if ($type == 'link') {
1453 // For symbolic links, use stat() to determine
1454 // the type of the underlying file.
1455 list(, , $mode) = stat($file_or_dir);
1456 $type = ($mode >> 12) & 017;
1459 elseif ($type == 004)
1464 $request->finish(fmt("Empty or not existing source. Unable to load: %s", $file_or_dir));
1465 } else if ($type == 'dir') {
1466 LoadDir($request, $file_or_dir, $files, $exclude);
1467 } else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir)) {
1468 $request->finish(fmt("Bad file type: %s", $type));
1469 } else if (IsZipFile($file_or_dir)) {
1470 LoadZip($request, $file_or_dir, $files, $exclude);
1471 } else /* if (!$files || in_array(basename($file_or_dir), $files)) */ {
1472 LoadFile($request, $file_or_dir);
1476 function LoadFileOrDir(&$request)
1478 $source = $request->getArg('source');
1479 $finder = new FileFinder;
1480 $source = $finder->slashifyPath($source);
1481 StartLoadDump($request,
1482 sprintf(_("Loading '%s'"), $source));
1483 LoadAny($request, $source);
1484 EndLoadDump($request);
1488 * HomePage was not found so first-time install is supposed to run.
1489 * - import all pgsrc pages.
1490 * - Todo: installer interface to edit config/config.ini settings
1491 * - Todo: ask for existing old index.php to convert to config/config.ini
1492 * - Todo: theme-specific pages:
1493 * blog - HomePage, ADMIN_USER/Blogs
1495 function SetupWiki(&$request)
1497 global $GenericPages, $LANG;
1499 //FIXME: This is a hack (err, "interim solution")
1500 // This is a bogo-bogo-login: Login without
1501 // saving login information in session state.
1502 // This avoids logging in the unsuspecting
1503 // visitor as ADMIN_USER
1505 // This really needs to be cleaned up...
1506 // (I'm working on it.)
1507 $real_user = $request->_user;
1508 if (ENABLE_USER_NEW)
1509 $request->_user = new _BogoUser(ADMIN_USER);
1512 $request->_user = new WikiUser($request, ADMIN_USER, WIKIAUTH_BOGO);
1514 StartLoadDump($request, _("Loading up virgin wiki"));
1516 $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1517 $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1519 $request->setArg('overwrite', true);
1520 if ($default_pgsrc != $pgsrc) {
1521 LoadAny($request, $default_pgsrc, $GenericPages);
1523 $request->setArg('overwrite', false);
1524 LoadAny($request, $pgsrc);
1525 $dbi =& $request->_dbi;
1527 // Ensure that all mandatory pages are loaded
1528 $finder = new FileFinder;
1531 $mandatory = explode(':', 'SandBox:Template/Category:Template/Talk:SpecialPages:CategoryCategory:CategoryActionPage:Help/OldTextFormattingRules:Help/TextFormattingRules:PhpWikiAdministration');
1532 } elseif (WIKI_NAME == "help") {
1533 $mandatory = explode(':', 'SandBox:Template/Category:Template/Talk:SpecialPages:CategoryCategory:CategoryActionPage:Help/TextFormattingRules:PhpWikiAdministration');
1535 $mandatory = explode(':', 'SandBox:Template/UserPage:Template/Category:Template/Talk:SpecialPages:CategoryCategory:CategoryActionPage:TextFormattingRules:PhpWikiAdministration');
1537 foreach (array_merge($mandatory,
1538 $GLOBALS['AllActionPages'],
1539 array(constant('HOME_PAGE'))) as $f) {
1540 $page = gettext($f);
1541 $epage = urlencode($page);
1542 if (!$dbi->isWikiPage($page)) {
1543 // translated version provided?
1544 if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $epage, 1)) {
1545 LoadAny($request, $lf);
1546 } else { // load english version of required action page
1547 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1551 if (!$dbi->isWikiPage($page)) {
1552 trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1557 $pagename = _("InterWikiMap");
1558 $map = $dbi->getPage($pagename);
1559 $map->set('locked', true);
1560 PrintXML(HTML::p(HTML::em(WikiLink($pagename)), HTML::strong(" locked")));
1561 EndLoadDump($request);
1564 function LoadPostFile(&$request)
1566 $upload = $request->getUploadedFile('file');
1569 $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1571 // Dump http headers.
1572 StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1574 $fd = $upload->open();
1576 LoadZip($request, $fd, false, array(_("RecentChanges")));
1578 LoadFile($request, $upload->getName(), $upload->getContents());
1580 EndLoadDump($request);
1586 // c-basic-offset: 4
1587 // c-hanging-comment-ender-p: nil
1588 // indent-tabs-mode: nil