2 rcs_id('$Id: PageDump.php,v 1.7 2004-05-04 17:21:06 rurban Exp $');
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.
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.
13 * TODO: What about multiple revisions in one file? comments/summary
14 * field? quoted-printable?
18 * http://...phpwiki/PageDump?page=HomePage?format=forcvs
19 * http://...phpwiki/index.php?PageDump&page=HomePage
20 * http://...phpwiki/index.php?PageDump&page=HomePage&download=1
22 * <?plugin PageDump page=HomePage?>
23 * Dynamic form (put both on the page):
25 * <?plugin-form PageDump?>
28 class WikiPlugin_PageDump
36 function getDescription() {
37 return _("View a single page dump online.");
40 function getVersion() {
41 return preg_replace("/[Revision: $]/", '',
45 function getDefaultArguments() {
46 return array('s' => false,
47 'page' => '[pagename]',
48 //'encoding' => 'binary', // 'binary', 'quoted-printable'
49 'format' => false, // 'normal', 'forcvs'
50 // display within WikiPage or give a downloadable
55 function run($dbi, $argstr, &$request, $basepage) {
56 extract($this->getArgs($argstr, $request));
62 if (! $dbi->isWikiPage($page))
63 return fmt("Page %s not found.",
64 WikiLink($page, 'unknown'));
66 $p = $dbi->getPage($page);
67 include_once("lib/loadsave.php");
68 $mailified = MailifyPage($p);
70 // fixup_headers massages the page dump headers depending on
71 // the 'format' argument, 'normal'(default) or 'forcvs'.
73 // Normal: Don't add X-Rcs-Id, add unique Message-Id, don't
74 // strip any fields from Content-Type.
76 // ForCVS: Add empty X-Rcs-Id, strip attributes from
77 // Content-Type field: "author", "version", "lastmodified",
78 // "author_id", "hits".
80 $this->pagename = $page;
81 $this->generateMessageId($mailified);
82 if ($format == 'forcvs')
83 $this->fixup_headers_forcvs($mailified);
85 $this->fixup_headers($mailified);
88 $request->discardOutput(); // Hijack the http request from PhpWiki.
89 ob_end_clean(); // clean up after hijacking $request
90 //ob_end_flush(); //debugging
91 Header("Content-disposition: attachment; filename=\""
92 . FilenameForPage($page) . "\"");
93 // TODO: Read charset from generated page itself.
94 // Inconsequential at the moment, since loadsave.php
95 // presently always assumes CHARSET.
96 Header("Content-Type: text/plain; name=\""
97 . FilenameForPage($page) . "\"; charset=\"" . $GLOBALS['charset']
99 $request->checkValidators();
100 // let $request provide last modifed & etag
101 Header("Content-Id: <" . $this->MessageId . ">");
102 // be nice to http keepalive~s
103 Header("Content-Length: " . strlen($mailified));
105 // Here comes our prepared mime file
107 exit; // noreturn! php exits.
110 // We are displaing inline preview in a WikiPage, so wrap the
111 // text if it is too long--unless quoted-printable (TODO).
112 $mailified = wordwrap($mailified, 70);
114 // fixme: what about when not using VIRTUAL_PATH?
115 $dlcvs = Button(array('page' => $page,
118 _("Download for CVS"),
119 $this->getName(), //fixme: $request->getPostUrl??
121 $dl = Button(array('page' => $page,
123 _("Download for backup"),
124 $this->getName(), //fixme: $request->getPostUrl??
127 $h2 = HTML::h2(fmt("Preview: Page dump of %s",
128 WikiLink($page, 'auto')));
129 if ($format == 'forcvs') {
130 $desc = _("(formatted for PhpWiki developers, not for backing up)");
131 $altpreviewbutton = Button(array('page' => $page),
132 _("Preview as backup format"),
133 $this->getName(), //fixme: $request->getPostUrl??
137 $desc = _("(formatted for backing up)");
138 $altpreviewbutton = Button(array('page' => $page,
139 'format'=> 'forcvs'),
140 _("Preview as developer format"),
141 $this->getName(), //fixme: $request->getPostUrl??
145 _("Please use one of the downloadable versions rather than copying and pasting from the above preview.")
147 _("The wordwrap of the preview doesn't take nested markup or list indentation into consideration!")
150 _("PhpWiki developers should manually inspect the downloaded file for nested markup before rewrapping with emacs and checking into CVS.")
155 if (!$Sep = $Theme->getButtonSeparator())
158 return HTML($h2, HTML::em($desc),
159 HTML::pre($mailified),
161 HTML::div(array('class' => 'errors'),
162 HTML::strong(_("Warning:")),
168 // function handle_plugin_args_cruft(&$argstr, &$args) {
171 function generateMessageId($mailified) {
172 $array = explode("\n", $mailified);
173 // Extract lastmodifed from mailified document for Content-Id
174 // and/or Message-Id header, NOT from DB (page could have been
175 // edited by someone else since we started).
176 $m1 = preg_grep("/^\s+lastmodified\=(.*);/", $array);
177 $m1 = array_values($m1); //reset resulting keys
179 $m2 = preg_split("/(^\s+lastmodified\=)|(;)/", $m1[0], 2,
180 PREG_SPLIT_NO_EMPTY);
182 // insert message id into actual message when appropriate, NOT
183 // into http header should be part of fixup_headers, in the
185 // <abbrphpwikiversion.mtimeepochTZ%InterWikiLinktothispage@hostname>
186 // Hopefully this provides a unique enough identifier without
187 // using md5. Even though this particular wiki may not
188 // actually be part of InterWiki, including this info provides
189 // the wiki name and name of the page which is being
190 // represented as a text message.
191 $this->MessageId = implode('', explode('.', PHPWIKI_VERSION))
192 . "-" . $m2[0] . (string)date("T")
193 //. "-". rawurlencode(WIKI_NAME.":" . $request->getURLtoSelf())
194 . "-". rawurlencode(WIKI_NAME.":" . $this->pagename)
195 . "@". rawurlencode(SERVER_NAME);
198 function fixup_headers(&$mailified) {
199 $return = explode("\n", $mailified);
201 // Leave message intact for backing up, just add Message-Id header before transmitting.
202 $item_to_insert = "Message-Id: <" . $this->MessageId .">";
203 $insert_into_key_position = 2;
204 $returnval_ignored = array_splice($return,
205 $insert_into_key_position,
208 $mailified = implode("\n", array_values($return));
211 function fixup_headers_forcvs(&$mailified) {
212 $array = explode("\n", $mailified);
214 // Massage headers to prepare for developer checkin to CVS.
215 $item_to_insert = "X-Rcs-Id: \$Id\$";
216 $insert_into_key_position = 2;
217 $returnval_ignored = array_splice($array,
218 $insert_into_key_position,
221 $item_to_insert = " pgsrc_version=\"2 \$Revision\$\";";
222 $insert_into_key_position = 5;
223 $returnval_ignored = array_splice($array,
224 $insert_into_key_position,
227 Strip out all this junk:
230 lastmodified=1041561552;
234 $killme = array("author", "version", "lastmodified",
235 "author_id", "hits");
236 // UltraNasty, fixme:
237 foreach ($killme as $pattern) {
238 $array = preg_replace("/^\s\s$pattern\=.*;/",
239 /*$replacement =*/"zzzjunk", $array);
241 // remove deleted values from array
242 for ($i = 0; $i < count($array); $i++ ) {
243 if(trim($array[$i]) != "zzzjunk") { //nasty, fixme
244 //trigger_error("'$array[$i]'");//debugging
245 $return[] =$array[$i];
249 $mailified = implode("\n", $return);
253 // $Log: not supported by cvs2svn $
254 // Revision 1.6 2004/05/03 20:44:55 rurban
255 // fixed gettext strings
256 // new SqlResult plugin
257 // _WikiTranslation: fixed init_locale
259 // Revision 1.5 2004/05/03 17:42:44 rurban
260 // fix cvs tags: "$tag$" => "$tag: $"
262 // Revision 1.4 2004/04/18 01:11:52 rurban
263 // more numeric pagename fixes.
264 // fixed action=upload with merge conflict warnings.
265 // charset changed from constant to global (dynamic utf-8 switching)
267 // Revision 1.3 2004/02/17 12:11:36 rurban
268 // 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, ...)
270 // Revision 1.2 2003/12/12 01:08:30 carstenklapp
271 // QuickFix for invalid Message-Id header format.
273 // Revision 1.1 2003/12/12 00:52:55 carstenklapp
274 // New feature: Plugin to download page dumps of individual pages. In the
275 // future this could be used as a rudimentary way to sync pages between
277 // Internal changes: enhanced and renamed from the experimental
278 // _MailifyPage plugin.
280 // Revision 1.3 2003/11/16 00:11:25 carstenklapp
281 // Fixed previous Log comment interfering with PHP (sorry).
282 // Improved error handling.
284 // Revision 1.2 2003/11/15 23:37:51 carstenklapp
285 // Enhanced plugin to allow invocation with \<\?plugin-form PageDump\?\>.
287 // Revision 1.1 2003/02/20 18:03:04 carstenklapp
288 // New experimental WikiPlugin for internal use only by PhpWiki developers.
296 // c-hanging-comment-ender-p: nil
297 // indent-tabs-mode: nil