]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
Refactor/cleanup of login code continues.
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php
2 rcs_id('$Id: loadsave.php,v 1.31 2002-01-23 05:10:22 dairiki Exp $');
3 require_once("lib/ziplib.php");
4 require_once("lib/Template.php");
5
6 function StartLoadDump($title, $html = '')
7 {
8     // FIXME: This is a hack
9     echo ereg_replace('</body>.*', '',
10                       GeneratePage('MESSAGE', $html, $title, 0));
11 }
12
13 function EndLoadDump(&$request)
14 {
15     // FIXME: This is a hack
16     $pagelink = LinkExistingWikiWord($request->getArg('pagename'));
17     
18     PrintXML(array(HTML::p(HTML::strong(_("Complete."))),
19                    HTML::p(fmt("Return to %s", $pagelink))));
20     echo "</body></html>\n";
21 }
22
23
24 ////////////////////////////////////////////////////////////////
25 //
26 //  Functions for dumping.
27 //
28 ////////////////////////////////////////////////////////////////
29
30 function MailifyPage ($page, $nversions = 1)
31 {
32     global $SERVER_ADMIN, $pagedump_format;
33     
34     $current = $page->getCurrentRevision();
35     $from = isset($SERVER_ADMIN) ? $SERVER_ADMIN : 'foo@bar';
36     $head = "";
37     if ($pagedump_format == 'quoted-printable') {
38         $head = "From $from  " . CTime(time()) . "\r\n";
39         $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
40         $head .= "From: $from (PhpWiki)\r\n";
41         $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
42         $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
43                          PHPWIKI_VERSION);
44     } else {
45         $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
46                          PHPWIKI_VERSION."+carsten's-binary-hack");
47     }
48     $head .= "X-RCS_ID: $" ."Id" ."$" ."\r\n";
49     
50     $iter = $page->getAllRevisions();
51     $parts = array();
52     while ($revision = $iter->next()) {
53         $parts[] = MimeifyPageRevision($revision);
54         if ($nversions > 0 && count($parts) >= $nversions)
55             break;
56     }
57     if (count($parts) > 1)
58         return $head . MimeMultipart($parts);
59     assert($parts);
60     return $head . $parts[0];
61 }
62
63 /***
64  * Compute filename to used for storing contents of a wiki page.
65  *
66  * Basically we do a rawurlencode() which encodes everything except
67  * ASCII alphanumerics and '.', '-', and '_'.
68  *
69  * But we also want to encode leading dots to avoid filenames like
70  * '.', and '..'. (Also, there's no point in generating "hidden" file
71  * names, like '.foo'.)
72  *
73  * @param $pagename string Pagename.
74  * @return string Filename for page.
75  */
76 function FilenameForPage ($pagename)
77 {
78     $enc = rawurlencode($pagename);
79     return preg_replace('/^\./', '%2e', $enc);
80 }
81
82 /**
83  * The main() function which generates a zip archive of a PhpWiki.
84  *
85  * If $include_archive is false, only the current version of each page
86  * is included in the zip file; otherwise all archived versions are
87  * included as well.
88  */
89 function MakeWikiZip (&$request)
90 {
91     if ($request->getArg('include') == 'all') {
92         $zipname         = "wikidb.zip";
93         $include_archive = true;
94     }
95     else {
96         $zipname         = "wiki.zip";
97         $include_archive = false;
98     }
99     
100     
101
102     $zip = new ZipWriter("Created by PhpWiki", $zipname);
103
104     $dbi = $request->getDbh();
105     $pages = $dbi->getAllPages();
106     while ($page = $pages->next()) {
107         set_time_limit(30);     // Reset watchdog.
108         
109         $current = $page->getCurrentRevision();
110         if ($current->getVersion() == 0)
111             continue;
112         
113         
114         $attrib = array('mtime'    => $current->get('mtime'),
115                         'is_ascii' => 1);
116         if ($page->get('locked'))
117             $attrib['write_protected'] = 1;
118         
119         if ($include_archive)
120             $content = MailifyPage($page, 0);
121         else
122             $content = MailifyPage($page);
123         
124         $zip->addRegularFile( FilenameForPage($page->getName()),
125                               $content, $attrib);
126     }
127     $zip->finish();
128 }
129
130 function DumpToDir (&$request) 
131 {
132     global $pagedump_format;
133     $directory = $request->getArg('directory');
134     if (empty($directory))
135         $request->finish(_("You must specify a directory to dump to"));
136     
137     // see if we can access the directory the user wants us to use
138     if (! file_exists($directory)) {
139         if (! mkdir($directory, 0755))
140             $request->finish(fmt("Cannot create directory '%s'", $directory));
141         else
142             $html = sprintf(_("Created directory '%s' for the page dump..."),
143                             $directory) . "<br />\n";
144     } else {
145         $html = sprintf(_("Using directory '%s'"),$directory) . "<br />\n";
146     }
147
148     $html .= "MIME " . $pagedump_format . "<br />\n";
149     StartLoadDump( _("Dumping Pages"), $html);
150
151     $dbi = $request->getDbh();
152     $pages = $dbi->getAllPages();
153     
154     while ($page = $pages->next()) {
155         
156         $filename = FilenameForPage($page->getName());
157         
158         $msg = array(HTML::br(), $page->getName(), ' ... ');
159         
160         if($page->getName() != $filename) {
161             $msg[] = HTTP::small(fmt("saved as %s", $filename));
162             $msg[] = " ... ";
163         }
164         
165         $data = MailifyPage($page);
166         
167         if ( !($fd = fopen("$directory/$filename", "w")) ) {
168             $msg[] = HTML::strong(fmt("couldn't open file '%s' for writing",
169                                       "$directory/$filename"));
170             $request->finish($msg);
171         }
172         
173         $num = fwrite($fd, $data, strlen($data));
174         $msg[] = HTML::small(fmt("%s bytes written", $num));
175         PrintXML($msg);
176         
177         flush();
178         assert($num == strlen($data));
179         fclose($fd);
180     }
181     
182     EndLoadDump($request);
183 }
184
185 ////////////////////////////////////////////////////////////////
186 //
187 //  Functions for restoring.
188 //
189 ////////////////////////////////////////////////////////////////
190
191 function SavePage (&$request, $pageinfo, $source, $filename)
192 {
193     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
194     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
195     
196     if (empty($pageinfo['pagename'])) {
197         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
198         return;
199     }
200     
201     if (empty($versiondata['author_id']))
202         $versiondata['author_id'] = $versiondata['author'];
203     
204     $pagename = $pageinfo['pagename'];
205     $content  = $pageinfo['content'];
206
207     $dbi = $request->getDbh();
208     $page = $dbi->getPage($pagename);
209     
210     foreach ($pagedata as $key => $value) {
211         if (!empty($value))
212             $page->set($key, $value);
213     }
214     
215     $mesg = HTML::dd();
216     $skip = false;
217     if ($source)
218         $mesg->pushContent(' ', fmt("from %s", $source));
219     
220
221     $current = $page->getCurrentRevision();
222     if ($current->getVersion() == 0) {
223         $mesg->pushContent(' ', _("new page"));
224         $isnew = true;
225     }
226     else {
227         if ($current->getPackedContent() == $content
228             && $current->get('author') == $versiondata['author']) {
229             $mesg->pushContent(' ',
230                                fmt("is identical to current version %d - skipped",
231                                    $current->getVersion()));
232             $skip = true;
233         }
234         $isnew = false;
235     }
236     
237     if (! $skip) {
238         $new = $page->createRevision(WIKIDB_FORCE_CREATE, $content,
239                                      $versiondata,
240                                      ExtractWikiPageLinks($content));
241         
242         $mesg->pushContent(' ', fmt("- saved to database as version %d",
243                                     $new->getVersion()));
244     }
245
246     $pagelink = LinkExistingWikiWord($pagename);
247     
248     PrintXML(array(HTML::dt($pagelink), $mesg));
249     flush();
250 }
251
252 function ParseSerializedPage($text, $default_pagename, $user)
253 {
254     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
255         return false;
256     
257     $pagehash = unserialize($text);
258     
259     // Split up pagehash into four parts:
260     //   pagename
261     //   content
262     //   page-level meta-data
263     //   revision-level meta-data
264     
265     if (!defined('FLAG_PAGE_LOCKED'))
266         define('FLAG_PAGE_LOCKED', 1);
267     $pageinfo = array('pagedata'    => array(),
268                       'versiondata' => array());
269     
270     $pagedata = &$pageinfo['pagedata'];
271     $versiondata = &$pageinfo['versiondata'];
272     
273     // Fill in defaults.
274     if (empty($pagehash['pagename']))
275         $pagehash['pagename'] = $default_pagename;
276     if (empty($pagehash['author'])) {
277         $pagehash['author'] = $user->getId();
278     }
279     
280     foreach ($pagehash as $key => $value) {
281         switch($key) {
282         case 'pagename':
283         case 'version':
284             $pageinfo[$key] = $value;
285             break;
286         case 'content':
287             $pageinfo[$key] = join("\n", $value);
288         case 'flags':
289             if (($value & FLAG_PAGE_LOCKED) != 0)
290                 $pagedata['locked'] = 'yes';
291             break;
292         case 'created':
293             $pagedata[$key] = $value;
294             break;
295         case 'lastmodified':
296             $versiondata['mtime'] = $value;
297             break;
298         case 'author':
299             $versiondata[$key] = $value;
300             break;
301         }
302     }
303     return $pageinfo;
304 }
305  
306 function SortByPageVersion ($a, $b) {
307     return $a['version'] - $b['version'];
308 }
309
310 function LoadFile (&$request, $filename, $text = false, $mtime = false)
311 {
312     if (!is_string($text)) {
313         // Read the file.
314         $stat  = stat($filename);
315         $mtime = $stat[9];
316         $text  = implode("", file($filename));
317     }
318    
319     set_time_limit(30); // Reset watchdog.
320     
321     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
322     $basename = basename("/dummy/" . $filename);
323    
324     if (!$mtime)
325         $mtime = time();        // Last resort.
326     
327     $default_pagename = rawurldecode($basename);
328     
329     if ( ($parts = ParseMimeifiedPages($text)) ) {
330         usort($parts, 'SortByPageVersion');
331         foreach ($parts as $pageinfo)
332             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),$filename),
333                      $basename);
334     }
335     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename, $request->getUser())) ) {
336         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),$filename),
337                  $basename);
338     }
339     else {
340         //FIXME:?
341         $user = $request->getUser();
342         
343         // Assume plain text file.
344         $pageinfo = array('pagename' => $default_pagename,
345                           'pagedata' => array(),
346                           'versiondata'
347                           => array('author' => $user->getId()),
348                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
349                                                      chop($text))
350                           );
351         SavePage($request, $pageinfo, sprintf(_("plain file %s"),$filename),
352                  $basename);
353     }
354 }
355
356 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
357     $zip = new ZipReader($zipfile);
358     while (list ($fn, $data, $attrib) = $zip->readFile()) {
359         // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
360         $fn = basename("/dummy/" . $fn);
361         if ( ($files && !in_array($fn, $files)) || ($exclude && in_array($fn, $exclude)) ) {
362
363             PrintXML(array(HTML::dt(LinkExistingWikiWord($fn)),
364                            HTML::dd(_("Skipping"))));
365            
366             continue;
367         }
368        
369         LoadFile($request, $fn, $data, $attrib['mtime']);
370     }
371 }
372
373 function LoadDir (&$request, $dirname, $files = false, $exclude = false)
374 {
375     $handle = opendir($dir = $dirname);
376     while ($fn = readdir($handle)) {
377         if ($fn[0] == '.' || filetype("$dir/$fn") != 'file')
378             continue;
379             
380         if ( ($files && !in_array($fn, $files)) || ($exclude && in_array($fn, $exclude)) ) {
381
382             PrintXML(array(HTML::dt(LinkExistingWikiWord($fn)),
383                            HTML::dd(_("Skipping"))));
384             continue;
385         }
386             
387         LoadFile($request, "$dir/$fn");
388     }
389     closedir($handle);
390 }
391
392 function IsZipFile ($filename_or_fd)
393 {
394     // See if it looks like zip file
395     if (is_string($filename_or_fd))
396         {
397             $fd    = fopen($filename_or_fd, "rb");
398             $magic = fread($fd, 4);
399             fclose($fd);
400         }
401     else
402         {
403             $fpos  = ftell($filename_or_fd);
404             $magic = fread($filename_or_fd, 4);
405             fseek($filename_or_fd, $fpos);
406         }
407     
408     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
409 }
410
411
412 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
413 {
414     $type = filetype($file_or_dir);
415     if ($type == 'link') {
416         // For symbolic links, use stat() to determine
417         // the type of the underlying file.
418         list(,,$mode) = stat($file_or_dir);
419         $type = ($mode >> 12) & 017;
420         if ($type == 010)
421             $type = 'file';
422         elseif ($type == 004)
423             $type = 'dir';
424     }
425     
426     if ($type == 'dir') {
427         LoadDir($request, $file_or_dir, $files, $exclude);
428     }
429     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
430     {
431         $request->finish(fmt("Bad file type: %s", $type));
432     }
433     else if (IsZipFile($file_or_dir)) {
434         LoadZip($request, $file_or_dir, $files, $exclude);
435     }
436     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
437     {
438         LoadFile($request, $file_or_dir);
439     }
440 }
441
442 function LoadFileOrDir (&$request)
443 {
444     $source = $request->getArg('source');
445     StartLoadDump( sprintf(_("Loading '%s'"),$source) );
446     echo "<dl>\n";
447     LoadAny($request->getDbh(), $source/*, false, array(gettext("RecentChanges"))*/);
448     echo "</dl>\n";
449     EndLoadDump($request);
450 }
451
452 function SetupWiki (&$request)
453 {
454     global $GenericPages, $LANG;
455     
456     
457     //FIXME: This is a hack (err, "interim solution")
458     // This is a bogo-bogo-login:  Login without
459     // saving login information in session state.
460     // This avoids logging in the unsuspecting
461     // visitor as "The PhpWiki programming team".
462     //
463     // This really needs to be cleaned up...
464     // (I'm working on it.)
465     $real_user = $request->_user;
466     $request->_user = new WikiUser(_("The PhpWiki programming team"),
467                                    WIKIAUTH_BOGO);
468     
469     StartLoadDump(_("Loading up virgin wiki"));
470     echo "<dl>\n";
471     
472     LoadAny($request, FindLocalizedFile(WIKI_PGSRC)/*, false, $ignore*/);
473     if ($LANG != "C")
474         LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC),
475                 $GenericPages/*, $ignore*/);
476     
477     echo "</dl>\n";
478     EndLoadDump($request);
479 }
480
481 function LoadPostFile (&$request)
482 {
483     $upload = $request->getUploadedFile('file');
484     
485     if (!$upload)
486         // FIXME: better message?
487         $request->finish(_("No uploaded file to upload?"));
488     
489     // Dump http headers.
490     StartLoadDump( sprintf(_("Uploading %s"),$upload->getName()) );
491     echo "<dl>\n";
492     
493     $fd = $upload->open();
494     if (IsZipFile($fd))
495         LoadZip($request->getDbh(), $fd, false, array(_("RecentChanges")));
496     else
497         Loadfile($request->getDbh(), $upload->getName(), $upload->getContents());
498     
499     echo "</dl>\n";
500     EndLoadDump($request);
501 }
502
503 // For emacs users
504 // Local Variables:
505 // mode: php
506 // tab-width: 8
507 // c-basic-offset: 4
508 // c-hanging-comment-ender-p: nil
509 // indent-tabs-mode: nil
510 // End:   
511 ?>