]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/PageDump.php
added dump of all revisions by format=backup (screen and download)
[SourceForge/phpwiki.git] / lib / plugin / PageDump.php
1 <?php // -*-php-*-
2 rcs_id('$Id: PageDump.php,v 1.14 2004-06-29 10:07:40 rurban Exp $');
3 /**
4  * PhpWikiPlugin for PhpWiki developers to generate single page dumps
5  * for checking into cvs, or for users or the admin to produce a
6  * downloadable page dump of a single page.
7  * 
8  * This plugin will also be useful to (semi-)automatically sync pages
9  * directly between two wikis. First the LoadFile function of
10  * PhpWikiAdministration needs to be updated to handle URLs again, and
11  * add loading capability from InterWiki addresses.
12
13  * multiple revisions in one file handled by format=backup
14  *
15  * TODO: What about comments/summary field? quoted-printable?
16  *
17  * Usage:
18  *  Direct URL access:
19  *   http://...phpwiki/PageDump?page=HomePage?format=forcvs
20  *   http://...phpwiki/index.php?PageDump&page=HomePage
21  *   http://...phpwiki/index.php?PageDump&page=HomePage&download=1
22  *  Static:
23  *   <?plugin PageDump page=HomePage?>
24  *  Dynamic form (put both on the page):
25  *   <?plugin PageDump?>
26  *   <?plugin-form PageDump?>
27  *  Typical usage: as actionbar button
28  */
29
30 class WikiPlugin_PageDump
31 extends WikiPlugin
32 {
33     var $MessageId;
34
35     function getName() {
36         return _("PageDump");
37     }
38     function getDescription() {
39         return _("View a single page dump online.");
40     }
41
42     function getVersion() {
43         return preg_replace("/[Revision: $]/", '',
44                             "\$Revision: 1.14 $");
45     }
46
47     function getDefaultArguments() {
48         return array('s'    => false,
49                      'page' => '[pagename]',
50                      //'encoding' => 'binary', // 'binary', 'quoted-printable'
51                      'format' => false, // 'normal', 'forcvs', 'backup'
52                      // display within WikiPage or give a downloadable
53                      // raw pgsrc?
54                      'download' => false);
55     }
56
57     function run($dbi, $argstr, &$request, $basepage) {
58         extract($this->getArgs($argstr, $request));
59         // allow plugin-form
60         if (!empty($s))
61             $page = $s;
62         if (!$page)
63             return '';
64         if (! $dbi->isWikiPage($page) )
65             return fmt("Page %s not found.",
66                        WikiLink($page, 'unknown'));
67
68         $p = $dbi->getPage($page);
69         include_once("lib/loadsave.php");
70         $mailified = MailifyPage($p, ($format == 'backup') ? 99 : 1);
71
72         // fixup_headers massages the page dump headers depending on
73         // the 'format' argument, 'normal'(default) or 'forcvs'.
74         //
75         // Normal: Don't add X-Rcs-Id, add unique Message-Id, don't
76         // strip any fields from Content-Type.
77         //
78         // ForCVS: Add empty X-Rcs-Id, strip attributes from
79         // Content-Type field: "author", "version", "lastmodified",
80         // "author_id", "hits".
81
82         $this->pagename = $page;
83         $this->generateMessageId($mailified);
84         if ($format == 'forcvs')
85             $this->fixup_headers_forcvs($mailified);
86         else // backup or normal
87             $this->fixup_headers($mailified);
88
89         if ($download) {
90             $request->discardOutput(); // Hijack the http request from PhpWiki.
91             ob_end_clean(); // clean up after hijacking $request
92             //ob_end_flush(); //debugging
93             Header("Content-disposition: attachment; filename=\""
94                    . FilenameForPage($page) . "\"");
95             // TODO: Read charset from generated page itself.
96             // Inconsequential at the moment, since loadsave.php
97             // presently always assumes CHARSET.
98             Header("Content-Type: text/plain; name=\""
99                    . FilenameForPage($page) . "\"; charset=\"" . $GLOBALS['charset']
100                    . "\"");
101             $request->checkValidators();
102             // let $request provide last modifed & etag
103             Header("Content-Id: <" . $this->MessageId . ">");
104             // be nice to http keepalive~s
105             Header("Content-Length: " . strlen($mailified));
106
107             // Here comes our prepared mime file
108             echo $mailified;
109             exit; // noreturn! php exits.
110             return;
111         }
112         // We are displaing inline preview in a WikiPage, so wrap the
113         // text if it is too long--unless quoted-printable (TODO).
114         $mailified = wordwrap($mailified, 70);
115
116         $dlcvs = Button(array(//'page' => $page,
117                               'action' => $this->getName(),
118                               'format'=> 'forcvs',
119                               'download'=> true),
120                         _("Download for CVS"),
121                         $page);
122         $dl = Button(array(//'page' => $page,
123                            'action' => $this->getName(),
124                            'download'=> true),
125                      _("Download for backup"),
126                      $page);
127         $dlall = Button(array(//'page' => $page,
128                            'action' => $this->getName(),
129                            'format'=> 'backup',
130                            'download'=> true),
131                      _("Download all revisions for backup"),
132                      $page);
133
134         $h2 = HTML::h2(fmt("Preview: Page dump of %s",
135                            WikiLink($page, 'auto')));
136         global $WikiTheme;
137         if (!$Sep = $WikiTheme->getButtonSeparator())
138             $Sep = " ";
139
140         if ($format == 'forcvs') {
141             $desc = _("(formatted for PhpWiki developers as pgsrc template, not for backing up)");
142             $altpreviewbuttons = HTML(
143                                       Button(array('action' => $this->getName()),
144                                              _("Preview as normal format"),
145                                              $page),
146                                       $Sep,
147                                       Button(array(
148                                                    'action' => $this->getName(),
149                                                    'format'=> 'backup'),
150                                              _("Preview as backup format"),
151                                              $page));
152         }
153         elseif ($format == 'backup') {
154             $desc = _("(formatted for backing up)"); // all revisions
155             $altpreviewbuttons = HTML(
156                                       Button(array('action' => $this->getName(),
157                                                    'format'=> 'forcvs'),
158                                              _("Preview as developer format"),
159                                              $page),
160                                       $Sep,
161                                       Button(array(
162                                                    'action' => $this->getName(),
163                                                    'format'=> ''),
164                                              _("Preview as normal format"),
165                                              $page));
166         } else {
167             $desc = _("(normal formatting)");
168             $altpreviewbuttons = HTML(
169                                       Button(array('action' => $this->getName(),
170                                                    'format'=> 'forcvs'),
171                                              _("Preview as developer format"),
172                                              $page),
173                                       $Sep,
174                                       Button(array(
175                                                    'action' => $this->getName(),
176                                                    'format'=> 'backup'),
177                                              _("Preview as backup format"),
178                                              $page));
179         }
180         $warning = HTML(
181 _("Please use one of the downloadable versions rather than copying and pasting from the above preview.")
182 . " " .
183 _("The wordwrap of the preview doesn't take nested markup or list indentation into consideration!")
184 . " ",
185 HTML::em(
186 _("PhpWiki developers should manually inspect the downloaded file for nested markup before rewrapping with emacs and checking into CVS.")
187          )
188                         );
189
190         return HTML($h2, HTML::em($desc),
191                     HTML::pre($mailified),
192                     $altpreviewbuttons,
193                     HTML::div(array('class' => 'errors'),
194                               HTML::strong(_("Warning:")),
195                               " ", $warning),
196                     $dl, $Sep, $dlall, $Sep, $dlcvs
197                     );
198     }
199
200     // function handle_plugin_args_cruft(&$argstr, &$args) {
201     // }
202
203     function generateMessageId($mailified) {
204         $array = explode("\n", $mailified);
205         // Extract lastmodifed from mailified document for Content-Id
206         // and/or Message-Id header, NOT from DB (page could have been
207         // edited by someone else since we started).
208         $m1 = preg_grep("/^\s+lastmodified\=(.*);/", $array);
209         $m1 = array_values($m1); //reset resulting keys
210         unset($array);
211         $m2 = preg_split("/(^\s+lastmodified\=)|(;)/", $m1[0], 2,
212                          PREG_SPLIT_NO_EMPTY);
213
214         // insert message id into actual message when appropriate, NOT
215         // into http header should be part of fixup_headers, in the
216         // format:
217         // <abbrphpwikiversion.mtimeepochTZ%InterWikiLinktothispage@hostname>
218         // Hopefully this provides a unique enough identifier without
219         // using md5. Even though this particular wiki may not
220         // actually be part of InterWiki, including this info provides
221         // the wiki name and name of the page which is being
222         // represented as a text message.
223         $this->MessageId = implode('', explode('.', PHPWIKI_VERSION))
224             . "-" . $m2[0] . date("O")
225             //. "-". rawurlencode(WIKI_NAME.":" . $request->getURLtoSelf())
226             . "-". rawurlencode(WIKI_NAME.":" . $this->pagename)
227             . "@". rawurlencode(SERVER_NAME);
228     }
229
230     function fixup_headers(&$mailified) {
231         $return = explode("\n", $mailified);
232
233         // Leave message intact for backing up, just add Message-Id header before transmitting.
234         $item_to_insert = "Message-Id: <" . $this->MessageId .">";
235         $insert_into_key_position = 2;
236         $returnval_ignored = array_splice($return,
237                                           $insert_into_key_position,
238                                           0, $item_to_insert);
239
240         $mailified = implode("\n", array_values($return));
241     }
242
243     function fixup_headers_forcvs(&$mailified) {
244         $array = explode("\n", $mailified);
245
246         // Massage headers to prepare for developer checkin to CVS.
247         $item_to_insert = "X-Rcs-Id: \$Id\$";
248         $insert_into_key_position = 2;
249         $returnval_ignored = array_splice($array,
250                                           $insert_into_key_position,
251                                           0, $item_to_insert);
252
253         $item_to_insert = "  pgsrc_version=\"2 \$Revision\$\";";
254         $insert_into_key_position = 5;
255         $returnval_ignored = array_splice($array,
256                                           $insert_into_key_position,
257                                           0, $item_to_insert);
258         /*
259             Strip out all this junk:
260             author=MeMe;
261             version=74;
262             lastmodified=1041561552;
263             author_id=127.0.0.1;
264             hits=146;
265         */
266         $killme = array("author", "version", "lastmodified",
267                         "author_id", "hits", "owner", "acl");
268         // UltraNasty, fixme:
269         foreach ($killme as $pattern) {
270             $array = preg_replace("/^\s\s$pattern\=.*;/",
271                                   /*$replacement =*/"zzzjunk", $array);
272         }
273         // remove deleted values from array
274         for ($i = 0; $i < count($array); $i++ ) {
275             if(trim($array[$i]) != "zzzjunk") { //nasty, fixme
276             //trigger_error("'$array[$i]'");//debugging
277                 $return[] =$array[$i];
278             }
279         }
280
281         $mailified = implode("\n", $return);
282     }
283 };
284
285 // $Log: not supported by cvs2svn $
286 // Revision 1.13  2004/06/17 10:39:18  rurban
287 // fix reverse translation of possible actionpage
288 //
289 // Revision 1.12  2004/06/16 13:32:43  rurban
290 // fix urlencoding of pagename in PageDump buttons
291 //
292 // Revision 1.11  2004/06/14 11:31:39  rurban
293 // renamed global $Theme to $WikiTheme (gforge nameclash)
294 // inherit PageList default options from PageList
295 //   default sortby=pagename
296 // use options in PageList_Selectable (limit, sortby, ...)
297 // added action revert, with button at action=diff
298 // added option regex to WikiAdminSearchReplace
299 //
300 // Revision 1.10  2004/06/07 22:28:05  rurban
301 // add acl field to mimified dump
302 //
303 // Revision 1.9  2004/06/07 19:50:41  rurban
304 // add owner field to mimified dump
305 //
306 // Revision 1.8  2004/05/25 12:43:29  rurban
307 // ViewSource link, better actionpage usage
308 //
309 // Revision 1.7  2004/05/04 17:21:06  rurban
310 // revert previous patch
311 //
312 // Revision 1.6  2004/05/03 20:44:55  rurban
313 // fixed gettext strings
314 // new SqlResult plugin
315 // _WikiTranslation: fixed init_locale
316 //
317 // Revision 1.5  2004/05/03 17:42:44  rurban
318 // fix cvs tags: "$tag$" => "$tag: $"
319 //
320 // Revision 1.4  2004/04/18 01:11:52  rurban
321 // more numeric pagename fixes.
322 // fixed action=upload with merge conflict warnings.
323 // charset changed from constant to global (dynamic utf-8 switching)
324 //
325 // Revision 1.3  2004/02/17 12:11:36  rurban
326 // added missing 4th basepage arg at plugin->run() to almost all plugins. This caused no harm so far, because it was silently dropped on normal usage. However on plugin internal ->run invocations it failed. (InterWikiSearch, IncludeSiteMap, ...)
327 //
328 // Revision 1.2  2003/12/12 01:08:30  carstenklapp
329 // QuickFix for invalid Message-Id header format.
330 //
331 // Revision 1.1  2003/12/12 00:52:55  carstenklapp
332 // New feature: Plugin to download page dumps of individual pages. In the
333 // future this could be used as a rudimentary way to sync pages between
334 // wikis.
335 // Internal changes: enhanced and renamed from the experimental
336 // _MailifyPage plugin.
337 //
338 // Revision 1.3  2003/11/16 00:11:25  carstenklapp
339 // Fixed previous Log comment interfering with PHP (sorry).
340 // Improved error handling.
341 //
342 // Revision 1.2  2003/11/15 23:37:51  carstenklapp
343 // Enhanced plugin to allow invocation with \<\?plugin-form PageDump\?\>.
344 //
345 // Revision 1.1  2003/02/20 18:03:04  carstenklapp
346 // New experimental WikiPlugin for internal use only by PhpWiki developers.
347 //
348
349 // For emacs users
350 // Local Variables:
351 // mode: php
352 // tab-width: 8
353 // c-basic-offset: 4
354 // c-hanging-comment-ender-p: nil
355 // indent-tabs-mode: nil
356 // End:
357 ?>