2 rcs_id('$Id: loadsave.php,v 1.79 2003-02-26 01:56:05 dairiki 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");
28 function StartLoadDump(&$request, $title, $html = '')
30 // FIXME: This is a hack
31 $tmpl = Template('html', array('TITLE' => $title,
33 'CONTENT' => '%BODY%'));
34 echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
37 function EndLoadDump(&$request)
39 // FIXME: This is a hack
40 $pagelink = WikiLink($request->getPage());
42 PrintXML(HTML::p(HTML::strong(_("Complete."))),
43 HTML::p(fmt("Return to %s", $pagelink)));
44 echo "</body></html>\n";
48 ////////////////////////////////////////////////////////////////
50 // Functions for dumping.
52 ////////////////////////////////////////////////////////////////
56 * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
57 * http://www.faqs.org/rfcs/rfc2045.html
58 * (RFC 1521 has been superceeded by RFC 2045 & others).
60 * Also see http://www.faqs.org/rfcs/rfc2822.html
62 function MailifyPage ($page, $nversions = 1)
64 $current = $page->getCurrentRevision();
67 if (STRICT_MAILABLE_PAGEDUMPS) {
68 $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
69 //This is for unix mailbox format: (not RFC (2)822)
70 // $head .= "From $from " . CTime(time()) . "\r\n";
71 $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
72 $head .= "From: $from (PhpWiki)\r\n";
73 // RFC 2822 requires only a Date: and originator (From:)
74 // field, however the obsolete standard RFC 822 also
75 // requires a destination field.
76 $head .= "To: $from (PhpWiki)\r\n";
78 $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
79 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
82 // This should just be entered by hand (or by script?)
83 // in the actual pgsrc files, since only they should have
85 //$head .= "X-Rcs-Id: \$Id\$\r\n";
87 $iter = $page->getAllRevisions();
89 while ($revision = $iter->next()) {
90 $parts[] = MimeifyPageRevision($revision);
91 if ($nversions > 0 && count($parts) >= $nversions)
94 if (count($parts) > 1)
95 return $head . MimeMultipart($parts);
97 return $head . $parts[0];
101 * Compute filename to used for storing contents of a wiki page.
103 * Basically we do a rawurlencode() which encodes everything except
104 * ASCII alphanumerics and '.', '-', and '_'.
106 * But we also want to encode leading dots to avoid filenames like
107 * '.', and '..'. (Also, there's no point in generating "hidden" file
108 * names, like '.foo'.)
110 * @param $pagename string Pagename.
111 * @return string Filename for page.
113 function FilenameForPage ($pagename)
115 $enc = rawurlencode($pagename);
116 return preg_replace('/^\./', '%2e', $enc);
120 * The main() function which generates a zip archive of a PhpWiki.
122 * If $include_archive is false, only the current version of each page
123 * is included in the zip file; otherwise all archived versions are
126 function MakeWikiZip (&$request)
128 if ($request->getArg('include') == 'all') {
129 $zipname = "wikidb.zip";
130 $include_archive = true;
133 $zipname = "wiki.zip";
134 $include_archive = false;
139 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
141 $dbi = $request->getDbh();
142 $pages = $dbi->getAllPages();
143 while ($page = $pages->next()) {
144 if (! ini_get('safe_mode'))
145 set_time_limit(30); // Reset watchdog.
147 $current = $page->getCurrentRevision();
148 if ($current->getVersion() == 0)
151 $wpn = new WikiPageName($page->getName());
152 if (!$wpn->isValid())
155 $attrib = array('mtime' => $current->get('mtime'),
157 if ($page->get('locked'))
158 $attrib['write_protected'] = 1;
160 if ($include_archive)
161 $content = MailifyPage($page, 0);
163 $content = MailifyPage($page);
165 $zip->addRegularFile( FilenameForPage($page->getName()),
171 function DumpToDir (&$request)
173 $directory = $request->getArg('directory');
174 if (empty($directory))
175 $request->finish(_("You must specify a directory to dump to"));
177 // see if we can access the directory the user wants us to use
178 if (! file_exists($directory)) {
179 if (! mkdir($directory, 0755))
180 $request->finish(fmt("Cannot create directory '%s'", $directory));
182 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
185 $html = HTML::p(fmt("Using directory '%s'", $directory));
188 StartLoadDump($request, _("Dumping Pages"), $html);
190 $dbi = $request->getDbh();
191 $pages = $dbi->getAllPages();
193 while ($page = $pages->next()) {
194 if (! ini_get('safe_mode'))
195 set_time_limit(30); // Reset watchdog.
197 $filename = FilenameForPage($page->getName());
199 $msg = HTML(HTML::br(), $page->getName(), ' ... ');
201 if($page->getName() != $filename) {
202 $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
206 if ($request->getArg('include') == 'all')
207 $data = MailifyPage($page, 0);
209 $data = MailifyPage($page);
211 if ( !($fd = fopen("$directory/$filename", "w")) ) {
212 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
213 "$directory/$filename")));
214 $request->finish($msg);
217 $num = fwrite($fd, $data, strlen($data));
218 $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
222 assert($num == strlen($data));
226 EndLoadDump($request);
230 function DumpHtmlToDir (&$request)
232 $directory = $request->getArg('directory');
233 if (empty($directory))
234 $request->finish(_("You must specify a directory to dump to"));
236 // see if we can access the directory the user wants us to use
237 if (! file_exists($directory)) {
238 if (! mkdir($directory, 0755))
239 $request->finish(fmt("Cannot create directory '%s'", $directory));
241 $html = HTML::p(fmt("Created directory '%s' for the page dump...",
244 $html = HTML::p(fmt("Using directory '%s'", $directory));
247 StartLoadDump($request, _("Dumping Pages"), $html);
249 $dbi = $request->getDbh();
250 $pages = $dbi->getAllPages();
252 global $HTML_DUMP_SUFFIX, $Theme;
253 if ($HTML_DUMP_SUFFIX)
254 $Theme->HTML_DUMP_SUFFIX = $HTML_DUMP_SUFFIX;
256 while ($page = $pages->next()) {
257 if (! ini_get('safe_mode'))
258 set_time_limit(30); // Reset watchdog.
260 $pagename = $page->getName();
261 $filename = FilenameForPage($pagename) . $Theme->HTML_DUMP_SUFFIX;
263 $msg = HTML(HTML::br(), $pagename, ' ... ');
265 if($page->getName() != $filename) {
266 $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
270 $revision = $page->getCurrentRevision();
272 $transformedContent = $revision->getTransformedContent();
274 $template = new Template('browse', $request,
275 array('revision' => $revision,
276 'CONTENT' => $transformedContent));
278 $data = GeneratePageasXML($template, $pagename);
280 if ( !($fd = fopen("$directory/$filename", "w")) ) {
281 $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
282 "$directory/$filename")));
283 $request->finish($msg);
286 $num = fwrite($fd, $data, strlen($data));
287 $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
291 assert($num == strlen($data));
295 //CopyImageFiles() will go here;
296 $Theme->$HTML_DUMP_SUFFIX = '';
298 EndLoadDump($request);
301 /* Known problem: any plugins or other code which echo()s text will
302 * lead to a corrupted html zip file which may produce the following
303 * errors upon unzipping:
305 * warning [wikihtml.zip]: 2401 extra bytes at beginning or within zipfile
306 * file #58: bad zipfile offset (local header sig): 177561
307 * (attempting to re-compensate)
309 * However, the actual wiki page data should be unaffected.
311 function MakeWikiZipHtml (&$request)
313 $zipname = "wikihtml.zip";
314 $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
315 $dbi = $request->getDbh();
316 $pages = $dbi->getAllPages();
318 global $HTML_DUMP_SUFFIX, $Theme;
319 if ($HTML_DUMP_SUFFIX)
320 $Theme->HTML_DUMP_SUFFIX = $HTML_DUMP_SUFFIX;
322 while ($page = $pages->next()) {
323 if (! ini_get('safe_mode'))
324 set_time_limit(30); // Reset watchdog.
326 $current = $page->getCurrentRevision();
327 if ($current->getVersion() == 0)
330 $attrib = array('mtime' => $current->get('mtime'),
332 if ($page->get('locked'))
333 $attrib['write_protected'] = 1;
335 $pagename = $page->getName();
336 $filename = FilenameForPage($pagename) . $Theme->HTML_DUMP_SUFFIX;
337 $revision = $page->getCurrentRevision();
339 $transformedContent = $revision->getTransformedContent();
341 $template = new Template('browse', $request,
342 array('revision' => $revision,
343 'CONTENT' => $transformedContent));
345 $data = GeneratePageasXML($template, $pagename);
347 $zip->addRegularFile( $filename, $data, $attrib);
349 // FIXME: Deal with images here.
351 $Theme->$HTML_DUMP_SUFFIX = '';
355 ////////////////////////////////////////////////////////////////
357 // Functions for restoring.
359 ////////////////////////////////////////////////////////////////
361 function SavePage (&$request, $pageinfo, $source, $filename)
363 $pagedata = $pageinfo['pagedata']; // Page level meta-data.
364 $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
366 if (empty($pageinfo['pagename'])) {
367 PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
371 if (empty($versiondata['author_id']))
372 $versiondata['author_id'] = $versiondata['author'];
374 $pagename = $pageinfo['pagename'];
375 $content = $pageinfo['content'];
377 if ($pagename ==_("InterWikiMap"))
378 $content = _tryinsertInterWikiMap($content);
380 $dbi = $request->getDbh();
381 $page = $dbi->getPage($pagename);
383 $current = $page->getCurrentRevision();
384 // Try to merge if updated pgsrc contents are different. This
385 // whole thing is hackish
387 // TODO: try merge unless:
388 // if (current contents = default contents && pgsrc_version >=
389 // pgsrc_version) then just upgrade this pgsrc
390 $needs_merge = false;
394 if ($request->getArg('merge')) {
397 else if ($request->getArg('overwrite')) {
401 if ( (! $current->hasDefaultContents())
402 && ($current->getPackedContent() != $content)
403 && ($merging == true) ) {
404 require_once('lib/editpage.php');
405 $request->setArg('pagename', $pagename);
406 $r = $current->getVersion();
407 $request->setArg('revision', $current->getVersion());
408 $p = new LoadFileConflictPageEditor($request);
409 $p->_content = $content;
410 $p->_currentVersion = $r - 1;
411 $p->editPage($saveFailed = true);
412 return; //early return
415 foreach ($pagedata as $key => $value) {
417 $page->set($key, $value);
423 $mesg->pushContent(' ', fmt("from %s", $source));
426 $current = $page->getCurrentRevision();
427 if ($current->getVersion() == 0) {
428 $mesg->pushContent(' ', _("new page"));
432 if ( (! $current->hasDefaultContents())
433 && ($current->getPackedContent() != $content) ) {
435 $mesg->pushContent(' ',
436 fmt("has edit conflicts - overwriting anyway"));
438 if (substr_count($source, 'pgsrc')) {
439 $versiondata['author'] = _("The PhpWiki programming team");
440 // but leave authorid as userid who loaded the file
444 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
445 $needs_merge = true; // hackish
449 else if ($current->getPackedContent() == $content
450 && $current->get('author') == $versiondata['author']) {
451 $mesg->pushContent(' ',
452 fmt("is identical to current version %d - skipped",
453 $current->getVersion()));
460 $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
462 $mesg->pushContent(' ', fmt("- saved to database as version %d",
463 $new->getVersion()));
467 // hackish, $source contains needed path+filename
468 $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
469 $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
470 $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
472 $meb = $Theme->makeButton($text = ("Merge Edit"),
473 $url = _("PhpWikiAdministration")
474 . "?action=loadfile&source=$f&merge=1",
475 $class = 'wikiadmin');
476 $owb = $Theme->makeButton($text = _("Restore Anyway"),
477 $url = _("PhpWikiAdministration")
478 . "?action=loadfile&source=$f&overwrite=1",
479 $class = 'wikiunsafe');
480 $mesg->pushContent(' ', $meb, " ", $owb);
484 PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
486 PrintXML(HTML::dt(WikiLink($pagename)), $mesg);
490 function _tryinsertInterWikiMap($content) {
492 if (strpos($content, "<verbatim>")) {
493 //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
496 if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
497 $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
500 if (!$goback && !file_exists(INTERWIKI_MAP_FILE)) {
501 $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
505 if (!empty($error_html))
506 trigger_error(_("Default InterWiki map file not loaded.")
507 . $error_html, E_USER_NOTICE);
512 $filename = INTERWIKI_MAP_FILE;
513 trigger_error(sprintf(_("Loading InterWikiMap from external file %s."),
514 $filename), E_USER_NOTICE);
516 $fd = fopen ($filename, "rb");
517 $data = fread ($fd, filesize($filename));
519 $content = $content . "\n<verbatim>\n$data</verbatim>\n";
523 function ParseSerializedPage($text, $default_pagename, $user)
525 if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
528 $pagehash = unserialize($text);
530 // Split up pagehash into four parts:
533 // page-level meta-data
534 // revision-level meta-data
536 if (!defined('FLAG_PAGE_LOCKED'))
537 define('FLAG_PAGE_LOCKED', 1);
538 $pageinfo = array('pagedata' => array(),
539 'versiondata' => array());
541 $pagedata = &$pageinfo['pagedata'];
542 $versiondata = &$pageinfo['versiondata'];
545 if (empty($pagehash['pagename']))
546 $pagehash['pagename'] = $default_pagename;
547 if (empty($pagehash['author'])) {
548 $pagehash['author'] = $user->getId();
551 foreach ($pagehash as $key => $value) {
556 $pageinfo[$key] = $value;
559 $pageinfo[$key] = join("\n", $value);
562 if (($value & FLAG_PAGE_LOCKED) != 0)
563 $pagedata['locked'] = 'yes';
566 $pagedata[$key] = $value;
569 $versiondata['mtime'] = $value;
574 $versiondata[$key] = $value;
581 function SortByPageVersion ($a, $b) {
582 return $a['version'] - $b['version'];
585 function LoadFile (&$request, $filename, $text = false, $mtime = false)
587 if (!is_string($text)) {
589 $stat = stat($filename);
591 $text = implode("", file($filename));
594 if (! ini_get('safe_mode'))
595 set_time_limit(30); // Reset watchdog.
597 // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
598 $basename = basename("/dummy/" . $filename);
601 $mtime = time(); // Last resort.
603 $default_pagename = rawurldecode($basename);
605 if ( ($parts = ParseMimeifiedPages($text)) ) {
606 usort($parts, 'SortByPageVersion');
607 foreach ($parts as $pageinfo)
608 SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
609 $filename), $basename);
611 else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
612 $request->getUser())) ) {
613 SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
614 $filename), $basename);
617 $user = $request->getUser();
619 // Assume plain text file.
620 $pageinfo = array('pagename' => $default_pagename,
621 'pagedata' => array(),
623 => array('author' => $user->getId()),
624 'content' => preg_replace('/[ \t\r]*\n/', "\n",
627 SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
632 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
633 $zip = new ZipReader($zipfile);
634 while (list ($fn, $data, $attrib) = $zip->readFile()) {
635 // FIXME: basename("filewithnoslashes") seems to return
636 // garbage sometimes.
637 $fn = basename("/dummy/" . $fn);
638 if ( ($files && !in_array($fn, $files))
639 || ($exclude && in_array($fn, $exclude)) ) {
640 PrintXML(HTML::dt(WikiLink($fn)),
641 HTML::dd(_("Skipping")));
645 LoadFile($request, $fn, $data, $attrib['mtime']);
649 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
650 $fileset = new LimitedFileSet($dirname, $files, $exclude);
652 if (($skiplist = $fileset->getSkippedFiles())) {
653 PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
655 foreach ($skiplist as $file)
656 $list->pushContent(HTML::li(WikiLink($file)));
657 PrintXML(HTML::dd($list));
660 // Defer HomePage loading until the end. If anything goes wrong
661 // the pages can still be loaded again.
662 $files = $fileset->getFiles();
663 if (in_array(HOME_PAGE, $files)) {
664 $files = array_diff($files, array(HOME_PAGE));
665 $files[] = HOME_PAGE;
667 foreach ($files as $file)
668 LoadFile($request, "$dirname/$file");
671 class LimitedFileSet extends FileSet {
672 function LimitedFileSet($dirname, $_include, $exclude) {
673 $this->_includefiles = $_include;
674 $this->_exclude = $exclude;
675 $this->_skiplist = array();
676 parent::FileSet($dirname);
679 function _filenameSelector($fn) {
680 $incl = &$this->_includefiles;
681 $excl = &$this->_exclude;
683 if ( ($incl && !in_array($fn, $incl))
684 || ($excl && in_array($fn, $excl)) ) {
685 $this->_skiplist[] = $fn;
692 function getSkippedFiles () {
693 return $this->_skiplist;
698 function IsZipFile ($filename_or_fd)
700 // See if it looks like zip file
701 if (is_string($filename_or_fd))
703 $fd = fopen($filename_or_fd, "rb");
704 $magic = fread($fd, 4);
709 $fpos = ftell($filename_or_fd);
710 $magic = fread($filename_or_fd, 4);
711 fseek($filename_or_fd, $fpos);
714 return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
718 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
720 // Try urlencoded filename for accented characters.
721 if (!file_exists($file_or_dir)) {
722 // Make sure there are slashes first to avoid confusing phps
723 // with broken dirname or basename functions.
724 // FIXME: windows uses \ and :
725 if (is_integer(strpos($file_or_dir, "/"))) {
726 $file_or_dir = FindFile($file_or_dir);
728 if (!file_exists($file_or_dir))
729 $file_or_dir = dirname($file_or_dir) . "/"
730 . urlencode(basename($file_or_dir));
732 // This is probably just a file.
733 $file_or_dir = urlencode($file_or_dir);
737 $type = filetype($file_or_dir);
738 if ($type == 'link') {
739 // For symbolic links, use stat() to determine
740 // the type of the underlying file.
741 list(,,$mode) = stat($file_or_dir);
742 $type = ($mode >> 12) & 017;
745 elseif ($type == 004)
750 $request->finish(fmt("Unable to load: %s", $file_or_dir));
752 else if ($type == 'dir') {
753 LoadDir($request, $file_or_dir, $files, $exclude);
755 else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
757 $request->finish(fmt("Bad file type: %s", $type));
759 else if (IsZipFile($file_or_dir)) {
760 LoadZip($request, $file_or_dir, $files, $exclude);
762 else /* if (!$files || in_array(basename($file_or_dir), $files)) */
764 LoadFile($request, $file_or_dir);
768 function LoadFileOrDir (&$request)
770 $source = $request->getArg('source');
771 StartLoadDump($request, sprintf(_("Loading '%s'"), $source));
773 LoadAny($request, $source);
775 EndLoadDump($request);
778 function SetupWiki (&$request)
780 global $GenericPages, $LANG;
783 //FIXME: This is a hack (err, "interim solution")
784 // This is a bogo-bogo-login: Login without
785 // saving login information in session state.
786 // This avoids logging in the unsuspecting
787 // visitor as "The PhpWiki programming team".
789 // This really needs to be cleaned up...
790 // (I'm working on it.)
791 $real_user = $request->_user;
792 $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
795 StartLoadDump($request, _("Loading up virgin wiki"));
798 $pgsrc = FindLocalizedFile(WIKI_PGSRC);
799 $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
801 if ($default_pgsrc != $pgsrc)
802 LoadAny($request, $default_pgsrc, $GenericPages);
804 LoadAny($request, $pgsrc);
807 EndLoadDump($request);
810 function LoadPostFile (&$request)
812 $upload = $request->getUploadedFile('file');
815 $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
818 // Dump http headers.
819 StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
822 $fd = $upload->open();
824 LoadZip($request, $fd, false, array(_("RecentChanges")));
826 LoadFile($request, $upload->getName(), $upload->getContents());
829 EndLoadDump($request);
833 $Log: not supported by cvs2svn $
834 Revision 1.78 2003/02/24 02:05:43 dairiki
835 Fix "n bytes written" message when dumping HTML.
837 Revision 1.77 2003/02/21 04:12:05 dairiki
838 Minor fixes for new cached markup.
840 Revision 1.76 2003/02/16 19:47:17 dairiki
841 Update WikiDB timestamp when editing or deleting pages.
843 Revision 1.75 2003/02/15 03:04:30 dairiki
844 Fix for WikiUser constructor API change.
846 Revision 1.74 2003/02/15 02:18:04 dairiki
847 When default language was English (at least), pgsrc was being
850 LimitedFileSet: Fix typo/bug. ($include was being ignored.)
852 SetupWiki(): Fix bugs in loading of $GenericPages.
854 Revision 1.73 2003/01/28 21:09:17 zorloc
855 The get_cfg_var() function should only be used when one is
856 interested in the value from php.ini or similar. Use ini_get()
857 instead to get the effective value of a configuration variable.
860 Revision 1.72 2003/01/03 22:25:53 carstenklapp
861 Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
862 programming team" as author when loading from pgsrc. Source
865 Revision 1.71 2003/01/03 02:48:05 carstenklapp
866 function SavePage: Added loadfile options for overwriting or merge &
867 compare a loaded pgsrc file with an existing page.
869 function LoadAny: Added a general error message when unable to load a
870 file instead of defaulting to "Bad file type".
879 // c-hanging-comment-ender-p: nil
880 // indent-tabs-mode: nil