]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/loadsave.php
improve loadfile stability by using markup=2 as default for undefined markup-style.
[SourceForge/phpwiki.git] / lib / loadsave.php
1 <?php //-*-php-*-
2 rcs_id('$Id: loadsave.php,v 1.121 2004-09-08 13:38:00 rurban Exp $');
3
4 /*
5  Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
6
7  This file is part of PhpWiki.
8
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.
13
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.
18
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
22  */
23
24
25 require_once("lib/ziplib.php");
26 require_once("lib/Template.php");
27
28 /**
29  * ignore fatal errors during dump
30  */
31 function _dump_error_handler(&$error) {
32     if ($error->isFatal()) {
33         $error->errno = E_USER_WARNING;
34         return true;
35     }
36     return true;         // Ignore error
37     /*
38     if (preg_match('/Plugin/', $error->errstr))
39         return true;
40     */
41     // let the message come through: call the remaining handlers:
42     // return false; 
43 }
44
45 function StartLoadDump(&$request, $title, $html = '')
46 {
47     if (isa($request,'MockRequest'))
48         return;
49     // FIXME: This is a hack
50     if ($html)
51         $html->pushContent('%BODY%');
52     $tmpl = Template('html', array('TITLE' => $title,
53                                    'HEADER' => $title,
54                                    'CONTENT' => $html ? $html : '%BODY%'));
55     echo ereg_replace('%BODY%.*', '', $tmpl->getExpansion($html));
56
57     /* Ignore fatals or warnings in any pagedumps (failing plugins). 
58      * WikiFunctionCb() fails with 4.0.6, works ok with 4.1.1 
59      */
60     if (!check_php_version(4,1) or (DEBUG & _DEBUG_VERBOSE)) return;
61     global $ErrorManager;
62     $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
63 }
64
65 function EndLoadDump(&$request)
66 {
67     if (isa($request,'MockRequest'))
68         return;
69     if (check_php_version(4,1)) {
70         global $ErrorManager;
71         $ErrorManager->popErrorHandler();
72     }
73     $action = $request->getArg('action');
74     $label = '';
75     switch ($action) {
76     case 'zip':        $label = _("ZIP files of database"); break;
77     case 'dumpserial': $label = _("Dump to directory"); break;
78     case 'upload':     $label = _("Upload File"); break;
79     case 'loadfile':   $label = _("Load File"); break;
80     case 'upgrade':    $label = _("Upgrade"); break;
81     case 'dumphtml': 
82     case 'ziphtml':    $label = _("Dump pages as XHTML"); break;
83     }
84     if ($label) $label = str_replace(" ","_",$label);
85     if ($action == 'browse') // loading virgin 
86         $pagelink = WikiLink(HOME_PAGE);
87     else
88         $pagelink = WikiLink(new WikiPageName(_("PhpWikiAdministration"),false,$label));
89
90     PrintXML(HTML::p(HTML::strong(_("Complete."))),
91              HTML::p(fmt("Return to %s", $pagelink)));
92     echo "</body></html>\n";
93 }
94
95
96 ////////////////////////////////////////////////////////////////
97 //
98 //  Functions for dumping.
99 //
100 ////////////////////////////////////////////////////////////////
101
102 /**
103  * For reference see:
104  * http://www.nacs.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
105  * http://www.faqs.org/rfcs/rfc2045.html
106  * (RFC 1521 has been superceeded by RFC 2045 & others).
107  *
108  * Also see http://www.faqs.org/rfcs/rfc2822.html
109  */
110 function MailifyPage ($page, $nversions = 1)
111 {
112     $current = $page->getCurrentRevision();
113     $head = '';
114
115     if (STRICT_MAILABLE_PAGEDUMPS) {
116         $from = defined('SERVER_ADMIN') ? SERVER_ADMIN : 'foo@bar';
117         //This is for unix mailbox format: (not RFC (2)822)
118         // $head .= "From $from  " . CTime(time()) . "\r\n";
119         $head .= "Subject: " . rawurlencode($page->getName()) . "\r\n";
120         $head .= "From: $from (PhpWiki)\r\n";
121         // RFC 2822 requires only a Date: and originator (From:)
122         // field, however the obsolete standard RFC 822 also
123         // requires a destination field.
124         $head .= "To: $from (PhpWiki)\r\n";
125     }
126     $head .= "Date: " . Rfc2822DateTime($current->get('mtime')) . "\r\n";
127     $head .= sprintf("Mime-Version: 1.0 (Produced by PhpWiki %s)\r\n",
128                      PHPWIKI_VERSION);
129
130     // This should just be entered by hand (or by script?)
131     // in the actual pgsrc files, since only they should have
132     // RCS ids.
133     //$head .= "X-Rcs-Id: \$Id\$\r\n";
134
135     $iter = $page->getAllRevisions();
136     $parts = array();
137     while ($revision = $iter->next()) {
138         $parts[] = MimeifyPageRevision($revision);
139         if ($nversions > 0 && count($parts) >= $nversions)
140             break;
141     }
142     if (count($parts) > 1)
143         return $head . MimeMultipart($parts);
144     assert($parts);
145     return $head . $parts[0];
146 }
147
148 /***
149  * Compute filename to used for storing contents of a wiki page.
150  *
151  * Basically we do a rawurlencode() which encodes everything except
152  * ASCII alphanumerics and '.', '-', and '_'.
153  *
154  * But we also want to encode leading dots to avoid filenames like
155  * '.', and '..'. (Also, there's no point in generating "hidden" file
156  * names, like '.foo'.)
157  *
158  * @param $pagename string Pagename.
159  * @return string Filename for page.
160  */
161 function FilenameForPage ($pagename)
162 {
163     $enc = rawurlencode($pagename);
164     return preg_replace('/^\./', '%2e', $enc);
165 }
166
167 /**
168  * The main() function which generates a zip archive of a PhpWiki.
169  *
170  * If $include_archive is false, only the current version of each page
171  * is included in the zip file; otherwise all archived versions are
172  * included as well.
173  */
174 function MakeWikiZip (&$request)
175 {
176     if ($request->getArg('include') == 'all') {
177         $zipname         = WIKI_NAME . _("FullDump") . date('Ymd-Hi') . '.zip';
178         $include_archive = true;
179     }
180     else {
181         $zipname         = WIKI_NAME . _("LatestSnapshot") . date('Ymd-Hi') . '.zip';
182         $include_archive = false;
183     }
184
185
186     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
187
188     /* ignore fatals in plugins */
189     if (check_php_version(4,1)) {
190         global $ErrorManager;
191         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
192     }
193
194     $dbi = $request->getDbh();
195     $thispage = $request->getArg('pagename'); // for "Return to ..."
196     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
197         $excludeList = explodePageList($exclude); 
198     } else {
199         $excludeList = array();
200     }
201     if ($whichpages = $request->getArg('pages')) {  // which pagenames
202         if ($whichpages == '[]') // current page
203             $whichpages = $thispage;
204         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
205     } else {
206         $pages = $dbi->getAllPages();
207     }
208     $request_args = $request->args;
209     
210     while ($page = $pages->next()) {
211         $request->args = $request_args; // some plugins might change them (esp. on POST)
212         if (! $request->getArg('start_debug'))
213             @set_time_limit(30); // Reset watchdog
214         else    
215             @set_time_limit(240);
216
217         $current = $page->getCurrentRevision();
218         if ($current->getVersion() == 0)
219             continue;
220
221         $pagename = $page->getName();
222         $wpn = new WikiPageName($pagename);
223         if (!$wpn->isValid())
224             continue;
225         if (in_array($page->getName(), $excludeList)) {
226             continue;
227         }
228
229         $attrib = array('mtime'    => $current->get('mtime'),
230                         'is_ascii' => 1);
231         if ($page->get('locked'))
232             $attrib['write_protected'] = 1;
233
234         if ($include_archive)
235             $content = MailifyPage($page, 0);
236         else
237             $content = MailifyPage($page);
238
239         $zip->addRegularFile( FilenameForPage($pagename),
240                               $content, $attrib);
241     }
242     $zip->finish();
243     if (check_php_version(4,1)) {
244         $ErrorManager->popErrorHandler();
245     }
246 }
247
248 function DumpToDir (&$request)
249 {
250     $directory = $request->getArg('directory');
251     if (empty($directory))
252         $directory = DEFAULT_DUMP_DIR; // See lib/plugin/WikiForm.php:87
253     if (empty($directory))
254         $request->finish(_("You must specify a directory to dump to"));
255
256     // see if we can access the directory the user wants us to use
257     if (! file_exists($directory)) {
258         if (! mkdir($directory, 0755))
259             $request->finish(fmt("Cannot create directory '%s'", $directory));
260         else
261             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
262                                 $directory));
263     } else {
264         $html = HTML::p(fmt("Using directory '%s'", $directory));
265     }
266
267     StartLoadDump($request, _("Dumping Pages"), $html);
268
269     $dbi = $request->getDbh();
270     $thispage = $request->getArg('pagename'); // for "Return to ..."
271     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
272         $excludeList = explodePageList($exclude); 
273     } else {
274         $excludeList = array();
275     }
276     if ($whichpages = $request->getArg('pages')) {  // which pagenames
277         if ($whichpages == '[]') // current page
278             $whichpages = $thispage;
279         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
280     } else {
281         $pages = $dbi->getAllPages();
282     }
283
284     $request_args = $request->args;
285     
286     while ($page = $pages->next()) {
287         $request->args = $request_args; // some plugins might change them (esp. on POST)
288         if (! $request->getArg('start_debug'))
289             @set_time_limit(30); // Reset watchdog.
290         else    
291             @set_time_limit(240);
292
293         $pagename = $page->getName();
294         if (!isa($request,'MockRequest')) {
295             PrintXML(HTML::br(), $pagename, ' ... ');
296             flush();
297         }
298
299         if (in_array($pagename, $excludeList)) {
300             if (!isa($request,'MockRequest')) {
301                 PrintXML(_("Skipped."));
302                 flush();
303             }
304             continue;
305         }
306         $filename = FilenameForPage($pagename);
307         $msg = HTML();
308         if($page->getName() != $filename) {
309             $msg->pushContent(HTML::small(fmt("saved as %s", $filename)),
310                               " ... ");
311         }
312
313         if ($request->getArg('include') == 'all')
314             $data = MailifyPage($page, 0);
315         else
316             $data = MailifyPage($page);
317
318         if ( !($fd = fopen("$directory/$filename", "wb")) ) {
319             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
320                                                "$directory/$filename")));
321             $request->finish($msg);
322         }
323
324         $num = fwrite($fd, $data, strlen($data));
325         $msg->pushContent(HTML::small(fmt("%s bytes written", $num)));
326         if (!isa($request,'MockRequest')) {
327             PrintXML($msg);
328             flush();
329         }
330         assert($num == strlen($data));
331         fclose($fd);
332     }
333
334     EndLoadDump($request);
335 }
336
337 /**
338  * Dump all pages as XHTML to a directory, as pagename.html.
339  * Copies all used css files to the directory, all used images to a 
340  * "images" subdirectory, and all used buttons to a "images/buttons" subdirectory.
341  * The webserver must have write permissions to these directories. 
342  *   chown httpd HTML_DUMP_DIR; chmod u+rwx HTML_DUMP_DIR 
343  * should be enough.
344  *
345  * @param string directory (optional) path to dump to. Default: HTML_DUMP_DIR
346  * @param string pages     (optional) Comma-seperated of glob-style pagenames to dump
347  * @param string exclude   (optional) Comma-seperated of glob-style pagenames to exclude
348  */
349 function DumpHtmlToDir (&$request)
350 {
351     $directory = $request->getArg('directory');
352     if (empty($directory))
353         $directory = HTML_DUMP_DIR; // See lib/plugin/WikiForm.php:87
354     if (empty($directory))
355         $request->finish(_("You must specify a directory to dump to"));
356
357     // see if we can access the directory the user wants us to use
358     if (! file_exists($directory)) {
359         if (! mkdir($directory, 0755))
360             $request->finish(fmt("Cannot create directory '%s'", $directory));
361         else
362             $html = HTML::p(fmt("Created directory '%s' for the page dump...",
363                                 $directory));
364     } else {
365         $html = HTML::p(fmt("Using directory '%s'", $directory));
366     }
367
368     StartLoadDump($request, _("Dumping Pages"), $html);
369     $thispage = $request->getArg('pagename'); // for "Return to ..."
370
371     $dbi = $request->getDbh();
372     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
373         $excludeList = explodePageList($exclude); 
374     } else {
375         $excludeList = array();
376     }
377     if ($whichpages = $request->getArg('pages')) {  // which pagenames
378         if ($whichpages == '[]') // current page
379             $whichpages = $thispage;
380         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
381     } else {
382         $pages = $dbi->getAllPages();
383     }
384
385     global $WikiTheme;
386     if (defined('HTML_DUMP_SUFFIX'))
387         $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
388     $WikiTheme->DUMP_MODE = 'HTML';
389     $request_args = $request->args;
390     
391     while ($page = $pages->next()) {
392         $request->args = $request_args; // some plugins might change them (esp. on POST)
393         if (! $request->getArg('start_debug'))
394             @set_time_limit(30); // Reset watchdog.
395         else    
396             @set_time_limit(240);
397           
398         $pagename = $page->getName();
399         if (!isa($request,'MockRequest')) {
400             PrintXML(HTML::br(), $pagename, ' ... ');
401             flush();
402         }
403         if (in_array($pagename, $excludeList)) {
404             if (!isa($request,'MockRequest')) {
405                 PrintXML(_("Skipped."));
406                 flush();
407             }
408             continue;
409         }
410
411         $request->setArg('pagename', $pagename); // Template::_basepage fix
412         $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
413         $msg = HTML();
414
415         $revision = $page->getCurrentRevision();
416         $transformedContent = $revision->getTransformedContent();
417         $template = new Template('browse', $request,
418                                  array('revision' => $revision,
419                                        'CONTENT' => $transformedContent));
420
421         $data = GeneratePageasXML($template, $pagename);
422
423         if ( !($fd = fopen("$directory/$filename", "wb")) ) {
424             $msg->pushContent(HTML::strong(fmt("couldn't open file '%s' for writing",
425                                                "$directory/$filename")));
426             $request->finish($msg);
427         }
428         $num = fwrite($fd, $data, strlen($data));
429         if($page->getName() != $filename) {
430             $prefix = '';
431             if (isWindows()) {  
432                 // drive where apache is installed
433                 $prefix = '/' . substr($_SERVER["DOCUMENT_ROOT"],0,2);
434             }
435             $link = LinkURL("file://".$prefix.$directory."/".$filename, 
436                             $filename);
437             $msg->pushContent(HTML::small(_("saved as "), $link, " ... "));
438         }
439         $msg->pushContent(HTML::small(fmt("%s bytes written", $num), "\n"));
440         if (!isa($request,'MockRequest')) {
441             PrintXML($msg);
442             flush();
443         }
444
445         assert($num == strlen($data));
446         fclose($fd);
447     }
448
449     if (!empty($WikiTheme->dumped_images) and is_array($WikiTheme->dumped_images)) {
450         @mkdir("$directory/images");
451         foreach ($WikiTheme->dumped_images as $img_file) {
452             if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
453                 $target = "$directory/images/".basename($img_file);
454                 if (copy($WikiTheme->_path . $from, $target)) {
455                     $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
456                     if (!isa($request,'MockRequest'))
457                         PrintXML($msg);
458                 }
459             } else {
460                 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
461                 if (!isa($request,'MockRequest'))
462                     PrintXML($msg);
463             }
464         }
465     }
466     if (!empty($WikiTheme->dumped_buttons) and is_array($WikiTheme->dumped_buttons)) {
467         // Buttons also
468         @mkdir("$directory/images/buttons");
469         foreach ($WikiTheme->dumped_buttons as $text => $img_file) {
470             if (($from = $WikiTheme->_findFile($img_file)) and basename($from)) {
471                 $target = "$directory/images/buttons/".basename($img_file);
472                 if (copy($WikiTheme->_path . $from, $target)) {
473                     $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
474                     if (!isa($request,'MockRequest'))
475                         PrintXML($msg);
476                 }
477             } else {
478                 $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
479                 if (!isa($request,'MockRequest'))
480                     PrintXML($msg);
481             }
482         }
483     }
484     if (!empty($WikiTheme->dumped_css) and is_array($WikiTheme->dumped_css)) {
485       foreach ($WikiTheme->dumped_css as $css_file) {
486           if (($from = $WikiTheme->_findFile(basename($css_file))) and basename($from)) {
487               $target = "$directory/" . basename($css_file);
488               if (copy($WikiTheme->_path . $from, $target)) {
489                   $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... copied to %s", $target)));
490                   if (!isa($request,'MockRequest'))
491                       PrintXML($msg);
492               }
493           } else {
494               $msg = HTML(HTML::br(), HTML($from), HTML::small(fmt("... not found", $target)));
495               if (!isa($request,'MockRequest'))
496                   PrintXML($msg);
497           }
498       }
499     }
500     $WikiTheme->HTML_DUMP_SUFFIX = '';
501     $WikiTheme->DUMP_MODE = false;
502
503     $request->setArg('pagename',$thispage); // Template::_basepage fix
504     EndLoadDump($request);
505 }
506
507 /* Known problem: any plugins or other code which echo()s text will
508  * lead to a corrupted html zip file which may produce the following
509  * errors upon unzipping:
510  *
511  * warning [wikihtml.zip]:  2401 extra bytes at beginning or within zipfile
512  * file #58:  bad zipfile offset (local header sig):  177561
513  *  (attempting to re-compensate)
514  *
515  * However, the actual wiki page data should be unaffected.
516  */
517 function MakeWikiZipHtml (&$request)
518 {
519     $zipname = "wikihtml.zip";
520     $zip = new ZipWriter("Created by PhpWiki " . PHPWIKI_VERSION, $zipname);
521     $dbi = $request->getDbh();
522     $thispage = $request->getArg('pagename'); // for "Return to ..."
523     if ($exclude = $request->getArg('exclude')) {   // exclude which pagenames
524         $excludeList = explodePageList($exclude); 
525     } else {
526         $excludeList = array();
527     }
528     if ($whichpages = $request->getArg('pages')) {  // which pagenames
529         if ($whichpages == '[]') // current page
530             $whichpages = $thispage;
531         $pages = new WikiDB_Array_PageIterator(explodePageList($whichpages));
532     } else {
533         $pages = $dbi->getAllPages();
534     }
535
536     global $WikiTheme;
537     if (defined('HTML_DUMP_SUFFIX'))
538         $WikiTheme->HTML_DUMP_SUFFIX = HTML_DUMP_SUFFIX;
539
540     /* ignore fatals in plugins */
541     if (check_php_version(4,1)) {
542         global $ErrorManager;
543         $ErrorManager->pushErrorHandler(new WikiFunctionCb('_dump_error_handler'));
544     }
545
546     $request_args = $request->args;
547     
548     while ($page = $pages->next()) {
549         $request->args = $request_args; // some plugins might change them (esp. on POST)
550         if (! $request->getArg('start_debug'))
551             @set_time_limit(30); // Reset watchdog.
552         else    
553             @set_time_limit(240);
554
555         $current = $page->getCurrentRevision();
556         if ($current->getVersion() == 0)
557             continue;
558         $pagename = $page->getName();
559         if (in_array($pagename, $excludeList)) {
560             continue;
561         }
562
563         $attrib = array('mtime'    => $current->get('mtime'),
564                         'is_ascii' => 1);
565         if ($page->get('locked'))
566             $attrib['write_protected'] = 1;
567
568         $request->setArg('pagename',$pagename); // Template::_basepage fix
569         $filename = FilenameForPage($pagename) . $WikiTheme->HTML_DUMP_SUFFIX;
570         $revision = $page->getCurrentRevision();
571
572         $transformedContent = $revision->getTransformedContent();
573
574         $template = new Template('browse', $request,
575                                  array('revision' => $revision,
576                                        'CONTENT' => $transformedContent));
577
578         $data = GeneratePageasXML($template, $pagename);
579
580         $zip->addRegularFile( $filename, $data, $attrib);
581     }
582     // FIXME: Deal with images here.
583     $zip->finish();
584     if (check_php_version(4,1)) {
585         $ErrorManager->popErrorHandler();
586     }
587     $WikiTheme->$HTML_DUMP_SUFFIX = '';
588 }
589
590
591 ////////////////////////////////////////////////////////////////
592 //
593 //  Functions for restoring.
594 //
595 ////////////////////////////////////////////////////////////////
596
597 function SavePage (&$request, &$pageinfo, $source, $filename)
598 {
599     $pagedata    = $pageinfo['pagedata'];    // Page level meta-data.
600     $versiondata = $pageinfo['versiondata']; // Revision level meta-data.
601
602     if (empty($pageinfo['pagename'])) {
603         PrintXML(HTML::dt(HTML::strong(_("Empty pagename!"))));
604         return;
605     }
606
607     if (empty($versiondata['author_id']))
608         $versiondata['author_id'] = $versiondata['author'];
609
610     $pagename = $pageinfo['pagename'];
611     $content  = $pageinfo['content'];
612
613     if ($pagename ==_("InterWikiMap"))
614         $content = _tryinsertInterWikiMap($content);
615
616     $dbi = $request->getDbh();
617     $page = $dbi->getPage($pagename);
618
619     // Try to merge if updated pgsrc contents are different. This
620     // whole thing is hackish
621     //
622     // TODO: try merge unless:
623     // if (current contents = default contents && pgsrc_version >=
624     // pgsrc_version) then just upgrade this pgsrc
625     $needs_merge = false;
626     $merging = false;
627     $overwrite = false;
628
629     if ($request->getArg('merge')) {
630         $merging = true;
631     }
632     else if ($request->getArg('overwrite')) {
633         $overwrite = true;
634     }
635
636     $current = $page->getCurrentRevision();
637     if ( $current and (! $current->hasDefaultContents())
638          && ($current->getPackedContent() != $content)
639          && ($merging == true) ) {
640         include_once('lib/editpage.php');
641         $request->setArg('pagename', $pagename);
642         $r = $current->getVersion();
643         $request->setArg('revision', $current->getVersion());
644         $p = new LoadFileConflictPageEditor($request);
645         $p->_content = $content;
646         $p->_currentVersion = $r - 1;
647         $p->editPage($saveFailed = true);
648         return; //early return
649     }
650
651     foreach ($pagedata as $key => $value) {
652         if (!empty($value))
653             $page->set($key, $value);
654     }
655
656     $mesg = HTML::dd();
657     $skip = false;
658     if ($source)
659         $mesg->pushContent(' ', fmt("from %s", $source));
660
661
662     if (!$current) {
663         //FIXME: This should not happen! (empty vdata, corrupt cache or db)
664         $current = $page->getCurrentRevision();
665     }
666     if ($current->getVersion() == 0) {
667         $mesg->pushContent(' - ', _("new page"));
668         $isnew = true;
669     }
670     else {
671         if ( (! $current->hasDefaultContents())
672              && ($current->getPackedContent() != $content) ) {
673             if ($overwrite) {
674                 $mesg->pushContent(' ',
675                                    fmt("has edit conflicts - overwriting anyway"));
676                 $skip = false;
677                 if (substr_count($source, 'pgsrc')) {
678                     $versiondata['author'] = _("The PhpWiki programming team");
679                     // but leave authorid as userid who loaded the file
680                 }
681             }
682             else {
683                 $mesg->pushContent(' ', fmt("has edit conflicts - skipped"));
684                 $needs_merge = true; // hackish
685                 $skip = true;
686             }
687         }
688         else if ($current->getPackedContent() == $content
689                  && $current->get('author') == $versiondata['author']) {
690             // The page metadata is already changed, we don't need a new revision.
691             // This was called previously "is identical to current version %d - skipped"
692             // which is wrong, since the pagedata was stored, not skipped.
693             $mesg->pushContent(' ',
694                                fmt("content is identical to current version %d - no new revision created",
695                                    $current->getVersion()));
696             $skip = true;
697         }
698         $isnew = false;
699     }
700
701     if (! $skip ) {
702         // in case of failures print the culprit:
703         if (!isa($request,'MockRequest')) {
704             PrintXML(HTML::dt(WikiLink($pagename))); flush();
705         }
706         $new = $page->save($content, WIKIDB_FORCE_CREATE, $versiondata);
707         $dbi->touch();
708         $mesg->pushContent(' ', fmt("- saved to database as version %d",
709                                     $new->getVersion()));
710     }
711     if ($needs_merge) {
712         $f = $source;
713         // hackish, $source contains needed path+filename
714         $f = str_replace(sprintf(_("MIME file %s"), ''), '', $f);
715         $f = str_replace(sprintf(_("Serialized file %s"), ''), '', $f);
716         $f = str_replace(sprintf(_("plain file %s"), ''), '', $f);
717         //check if uploaded file? they pass just the content, but the file is gone
718         if (@stat($f)) {
719             global $WikiTheme;
720             $meb = Button(array('action' => 'loadfile',
721                                 'merge'=> true,
722                                 'source'=> $f),
723                           _("Merge Edit"),
724                           _("PhpWikiAdministration"),
725                           'wikiadmin');
726             $owb = Button(array('action' => 'loadfile',
727                                 'overwrite'=> true,
728                                 'source'=> $f),
729                           _("Restore Anyway"),
730                           _("PhpWikiAdministration"),
731                           'wikiunsafe');
732             $mesg->pushContent(' ', $meb, " ", $owb);
733         } else {
734             $mesg->pushContent(HTML::em(_(" Sorry, cannot merge.")));
735         }
736     }
737
738     if (!isa($request,'MockRequest')) {
739       if ($skip)
740         PrintXML(HTML::dt(HTML::em(WikiLink($pagename))), $mesg);
741       else
742         PrintXML($mesg);
743       flush();
744     }
745 }
746
747 // action=revert (by diff)
748 function RevertPage (&$request)
749 {
750     $mesg = HTML::dd();
751     $pagename = $request->getArg('pagename');
752     $version = $request->getArg('version');
753     if (!$version) {
754         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
755                  HTML::dd(_("missing required version argument")));
756         return;
757     }
758     $dbi = $request->getDbh();
759     $page = $dbi->getPage($pagename);
760     $current = $page->getCurrentRevision();
761     if ($current->getVersion() == 0) {
762         $mesg->pushContent(' ', _("no page content"));
763         PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
764                  $mesg);
765         return;
766     }
767     if ($current->getVersion() == $version) {
768         $mesg->pushContent(' ', _("same version page"));
769         return;
770     }
771     $rev = $page->getRevision($version);
772     $content = $rev->getPackedContent();
773     $versiondata = $rev->_data;
774     $versiondata['summary'] = sprintf(_("revert to version %d"), $version);
775     $new = $page->save($content, $current->getVersion() + 1, $versiondata);
776     $dbi->touch();
777     $mesg->pushContent(' ', fmt("- version %d saved to database as version %d",
778                                 $version, $new->getVersion()));
779     PrintXML(HTML::dt(fmt("Revert")," ",WikiLink($pagename)),
780              $mesg);
781     flush();
782 }
783
784 function _tryinsertInterWikiMap($content) {
785     $goback = false;
786     if (strpos($content, "<verbatim>")) {
787         //$error_html = " The newly loaded pgsrc already contains a verbatim block.";
788         $goback = true;
789     }
790     if (!$goback && !defined('INTERWIKI_MAP_FILE')) {
791         $error_html = sprintf(" "._("%s: not defined"), "INTERWIKI_MAP_FILE");
792         $goback = true;
793     }
794     $mapfile = FindFile(INTERWIKI_MAP_FILE,1);
795     if (!$goback && !file_exists($mapfile)) {
796         $error_html = sprintf(" "._("%s: file not found"), INTERWIKI_MAP_FILE);
797         $goback = true;
798     }
799
800     if (!empty($error_html))
801         trigger_error(_("Default InterWiki map file not loaded.")
802                       . $error_html, E_USER_NOTICE);
803     if ($goback)
804         return $content;
805
806     // if loading from virgin setup do echo, otherwise trigger_error E_USER_NOTICE
807     if (!isa($GLOBALS['request'],'MockRequest'))
808         echo sprintf(_("Loading InterWikiMap from external file %s."), $mapfile),"<br />";
809
810     $fd = fopen ($mapfile, "rb");
811     $data = fread ($fd, filesize($mapfile));
812     fclose ($fd);
813     $content = $content . "\n<verbatim>\n$data</verbatim>\n";
814     return $content;
815 }
816
817 function ParseSerializedPage($text, $default_pagename, $user)
818 {
819     if (!preg_match('/^a:\d+:{[si]:\d+/', $text))
820         return false;
821
822     $pagehash = unserialize($text);
823
824     // Split up pagehash into four parts:
825     //   pagename
826     //   content
827     //   page-level meta-data
828     //   revision-level meta-data
829
830     if (!defined('FLAG_PAGE_LOCKED'))
831         define('FLAG_PAGE_LOCKED', 1);
832     $pageinfo = array('pagedata'    => array(),
833                       'versiondata' => array());
834
835     $pagedata = &$pageinfo['pagedata'];
836     $versiondata = &$pageinfo['versiondata'];
837
838     // Fill in defaults.
839     if (empty($pagehash['pagename']))
840         $pagehash['pagename'] = $default_pagename;
841     if (empty($pagehash['author'])) {
842         $pagehash['author'] = $user->getId();
843     }
844
845     foreach ($pagehash as $key => $value) {
846         switch($key) {
847             case 'pagename':
848             case 'version':
849             case 'hits':
850                 $pageinfo[$key] = $value;
851                 break;
852             case 'content':
853                 $pageinfo[$key] = join("\n", $value);
854                 break;
855             case 'flags':
856                 if (($value & FLAG_PAGE_LOCKED) != 0)
857                     $pagedata['locked'] = 'yes';
858                 break;
859             case 'owner':
860             case 'created':
861                 $pagedata[$key] = $value;
862                 break;
863             case 'acl':
864             case 'perm':
865                 $pagedata['perm'] = ParseMimeifiedPerm($value);
866                 break;
867             case 'lastmodified':
868                 $versiondata['mtime'] = $value;
869                 break;
870             case 'author':
871             case 'author_id':
872             case 'summary':
873                 $versiondata[$key] = $value;
874                 break;
875         }
876     }
877     return $pageinfo;
878 }
879
880 function SortByPageVersion ($a, $b) {
881     return $a['version'] - $b['version'];
882 }
883
884 function LoadFile (&$request, $filename, $text = false, $mtime = false)
885 {
886     if (!is_string($text)) {
887         // Read the file.
888         $stat  = stat($filename);
889         $mtime = $stat[9];
890         $text  = implode("", file($filename));
891     }
892
893         if (! $request->getArg('start_debug'))
894         @set_time_limit(30); // Reset watchdog.
895     else    
896         @set_time_limit(240);
897
898     // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
899     $basename = basename("/dummy/" . $filename);
900
901     if (!$mtime)
902         $mtime = time();    // Last resort.
903
904     $default_pagename = rawurldecode($basename);
905
906     if ( ($parts = ParseMimeifiedPages($text)) ) {
907         usort($parts, 'SortByPageVersion');
908         foreach ($parts as $pageinfo)
909             SavePage($request, $pageinfo, sprintf(_("MIME file %s"),
910                                                   $filename), $basename);
911     }
912     else if ( ($pageinfo = ParseSerializedPage($text, $default_pagename,
913                                                $request->getUser())) ) {
914         SavePage($request, $pageinfo, sprintf(_("Serialized file %s"),
915                                               $filename), $basename);
916     }
917     else {
918         $user = $request->getUser();
919
920         // Assume plain text file.
921         $pageinfo = array('pagename' => $default_pagename,
922                           'pagedata' => array(),
923                           'versiondata'
924                           => array('author' => $user->getId()),
925                           'content'  => preg_replace('/[ \t\r]*\n/', "\n",
926                                                      chop($text))
927                           );
928         SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename),
929                  $basename);
930     }
931 }
932
933 function LoadZip (&$request, $zipfile, $files = false, $exclude = false) {
934     $zip = new ZipReader($zipfile);
935     while (list ($fn, $data, $attrib) = $zip->readFile()) {
936         // FIXME: basename("filewithnoslashes") seems to return
937         // garbage sometimes.
938         $fn = basename("/dummy/" . $fn);
939         if ( ($files && !in_array($fn, $files))
940              || ($exclude && in_array($fn, $exclude)) ) {
941             PrintXML(HTML::dt(WikiLink($fn)),
942                      HTML::dd(_("Skipping")));
943             flush();
944             continue;
945         }
946
947         LoadFile($request, $fn, $data, $attrib['mtime']);
948     }
949 }
950
951 function LoadDir (&$request, $dirname, $files = false, $exclude = false) {
952     $fileset = new LimitedFileSet($dirname, $files, $exclude);
953
954     if (!$files and ($skiplist = $fileset->getSkippedFiles())) {
955         PrintXML(HTML::dt(HTML::strong(_("Skipping"))));
956         $list = HTML::ul();
957         foreach ($skiplist as $file)
958             $list->pushContent(HTML::li(WikiLink($file)));
959         PrintXML(HTML::dd($list));
960     }
961
962     // Defer HomePage loading until the end. If anything goes wrong
963     // the pages can still be loaded again.
964     $files = $fileset->getFiles();
965     if (in_array(HOME_PAGE, $files)) {
966         $files = array_diff($files, array(HOME_PAGE));
967         $files[] = HOME_PAGE;
968     }
969     foreach ($files as $file) {
970         if (substr($file,-1,1) != '~') // refuse to load backup files
971             LoadFile($request, "$dirname/$file");
972     }
973 }
974
975 class LimitedFileSet extends FileSet {
976     function LimitedFileSet($dirname, $_include, $exclude) {
977         $this->_includefiles = $_include;
978         $this->_exclude = $exclude;
979         $this->_skiplist = array();
980         parent::FileSet($dirname);
981     }
982
983     function _filenameSelector($fn) {
984         $incl = &$this->_includefiles;
985         $excl = &$this->_exclude;
986
987         if ( ($incl && !in_array($fn, $incl))
988              || ($excl && in_array($fn, $excl)) ) {
989             $this->_skiplist[] = $fn;
990             return false;
991         } else {
992             return true;
993         }
994     }
995
996     function getSkippedFiles () {
997         return $this->_skiplist;
998     }
999 }
1000
1001
1002 function IsZipFile ($filename_or_fd)
1003 {
1004     // See if it looks like zip file
1005     if (is_string($filename_or_fd))
1006     {
1007         $fd    = fopen($filename_or_fd, "rb");
1008         $magic = fread($fd, 4);
1009         fclose($fd);
1010     }
1011     else
1012     {
1013         $fpos  = ftell($filename_or_fd);
1014         $magic = fread($filename_or_fd, 4);
1015         fseek($filename_or_fd, $fpos);
1016     }
1017
1018     return $magic == ZIP_LOCHEAD_MAGIC || $magic == ZIP_CENTHEAD_MAGIC;
1019 }
1020
1021
1022 function LoadAny (&$request, $file_or_dir, $files = false, $exclude = false)
1023 {
1024     // Try urlencoded filename for accented characters.
1025     if (!file_exists($file_or_dir)) {
1026         // Make sure there are slashes first to avoid confusing phps
1027         // with broken dirname or basename functions.
1028         // FIXME: windows uses \ and :
1029         if (is_integer(strpos($file_or_dir, "/"))) {
1030             $file_or_dir = FindFile($file_or_dir);
1031             // Panic
1032             if (!file_exists($file_or_dir))
1033                 $file_or_dir = dirname($file_or_dir) . "/"
1034                     . urlencode(basename($file_or_dir));
1035         } else {
1036             // This is probably just a file.
1037             $file_or_dir = urlencode($file_or_dir);
1038         }
1039     }
1040
1041     $type = filetype($file_or_dir);
1042     if ($type == 'link') {
1043         // For symbolic links, use stat() to determine
1044         // the type of the underlying file.
1045         list(,,$mode) = stat($file_or_dir);
1046         $type = ($mode >> 12) & 017;
1047         if ($type == 010)
1048             $type = 'file';
1049         elseif ($type == 004)
1050             $type = 'dir';
1051     }
1052
1053     if (! $type) {
1054         $request->finish(fmt("Unable to load: %s", $file_or_dir));
1055     }
1056     else if ($type == 'dir') {
1057         LoadDir($request, $file_or_dir, $files, $exclude);
1058     }
1059     else if ($type != 'file' && !preg_match('/^(http|ftp):/', $file_or_dir))
1060     {
1061         $request->finish(fmt("Bad file type: %s", $type));
1062     }
1063     else if (IsZipFile($file_or_dir)) {
1064         LoadZip($request, $file_or_dir, $files, $exclude);
1065     }
1066     else /* if (!$files || in_array(basename($file_or_dir), $files)) */
1067     {
1068         LoadFile($request, $file_or_dir);
1069     }
1070 }
1071
1072 function LoadFileOrDir (&$request)
1073 {
1074     $source = $request->getArg('source');
1075     $finder = new FileFinder;
1076     $source = $finder->slashifyPath($source);
1077     $page = rawurldecode(basename($source));
1078     StartLoadDump($request, fmt("Loading '%s'", 
1079         HTML(dirname($source),
1080              dirname($source) ? "/" : "",
1081              WikiLink($page,'auto'))));
1082     echo "<dl>\n";
1083     LoadAny($request, $source);
1084     echo "</dl>\n";
1085     EndLoadDump($request);
1086 }
1087
1088 function SetupWiki (&$request)
1089 {
1090     global $GenericPages, $LANG;
1091
1092
1093     //FIXME: This is a hack (err, "interim solution")
1094     // This is a bogo-bogo-login:  Login without
1095     // saving login information in session state.
1096     // This avoids logging in the unsuspecting
1097     // visitor as "The PhpWiki programming team".
1098     //
1099     // This really needs to be cleaned up...
1100     // (I'm working on it.)
1101     $real_user = $request->_user;
1102     if (ENABLE_USER_NEW)
1103         $request->_user = new _BogoUser(_("The PhpWiki programming team"));
1104
1105     else
1106         $request->_user = new WikiUser($request, _("The PhpWiki programming team"),
1107                                        WIKIAUTH_BOGO);
1108
1109     StartLoadDump($request, _("Loading up virgin wiki"));
1110     echo "<dl>\n";
1111
1112     $pgsrc = FindLocalizedFile(WIKI_PGSRC);
1113     $default_pgsrc = FindFile(DEFAULT_WIKI_PGSRC);
1114
1115     $request->setArg('overwrite',true);
1116     if ($default_pgsrc != $pgsrc) {
1117         LoadAny($request, $default_pgsrc, $GenericPages);
1118     }
1119     $request->setArg('overwrite',false);
1120     LoadAny($request, $pgsrc);
1121
1122     // Ensure that all mandatory pages are loaded
1123     $finder = new FileFinder;
1124     foreach (array_merge(explode(':','OldTextFormattingRules:TextFormattingRules:PhpWikiAdministration'),
1125                          $GLOBALS['AllActionPages'],
1126                          array(constant('HOME_PAGE'))) as $f) {
1127         $page = gettext($f);
1128         if (isSubPage($page))
1129             $page = urlencode($page);
1130         if (! $request->_dbi->isWikiPage(urldecode($page)) ) {
1131             // translated version provided?
1132             if ($lf = FindLocalizedFile($pgsrc . $finder->_pathsep . $page, 1))
1133                 LoadAny($request, $lf);
1134             else { // load english version of required action page
1135                 LoadAny($request, FindFile(DEFAULT_WIKI_PGSRC . $finder->_pathsep . urlencode($f)));
1136                 $page = $f;
1137             }
1138         }
1139         if (!$request->_dbi->isWikiPage(urldecode($page))) {
1140             trigger_error(sprintf("Mandatory file %s couldn't be loaded!", $page),
1141                           E_USER_WARNING);
1142         }
1143     }
1144
1145     echo "</dl>\n";
1146     EndLoadDump($request);
1147 }
1148
1149 function LoadPostFile (&$request)
1150 {
1151     $upload = $request->getUploadedFile('file');
1152
1153     if (!$upload)
1154         $request->finish(_("No uploaded file to upload?")); // FIXME: more concise message
1155
1156
1157     // Dump http headers.
1158     StartLoadDump($request, sprintf(_("Uploading %s"), $upload->getName()));
1159     echo "<dl>\n";
1160
1161     $fd = $upload->open();
1162     if (IsZipFile($fd))
1163         LoadZip($request, $fd, false, array(_("RecentChanges")));
1164     else
1165         LoadFile($request, $upload->getName(), $upload->getContents());
1166
1167     echo "</dl>\n";
1168     EndLoadDump($request);
1169 }
1170
1171 /**
1172  $Log: not supported by cvs2svn $
1173  Revision 1.120  2004/07/08 19:04:42  rurban
1174  more unittest fixes (file backend, metadata RatingsDb)
1175
1176  Revision 1.119  2004/07/08 15:23:59  rurban
1177  less verbose for tests
1178
1179  Revision 1.118  2004/07/08 13:50:32  rurban
1180  various unit test fixes: print error backtrace on _DEBUG_TRACE; allusers fix; new PHPWIKI_NOMAIN constant for omitting the mainloop
1181
1182  Revision 1.117  2004/07/02 09:55:58  rurban
1183  more stability fixes: new DISABLE_GETIMAGESIZE if your php crashes when loading LinkIcons: failing getimagesize in old phps; blockparser stabilized
1184
1185  Revision 1.116  2004/07/01 09:05:41  rurban
1186  support pages and exclude arguments for all 4 dump methods
1187
1188  Revision 1.115  2004/07/01 08:51:22  rurban
1189  dumphtml: added exclude, print pagename before processing
1190
1191  Revision 1.114  2004/06/28 12:51:41  rurban
1192  improved dumphtml and virgin setup
1193
1194  Revision 1.113  2004/06/27 10:26:02  rurban
1195  oci8 patch by Philippe Vanhaesendonck + some ADODB notes+fixes
1196
1197  Revision 1.112  2004/06/25 14:29:20  rurban
1198  WikiGroup refactoring:
1199    global group attached to user, code for not_current user.
1200    improved helpers for special groups (avoid double invocations)
1201  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
1202  fixed a XHTML validation error on userprefs.tmpl
1203
1204  Revision 1.111  2004/06/21 16:38:55  rurban
1205  fixed the StartLoadDump html argument hack.
1206
1207  Revision 1.110  2004/06/21 16:22:30  rurban
1208  add DEFAULT_DUMP_DIR and HTML_DUMP_DIR constants, for easier cmdline dumps,
1209  fixed dumping buttons locally (images/buttons/),
1210  support pages arg for dumphtml,
1211  optional directory arg for dumpserial + dumphtml,
1212  fix a AllPages warning,
1213  show dump warnings/errors on DEBUG,
1214  don't warn just ignore on wikilens pagelist columns, if not loaded.
1215  RateIt pagelist column is called "rating", not "ratingwidget" (Dan?)
1216
1217  Revision 1.109  2004/06/17 11:31:05  rurban
1218  jump back to label after dump/upgrade
1219
1220  Revision 1.108  2004/06/16 12:43:01  rurban
1221  4.0.6 cannot use this errorhandler (not found)
1222
1223  Revision 1.107  2004/06/14 11:31:37  rurban
1224  renamed global $Theme to $WikiTheme (gforge nameclash)
1225  inherit PageList default options from PageList
1226    default sortby=pagename
1227  use options in PageList_Selectable (limit, sortby, ...)
1228  added action revert, with button at action=diff
1229  added option regex to WikiAdminSearchReplace
1230
1231  Revision 1.106  2004/06/13 13:54:25  rurban
1232  Catch fatals on the four dump calls (as file and zip, as html and mimified)
1233  FoafViewer: Check against external requirements, instead of fatal.
1234  Change output for xhtmldumps: using file:// urls to the local fs.
1235  Catch SOAP fatal by checking for GOOGLE_LICENSE_KEY
1236  Import GOOGLE_LICENSE_KEY and FORTUNE_DIR from config.ini.
1237
1238  Revision 1.105  2004/06/08 19:48:16  rurban
1239  fixed foreign setup: no ugly skipped msg for the GenericPages, load english actionpages if translated not found
1240
1241  Revision 1.104  2004/06/08 13:51:57  rurban
1242  some comments only
1243
1244  Revision 1.103  2004/06/08 10:54:46  rurban
1245  better acl dump representation, read back acl and owner
1246
1247  Revision 1.102  2004/06/06 16:58:51  rurban
1248  added more required ActionPages for foreign languages
1249  install now english ActionPages if no localized are found. (again)
1250  fixed default anon user level to be 0, instead of -1
1251    (wrong "required administrator to view this page"...)
1252
1253  Revision 1.101  2004/06/04 20:32:53  rurban
1254  Several locale related improvements suggested by Pierrick Meignen
1255  LDAP fix by John Cole
1256  reanable admin check without ENABLE_PAGEPERM in the admin plugins
1257
1258  Revision 1.100  2004/05/02 21:26:38  rurban
1259  limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
1260    because they will not survive db sessions, if too large.
1261  extended action=upgrade
1262  some WikiTranslation button work
1263  revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
1264  some temp. session debug statements
1265
1266  Revision 1.99  2004/05/02 15:10:07  rurban
1267  new finally reliable way to detect if /index.php is called directly
1268    and if to include lib/main.php
1269  new global AllActionPages
1270  SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
1271  WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
1272  PageGroupTestOne => subpages
1273  renamed PhpWikiRss to PhpWikiRecentChanges
1274  more docs, default configs, ...
1275
1276  Revision 1.98  2004/04/29 23:25:12  rurban
1277  re-ordered locale init (as in 1.3.9)
1278  fixed loadfile with subpages, and merge/restore anyway
1279    (sf.net bug #844188)
1280
1281  Revision 1.96  2004/04/19 23:13:03  zorloc
1282  Connect the rest of PhpWiki to the IniConfig system.  Also the keyword regular expression is not a config setting
1283
1284  Revision 1.95  2004/04/18 01:11:52  rurban
1285  more numeric pagename fixes.
1286  fixed action=upload with merge conflict warnings.
1287  charset changed from constant to global (dynamic utf-8 switching)
1288
1289  Revision 1.94  2004/03/14 16:36:37  rurban
1290  dont load backup files
1291
1292  Revision 1.93  2004/02/26 03:22:05  rurban
1293  also copy css and images with XHTML Dump
1294
1295  Revision 1.92  2004/02/26 02:25:54  rurban
1296  fix empty and #-anchored links in XHTML Dumps
1297
1298  Revision 1.91  2004/02/24 17:19:37  rurban
1299  debugging helpers only
1300
1301  Revision 1.90  2004/02/24 17:09:24  rurban
1302  fixed \r\r\n with dumping on windows
1303
1304  Revision 1.88  2004/02/22 23:20:31  rurban
1305  fixed DumpHtmlToDir,
1306  enhanced sortby handling in PageList
1307    new button_heading th style (enabled),
1308  added sortby and limit support to the db backends and plugins
1309    for paging support (<<prev, next>> links on long lists)
1310
1311  Revision 1.87  2004/01/26 09:17:49  rurban
1312  * changed stored pref representation as before.
1313    the array of objects is 1) bigger and 2)
1314    less portable. If we would import packed pref
1315    objects and the object definition was changed, PHP would fail.
1316    This doesn't happen with an simple array of non-default values.
1317  * use $prefs->retrieve and $prefs->store methods, where retrieve
1318    understands the interim format of array of objects also.
1319  * simplified $prefs->get() and fixed $prefs->set()
1320  * added $user->_userid and class '_WikiUser' portability functions
1321  * fixed $user object ->_level upgrading, mostly using sessions.
1322    this fixes yesterdays problems with loosing authorization level.
1323  * fixed WikiUserNew::checkPass to return the _level
1324  * fixed WikiUserNew::isSignedIn
1325  * added explodePageList to class PageList, support sortby arg
1326  * fixed UserPreferences for WikiUserNew
1327  * fixed WikiPlugin for empty defaults array
1328  * UnfoldSubpages: added pagename arg, renamed pages arg,
1329    removed sort arg, support sortby arg
1330
1331  Revision 1.86  2003/12/02 16:18:26  carstenklapp
1332  Minor enhancement: Provide more meaningful filenames for WikiDB zip
1333  dumps & snapshots.
1334
1335  Revision 1.85  2003/11/30 18:18:13  carstenklapp
1336  Minor code optimization: use include_once instead of require_once
1337  inside functions that might not always called.
1338
1339  Revision 1.84  2003/11/26 20:47:47  carstenklapp
1340  Redo bugfix: My last refactoring broke merge-edit & overwrite
1341  functionality again, should be fixed now. Sorry.
1342
1343  Revision 1.83  2003/11/20 22:18:54  carstenklapp
1344  New feature: h1 during merge-edit displays WikiLink to original page.
1345  Internal changes: Replaced some hackish url-generation code in
1346  function SavePage (for pgsrc merge-edit) with appropriate Button()
1347  calls.
1348
1349  Revision 1.82  2003/11/18 19:48:01  carstenklapp
1350  Fixed missing gettext _() for button name.
1351
1352  Revision 1.81  2003/11/18 18:28:35  carstenklapp
1353  Bugfix: In the Load File function of PhpWikiAdministration: When doing
1354  a "Merge Edit" or "Restore Anyway", page names containing accented
1355  letters (such as locale/de/pgsrc/G%E4steBuch) would produce a file not
1356  found error (Use FilenameForPage funtion to urlencode page names).
1357
1358  Revision 1.80  2003/03/07 02:46:57  dairiki
1359  Omit checks for safe_mode before set_time_limit().  Just prefix the
1360  set_time_limit() calls with @ so that they fail silently if not
1361  supported.
1362
1363  Revision 1.79  2003/02/26 01:56:05  dairiki
1364  Only zip pages with legal pagenames.
1365
1366  Revision 1.78  2003/02/24 02:05:43  dairiki
1367  Fix "n bytes written" message when dumping HTML.
1368
1369  Revision 1.77  2003/02/21 04:12:05  dairiki
1370  Minor fixes for new cached markup.
1371
1372  Revision 1.76  2003/02/16 19:47:17  dairiki
1373  Update WikiDB timestamp when editing or deleting pages.
1374
1375  Revision 1.75  2003/02/15 03:04:30  dairiki
1376  Fix for WikiUser constructor API change.
1377
1378  Revision 1.74  2003/02/15 02:18:04  dairiki
1379  When default language was English (at least), pgsrc was being
1380  loaded twice.
1381
1382  LimitedFileSet: Fix typo/bug. ($include was being ignored.)
1383
1384  SetupWiki(): Fix bugs in loading of $GenericPages.
1385
1386  Revision 1.73  2003/01/28 21:09:17  zorloc
1387  The get_cfg_var() function should only be used when one is
1388  interested in the value from php.ini or similar. Use ini_get()
1389  instead to get the effective value of a configuration variable.
1390  -- Martin Geisler
1391
1392  Revision 1.72  2003/01/03 22:25:53  carstenklapp
1393  Cosmetic fix to "Merge Edit" & "Overwrite" buttons. Added "The PhpWiki
1394  programming team" as author when loading from pgsrc. Source
1395  reformatting.
1396
1397  Revision 1.71  2003/01/03 02:48:05  carstenklapp
1398  function SavePage: Added loadfile options for overwriting or merge &
1399  compare a loaded pgsrc file with an existing page.
1400
1401  function LoadAny: Added a general error message when unable to load a
1402  file instead of defaulting to "Bad file type".
1403
1404  */
1405
1406 // For emacs users
1407 // Local Variables:
1408 // mode: php
1409 // tab-width: 8
1410 // c-basic-offset: 4
1411 // c-hanging-comment-ender-p: nil
1412 // indent-tabs-mode: nil
1413 // End:
1414 ?>