]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/PageDump.php
Better error message
[SourceForge/phpwiki.git] / lib / plugin / PageDump.php
1 <?php
2
3 /*
4  * Copyright (C) 2003 $ThePhpWikiProgrammingTeam
5  *
6  * This file is part of PhpWiki.
7  *
8  * PhpWiki is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * PhpWiki is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * PhpWikiPlugin for PhpWiki developers to generate single page dumps
25  * for checking into Subversion, or for users or the admin to produce a
26  * downloadable page dump of a single page.
27  *
28  * This plugin will also be useful to (semi-)automatically sync pages
29  * directly between two wikis. First the LoadFile function of
30  * PhpWikiAdministration needs to be updated to handle URLs again, and
31  * add loading capability from InterWiki addresses.
32  *
33  * Multiple revisions in one file handled by format=backup
34  *
35  * TODO: What about comments/summary field? quoted-printable?
36  *
37  * Usage:
38  *  Direct URL access:
39  *   http://...phpwiki/PageDump?page=HomePage?format=forsvn
40  *   http://...phpwiki/index.php?PageDump&page=HomePage
41  *   http://...phpwiki/index.php?PageDump&page=HomePage&download=1
42  *  Static:
43  *   <<PageDump page=HomePage>>
44  *  Dynamic form (put both on the page):
45  *   <<PageDump>>
46  *   <?plugin-form PageDump?>
47  *  Typical usage: as actionbar button
48  */
49
50 class WikiPlugin_PageDump
51     extends WikiPlugin
52 {
53     var $MessageId;
54
55     function getName()
56     {
57         return _("PageDump");
58     }
59
60     function getDescription()
61     {
62         return _("View a single page dump online.");
63     }
64
65     function getDefaultArguments()
66     {
67         return array('s' => false,
68             'page' => '[pagename]',
69             //'encoding' => 'binary', // 'binary', 'quoted-printable'
70             'format' => false, // 'normal', 'forsvn', 'forcvs', 'backup'
71             // display within WikiPage or give a downloadable
72             // raw pgsrc?
73             'download' => false);
74     }
75
76     function run($dbi, $argstr, &$request, $basepage)
77     {
78         extract($this->getArgs($argstr, $request));
79         // allow plugin-form
80         if (!empty($s)) {
81             $page = $s;
82         }
83         if (!$page) {
84             return '';
85         }
86         if (!$dbi->isWikiPage($page)) {
87             return $this->error(sprintf(_("Page ā€œ%sā€ does not exist."), $page));
88         }
89
90         // Check if user is allowed to get the Page.
91         if (!mayAccessPage('view', $page)) {
92             return $this->error(sprintf(_("Illegal access to page %s: no read access"),
93                 $page));
94         }
95
96         $p = $dbi->getPage($page);
97         include_once 'lib/loadsave.php';
98         $mailified = MailifyPage($p, ($format == 'backup') ? 99 : 1);
99
100         // fixup_headers massages the page dump headers depending on
101         // the 'format' argument, 'normal'(default) or 'forsvn'.
102         //
103         // Normal: add unique Message-Id, don't
104         // strip any fields from Content-Type.
105         //
106         // ForCVS: strip attributes from
107         // Content-Type field: "author", "version", "lastmodified",
108         // "author_id", "hits".
109
110         $this->pagename = $page;
111         $this->generateMessageId($mailified);
112         if (($format == 'forsvn') || ($format == 'forcvs'))
113             $this->fixup_headers_forsvn($mailified);
114         else // backup or normal
115             $this->fixup_headers($mailified);
116
117         if ($download) {
118             // TODO: we need a way to hook into the generated headers, to override
119             // Content-Type, Set-Cookie, Cache-control, ...
120             $request->discardOutput(); // Hijack the http request from PhpWiki.
121             ob_end_clean(); // clean up after hijacking $request
122             //while (@ob_end_flush()); //debugging
123             $filename = FilenameForPage($page);
124             Header("Content-disposition: attachment; filename=\""
125                 . $filename . "\"");
126             // Read charset from generated page itself.
127             // Inconsequential at the moment, since loadsave.php
128             // always generates headers.
129             $charset = $p->get('charset');
130             if (!$charset) $charset = $GLOBALS['charset'];
131             // We generate 3 Content-Type headers! first in loadsave,
132             // then here and the mimified string $mailified also has it!
133             // This one is correct and overwrites the others.
134             Header("Content-Type: application/octet-stream; name=\""
135                 . $filename . "\"; charset=\"" . $charset
136                 . "\"");
137             $request->checkValidators();
138             // let $request provide last modified & etag
139             Header("Content-Id: <" . $this->MessageId . ">");
140             // be nice to http keepalive~s
141             Header("Content-Length: " . strlen($mailified));
142
143             // Here comes our prepared mime file
144             echo $mailified;
145             exit(); // noreturn! php exits.
146         }
147         // We are displaing inline preview in a WikiPage, so wrap the
148         // text if it is too long--unless quoted-printable (TODO).
149         $mailified = wordwrap($mailified, 70);
150
151         $dlsvn = Button(array( //'page' => $page,
152                 'action' => $this->getName(),
153                 'format' => 'forsvn',
154                 'download' => true),
155             _("Download for Subversion"),
156             $page);
157         $dl = Button(array( //'page' => $page,
158                 'action' => $this->getName(),
159                 'download' => true),
160             _("Download for backup"),
161             $page);
162         $dlall = Button(array( //'page' => $page,
163                 'action' => $this->getName(),
164                 'format' => 'backup',
165                 'download' => true),
166             _("Download all revisions for backup"),
167             $page);
168
169         $h2 = HTML::h2(fmt("Preview: Page dump of %s",
170             WikiLink($page, 'auto')));
171         global $WikiTheme;
172         if (!$Sep = $WikiTheme->getButtonSeparator())
173             $Sep = " ";
174
175         if ($format == 'forsvn') {
176             $desc = _("(formatted for PhpWiki developers as pgsrc template, not for backing up)");
177             $altpreviewbuttons = HTML(
178                 Button(array('action' => $this->getName()),
179                     _("Preview as normal format"),
180                     $page),
181                 $Sep,
182                 Button(array(
183                         'action' => $this->getName(),
184                         'format' => 'backup'),
185                     _("Preview as backup format"),
186                     $page));
187         } elseif ($format == 'backup') {
188             $desc = _("(formatted for backing up: all revisions)"); // all revisions
189             $altpreviewbuttons = HTML(
190                 Button(array('action' => $this->getName(),
191                         'format' => 'forsvn'),
192                     _("Preview as developer format"),
193                     $page),
194                 $Sep,
195                 Button(array(
196                         'action' => $this->getName(),
197                         'format' => ''),
198                     _("Preview as normal format"),
199                     $page));
200         } else {
201             $desc = _("(normal formatting: latest revision only)");
202             $altpreviewbuttons = HTML(
203                 Button(array('action' => $this->getName(),
204                         'format' => 'forsvn'),
205                     _("Preview as developer format"),
206                     $page),
207                 $Sep,
208                 Button(array(
209                         'action' => $this->getName(),
210                         'format' => 'backup'),
211                     _("Preview as backup format"),
212                     $page));
213         }
214         $warning = HTML(
215             _("Please use one of the downloadable versions rather than copying and pasting from the above preview.")
216                 . " " .
217                 _("The wordwrap of the preview doesn't take nested markup or list indentation into consideration!")
218                 . " ",
219             HTML::em(
220                 _("PhpWiki developers should manually inspect the downloaded file for nested markup before rewrapping with emacs and checking into Subversion.")
221             )
222         );
223
224         return HTML($h2, HTML::em($desc),
225             HTML::pre($mailified),
226             $altpreviewbuttons,
227             HTML::div(array('class' => 'error'),
228                 HTML::strong(_("Warning:")),
229                 " ", $warning),
230             $dl, $Sep, $dlall, $Sep, $dlsvn
231         );
232     }
233
234     // function handle_plugin_args_cruft(&$argstr, &$args) {
235     // }
236
237     function generateMessageId($mailified)
238     {
239         $array = explode("\n", $mailified);
240         // Extract lastmodifed from mailified document for Content-Id
241         // and/or Message-Id header, NOT from DB (page could have been
242         // edited by someone else since we started).
243         $m1 = preg_grep("/^\s+lastmodified\=(.*);/", $array);
244         $m1 = array_values($m1); //reset resulting keys
245         unset($array);
246         $m2 = preg_split("/(^\s+lastmodified\=)|(;)/", $m1[0], 2,
247             PREG_SPLIT_NO_EMPTY);
248
249         // insert message id into actual message when appropriate, NOT
250         // into http header should be part of fixup_headers, in the
251         // format:
252         // <abbrphpwikiversion.mtimeepochTZ%InterWikiLinktothispage@hostname>
253         // Hopefully this provides a unique enough identifier without
254         // using md5. Even though this particular wiki may not
255         // actually be part of InterWiki, including this info provides
256         // the wiki name and name of the page which is being
257         // represented as a text message.
258         $this->MessageId = implode('', explode('.', PHPWIKI_VERSION))
259             . "-" . $m2[0] . date("O")
260             //. "-". rawurlencode(WIKI_NAME.":" . $request->getURLtoSelf())
261             . "-" . rawurlencode(WIKI_NAME . ":" . $this->pagename)
262             . "@" . rawurlencode(SERVER_NAME);
263     }
264
265     function fixup_headers(&$mailified)
266     {
267         $return = explode("\n", $mailified);
268
269         // Leave message intact for backing up, just add Message-Id header before transmitting.
270         $item_to_insert = "Message-Id: <" . $this->MessageId . ">";
271         $insert_into_key_position = 2;
272         $returnval_ignored = array_splice($return,
273             $insert_into_key_position,
274             0, $item_to_insert);
275
276         $mailified = implode("\n", array_values($return));
277     }
278
279     function fixup_headers_forsvn(&$mailified)
280     {
281         $array = explode("\n", $mailified);
282
283         // Massage headers to prepare for developer checkin to Subversion.
284         /*
285             Strip out all this junk:
286             author=MeMe;
287             version=74;
288             lastmodified=1041561552;
289             author_id=127.0.0.1;
290             hits=146;
291         */
292         $killme = array("author", "version", "lastmodified",
293             "author_id", "hits", "owner", "acl");
294         // UltraNasty, fixme:
295         foreach ($killme as $pattern) {
296             $array = preg_replace("/^\s\s$pattern\=.*;/",
297                 /*$replacement =*/
298                 "zzzjunk", $array);
299         }
300         // remove deleted values from array
301         for ($i = 0; $i < count($array); $i++) {
302             if (trim($array[$i]) != "zzzjunk") { //nasty, fixme
303                 //trigger_error("'$array[$i]'");//debugging
304                 $return[] = $array[$i];
305             }
306         }
307
308         $mailified = implode("\n", $return);
309     }
310 }
311
312 // Local Variables:
313 // mode: php
314 // tab-width: 8
315 // c-basic-offset: 4
316 // c-hanging-comment-ender-p: nil
317 // indent-tabs-mode: nil
318 // End: