1 <?php rcs_id('$Id: loadsave.php,v 1.36 2002-01-24 21:22:59 dairiki Exp $');
3 require_once("lib/ziplib.php");
4 require_once("lib/Template.php");
6 function StartLoadDump(&$request, $title, $html = '')
8 // FIXME: This is a hack
9 $tmpl = Template('top', array('TITLE' => $title, 'HEADER' => $title));
10 echo ereg_replace('</body>.*', '', $tmpl->getExpansion($html));
13 function EndLoadDump(&$request)
15 // FIXME: This is a hack
17 $pagelink = $Theme->LinkExistingWikiWord($request->getArg('pagename'));
19 PrintXML(array(HTML::p(HTML::strong(_("Complete."))),
20 HTML::p(fmt("Return to %s", $pagelink))));
21 echo "</body></html>\n";
25 ////////////////////////////////////////////////////////////////
27 // Functions for dumping.
29 ////////////////////////////////////////////////////////////////
31 function MailifyPage ($page, $nversions = 1)
33 global $SERVER_ADMIN, $pagedump_format;
35 $current = $page->getCurrentRevision();
36 $from = isset($SERVER_ADMIN) ? $SERVER_ADMIN : 'foo@bar';
38 if ($pagedump_format == 'quoted-printable') {
39 $head = "From $from " . CTime(time()) . "\r\n";
40 $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
41 $head .= "From: $from (PhpWiki)\r\n";
42 $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
43 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
46 $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
47 PHPWIKI_VERSION."+carsten's-binary-hack");
49 $head .= "X-RCS_ID: $" ."Id" ."$" ."\r\n";
51 $iter = $page->getAllRevisions();
53 while ($revision = $iter->next()) {
54 $parts[] = MimeifyPageRevision($revision);
55 if ($nversions > 0 && count($parts) >= $nversions)
58 if (count($parts) > 1)
59 return $head . MimeMultipart($parts);
61 return $head . $parts[0];
65 * Compute filename to used for storing contents of a wiki page.
67 * Basically we do a rawurlencode() which encodes everything except
68 * ASCII alphanumerics and '.', '-', and '_'.
70 * But we also want to encode leading dots to avoid filenames like
71 * '.', and '..'. (Also, there's no point in generating "hidden" file
72 * names, like '.foo'.)
74 * @param $pagename string Pagename.
75 * @return string Filename for page.
77 function FilenameForPage ($pagename)
79 $enc = rawurlencode($pagename);
80 return preg_replace('/^\./', '%2e', $enc);
84 * The main() function which generates a zip archive of a PhpWiki.
86 * If $include_archive is false, only the current version of each page
87 * is included in the zip file; otherwise all archived versions are
90 function MakeWikiZip (&$request)
92 if ($request->getArg('include') == 'all') {
93 $zipname = "wikidb.zip";
94 $include_archive = true;
97 $zipname = "wiki.zip";
98 $include_archive = false;
103 $zip = new ZipWriter("Created by PhpWiki", $zipname);
105 $dbi = $request->getDbh();
106 $pages = $dbi->getAllPages();
107 while ($page = $pages->next()) {
108 set_time_limit(30); // Reset watchdog.
110 $current = $page->getCurrentRevision();
111 if ($current->getVersion() == 0)
115 $attrib = array('mtime' => $current->get('mtime'),
117 if ($page->get('locked'))
118 $attrib['write_protected'] = 1;
120 if ($include_archive)
121 $content = MailifyPage($page, 0);
123 $content = MailifyPage($page);
125 $zip->addRegularFile( FilenameForPage($page->getName()),
131 function DumpToDir (&$request)
133 global $pagedump_format;
134 $directory = $request->getArg('directory');
135 if (empty($directory))
136 $request->finish(_("You must specify a directory to dump to"));
138 // see if we can access the directory the user wants us to use
139 if (! file_exists($directory)) {
140 if (! mkdir($directory, 0755))
141 $request->finish(fmt("Cannot create directory '%s'", $directory));
143 $html = sprintf(_("Created directory '%s' for the page dump..."),
144 $directory) . "<br />\n";
146 $html = sprintf(_("Using directory '%s'"),$directory) . "<br />\n";
149 $html .= "MIME " . $pagedump_format . "<br />\n";
150 StartLoadDump($request, _("Dumping Pages"), $html);
152 $dbi = $request->getDbh();
153 $pages = $dbi->getAllPages();
155 while ($page = $pages->next()) {
157 $filename = FilenameForPage($page->getName());
159 $msg = array(HTML::br(), $page->getName(), ' ... ');
161 if($page->getName() != $filename) {
162 $msg[] = HTTP::small(fmt("saved as %s", $filename));
166 $data = MailifyPage($page);
168 if ( !($fd = fopen("$directory/$filename", "w")) ) {
169 $msg[] = HTML::strong(fmt("couldn't open file '%s' for writing",
170 "$directory/$filename"));
171 $request->finish($msg);
174 $num = fwrite($fd, $data, strlen($data));
175 $msg[] = HTML::small(fmt("%s bytes written", $num));
179 assert($num == strlen($data));
183 EndLoadDump($request);
186 ////////////////////////////////////////////////////////////////
188 // Functions for restoring.
190 ////////////////////////////////////////////////////////////////
192 function SavePage (&$request, $pageinfo, $source, $filename)
194 $pagedata = $pageinfo['pagedata']; // Page level meta-data.
195 $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
197 if (empty($pageinfo['pagename'])) {
198 PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
202 if (empty($versiondata['author_id']))
203 $versiondata['author_id'] = $versiondata['author'];
205 $pagename = $pageinfo['pagename'];
206 $content = $pageinfo['content'];
208 $dbi = $request->getDbh();
209 $page = $dbi->getPage($pagename);
211 foreach ($pagedata as $key => $value) {
213 $page->set($key, $value);
219 $mesg->pushContent(' ', fmt("from %s", $source));
222 $current = $page->getCurrentRevision();
223 if ($current->getVersion() == 0) {
224 $mesg->pushContent(' ', _("new page"));
228 if ($current->getPackedContent() == $content
229 && $current->get('author') == $versiondata['author']) {
230 $mesg->pushContent(' ',
231 fmt("is identical to current version %d - skipped",
232 $current->getVersion()));
239 $new = $page->createRevision(WIKIDB_FORCE_CREATE, $content,
241 ExtractWikiPageLinks($content));
243 $mesg->pushContent(' ', fmt("- saved to database as version %d",
244 $new->getVersion()));
248 $pagelink = $Theme->LinkExistingWikiWord($pagename);
250 PrintXML(array(HTML::dt($pagelink), $mesg));
254 function ParseSerializedPage($text, $default_pagename, $user)
256 if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
259 $pagehash = unserialize($text);
261 // Split up pagehash into four parts:
264 // page-level meta-data
265 // revision-level meta-data
267 if (!defined('FLAG_PAGE_LOCKED'))
268 define('FLAG_PAGE_LOCKED', 1);
269 $pageinfo = array('pagedata' => array(),
270 'versiondata' => array());
272 $pagedata = &$pageinfo['pagedata'];
273 $versiondata = &$pageinfo['versiondata'];
276 if (empty($pagehash['pagename']))
277 $pagehash['pagename'] = $default_pagename;
278 if (empty($pagehash['author'])) {
279 $pagehash['author'] = $user->getId();
282 foreach ($pagehash as $key => $value) {
286 $pageinfo[$key] = $value;
289 $pageinfo[$key] = join("\n", $value);
291 if (($value & FLAG_PAGE_LOCKED) != 0)
292 $pagedata['locked'] = 'yes';
295 $pagedata[$key] = $value;
298 $versiondata['mtime'] = $value;
301 $versiondata[$key] = $value;
308 function SortByPageVersion ($a, $b) {
309 return $a['version'] - $b['version'];
312 function LoadFile (&$request, $filename, $text = false, $mtime = false)
314 if (!is_string($text)) {
316 $stat = stat($filename);
318 $text = implode("", file($filename));
321 set_time_limit(30); // Reset watchdog.
323 // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
324 $basename = basename("/dummy/" . $filename);
327 $mtime = time(); // Last resort.
329 $default_pagename = rawurldecode($basename);
331 if ( ($parts = ParseMimeifiedPages($text)) ) {
332 usort($parts, 'SortByPageVersion');
333 foreach ($parts as $pageinfo)
334 SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
335 $filename), $basename);
337 else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
338 $request->getUser())) ) {
339 SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
340 $filename), $basename);
344 $user = $request->getUser();
346 // Assume plain text file.
347 $pageinfo = array('pagename' => $default_pagename,
348 'pagedata' => array(),
350 => array('author' => $user->getId()),
351 'content' => preg_replace('/[ \t\r]*\n/', "\n",
354 SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
359 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
360 $zip = new ZipReader($zipfile);
362 while (list ($fn, $data, $attrib) = $zip->readFile()) {
363 // FIXME: basename("filewithnoslashes") seems to return
364 // garbage sometimes.
365 $fn = basename("/dummy/" . $fn);
366 if ( ($files && !in_array($fn, $files)) || ($exclude && in_array($fn, $exclude)) ) {
368 PrintXML(array(HTML::dt($Theme->LinkExistingWikiWord($fn)),
369 HTML::dd(_("Skipping"))));
374 LoadFile($request, $fn, $data, $attrib['mtime']);
378 function LoadDir (&$request, $dirname, $files = false, $exclude = false)
380 $handle = opendir($dir = $dirname);
382 while ($fn = readdir($handle)) {
383 if ($fn[0] == '.' || filetype("$dir/$fn") != 'file')
386 if ( ($files && !in_array($fn, $files)) || ($exclude && in_array($fn, $exclude)) ) {
388 PrintXML(array(HTML::dt($Theme->LinkExistingWikiWord($fn)),
389 HTML::dd(_("Skipping"))));
393 LoadFile($request, "$dir/$fn");
398 function IsZipFile ($filename_or_fd)
400 // See if it looks like zip file
401 if (is_string($filename_or_fd))
403 $fd = fopen($filename_or_fd, "rb");
404 $magic = fread($fd, 4);
409 $fpos = ftell($filename_or_fd);
410 $magic = fread($filename_or_fd, 4);
411 fseek($filename_or_fd, $fpos);
414 return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
418 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
420 $type = filetype($file_or_dir);
421 if ($type == 'link') {
422 // For symbolic links, use stat() to determine
423 // the type of the underlying file.
424 list(,,$mode) = stat($file_or_dir);
425 $type = ($mode >> 12) & 017;
428 elseif ($type == 004)
432 if ($type == 'dir') {
433 LoadDir($request, $file_or_dir, $files, $exclude);
435 else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
437 $request->finish(fmt("Bad file type: %s", $type));
439 else if (IsZipFile($file_or_dir)) {
440 LoadZip($request, $file_or_dir, $files, $exclude);
442 else /* if (!$files || in_array(basename($file_or_dir), $files)) */
444 LoadFile($request, $file_or_dir);
448 function LoadFileOrDir (&$request)
450 $source = $request->getArg('source');
451 StartLoadDump($request, sprintf(_("Loading '%s'"), $source));
453 LoadAny($request->getDbh(), $source/*, false, array(_("RecentChanges"))*/);
455 EndLoadDump($request);
458 function SetupWiki (&$request)
460 global $GenericPages, $LANG;
463 //FIXME: This is a hack (err, "interim solution")
464 // This is a bogo-bogo-login: Login without
465 // saving login information in session state.
466 // This avoids logging in the unsuspecting
467 // visitor as "The PhpWiki programming team".
469 // This really needs to be cleaned up...
470 // (I'm working on it.)
471 $real_user = $request->_user;
472 $request->_user = new WikiUser(_("The PhpWiki programming team"),
475 StartLoadDump($request, _("Loading up virgin wiki"));
478 LoadAny($request, FindLocalizedFile(WIKI_PGSRC)/*, false, $ignore*/);
480 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC),
481 $GenericPages/*, $ignore*/);
484 EndLoadDump($request);
487 function LoadPostFile (&$request)
489 $upload = $request->getUploadedFile('file');
492 $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
495 // Dump http headers.
496 StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
499 $fd = $upload->open();
501 LoadZip($request->getDbh(), $fd, false, array(_("RecentChanges")));
503 Loadfile($request->getDbh(), $upload->getName(), $upload->getContents());
506 EndLoadDump($request);
514 // c-hanging-comment-ender-p: nil
515 // indent-tabs-mode: nil