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