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