]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/display.php
Reformat code
[SourceForge/phpwiki.git] / lib / display.php
1 <?php
2
3 /* Copyright (C) 2004-2011 $ThePhpWikiProgrammingTeam
4  *
5  * This file is part of PhpWiki.
6  *
7  * PhpWiki is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * PhpWiki is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 // display.php: fetch page or get default content
23
24 require_once 'lib/Template.php';
25
26 /**
27  * Extract keywords from Category* links on page.
28  */
29 function GleanKeywords($page)
30 {
31     if (!defined('KEYWORDS')) return '';
32     require_once 'lib/TextSearchQuery.php';
33     $search = new TextSearchQuery(KEYWORDS, true);
34     $KeywordLinkRegexp = $search->asRegexp();
35     // iterate over the pagelinks (could be a large number) [15ms on PluginManager]
36     // or do a titleSearch and check the categories if they are linked?
37     $links = $page->getPageLinks();
38     $keywords[] = SplitPagename($page->getName());
39     while ($link = $links->next()) {
40         $m = array();
41         if (preg_match($KeywordLinkRegexp, $link->getName(), $m))
42             $keywords[] = SplitPagename($m[0]);
43     }
44     $keywords[] = WIKI_NAME;
45     return join(', ', $keywords);
46 }
47
48 /** Make a link back to redirecting page.
49  *
50  * @param $pagename string  Name of redirecting page.
51  * @return XmlContent Link to the redirecting page.
52  */
53 function RedirectorLink($pagename)
54 {
55     $url = WikiURL($pagename, array('redirectfrom' => ''));
56     return HTML::a(array('class' => 'redirectfrom wiki',
57             'href' => $url),
58         $pagename);
59 }
60
61 /* only on ?action= */
62 function actionPage(&$request, $action)
63 {
64     global $WikiTheme;
65     global $robots;
66
67     $pagename = $request->getArg('pagename');
68     $version = $request->getArg('version');
69
70     $page = $request->getPage();
71     $revision = $page->getCurrentRevision();
72
73     $dbi = $request->getDbh();
74     $actionpage = $dbi->getPage($action);
75     $actionrev = $actionpage->getCurrentRevision();
76
77     $pagetitle = HTML(fmt("%s: %s",
78         $actionpage->getName(),
79         $WikiTheme->linkExistingWikiWord($pagename, false, $version)));
80
81     $request->setValidators(array('pageversion' => $revision->getVersion(),
82         '%mtime' => $revision->get('mtime')));
83     $request->appendValidators(array('pagerev' => $revision->getVersion(),
84         '%mtime' => $revision->get('mtime')));
85     $request->appendValidators(array('actionpagerev' => $actionrev->getVersion(),
86         '%mtime' => $actionrev->get('mtime')));
87
88     $transformedContent = $actionrev->getTransformedContent();
89
90     /* Optionally tell google (and others) not to take notice of action pages.
91        RecentChanges or AllPages might be an exception.
92     */
93     $args = array();
94     if (GOOGLE_LINKS_NOFOLLOW) {
95         $robots = "noindex,nofollow";
96         $args = array('ROBOTS_META' => $robots);
97     }
98
99     /* Handle other formats: So far we had html only.
100        xml is requested by loaddump, rss is handled by recentchanges,
101        pdf is a special action, but should be a format to dump multiple pages
102        if the actionpage plugin returns a pagelist.
103        rdf and owl are handled by SemanticWeb.
104     */
105     $format = $request->getArg('format');
106
107     /* At first the single page formats: html, xml */
108     if ($pagename == _("LinkDatabase")) {
109         $template = Template('browse', array('CONTENT' => $transformedContent));
110         GeneratePage($template, $pagetitle, $revision, $args);
111     } elseif (!$format or $format == 'html' or $format == 'sidebar' or $format == 'contribs') {
112         $template = Template('browse', array('CONTENT' => $transformedContent));
113         GeneratePage($template, $pagetitle, $revision, $args);
114     } elseif ($format == 'xml') {
115         $request->setArg('format', '');
116         $template = new Template('browse', $request,
117             array('revision' => $revision,
118                 'CONTENT' => $transformedContent,
119             ));
120         $html = GeneratePageAsXML($template, $pagename, $revision /*,
121                   array('VALID_LINKS' => $args['VALID_LINKS'])*/);
122         header("Content-Type: application/xhtml+xml; charset=" . $GLOBALS['charset']);
123         echo $html;
124     } else {
125         $pagelist = null;
126         require_once 'lib/WikiPlugin.php';
127         // Then the multi-page formats
128         // rss (if not already handled by RecentChanges)
129         // Need the pagelist from the first plugin
130         foreach ($transformedContent->_content as $cached_element) {
131             if (is_a($cached_element, "Cached_PluginInvocation")) {
132                 $loader = new WikiPluginLoader;
133                 $markup = null;
134                 // return the first found pagelist
135                 $pagelist = $loader->expandPI($cached_element->_pi, $request,
136                     $markup, $pagename);
137                 if (is_a($pagelist, 'PageList'))
138                     break;
139             }
140         }
141         if (!$pagelist or !is_a($pagelist, 'PageList')) {
142             if (!in_array($format, array("rss91", "rss2", "rss", "atom", "rdf")))
143                 trigger_error(sprintf("Format %s requires an actionpage returning a pagelist.",
144                     $format)
145                     . "\n" . ("Fall back to single page mode"), E_USER_WARNING);
146             require_once 'lib/PageList.php';
147             $pagelist = new PageList();
148             if ($format == 'pdf')
149                 $pagelist->addPage($page);
150         } else {
151             foreach ($pagelist->_pages as $page) {
152                 $name = $page->getName();
153                 if ($name != $pagename and $page->exists())
154                     $args['VALID_LINKS'][] = $name;
155             }
156         }
157         if ($format == 'pdf') {
158             require_once 'lib/pdf.php';
159             array_unshift($args['VALID_LINKS'], $pagename);
160             ConvertAndDisplayPdfPageList($request, $pagelist, $args);
161         } elseif ($format == 'ziphtml') { // need to fix links
162             require_once 'lib/loadsave.php';
163             array_unshift($args['VALID_LINKS'], $pagename);
164             $request->setArg('zipname', FilenameForPage($pagename) . ".zip");
165             $request->setArg('pages', $args['VALID_LINKS']);
166             $request->setArg('format', '');
167             MakeWikiZipHtml($request);
168         } // time-sorted RDF à la RecentChanges
169         elseif (in_array($format, array("rss91", "rss2", "rss", "atom"))) {
170             $args = $request->getArgs();
171             //$request->setArg('format','');
172             if ($pagename == _("RecentChanges")) {
173                 $template->printExpansion($args);
174             } else {
175                 require_once 'lib/plugin/RecentChanges.php';
176                 $plugin = new WikiPlugin_RecentChanges();
177                 return $plugin->format($plugin->getChanges($request->_dbi, $args), $args);
178             }
179         } elseif ($format == 'json') { // for faster autocompletion on searches
180             $req_args =& $request->args;
181             unset($req_args['format']);
182             $json = array('count' => count($pagelist->_pages),
183                 'list' => $args['VALID_LINKS'],
184                 'args' => $req_args,
185                 'phpwiki-version' => PHPWIKI_VERSION);
186             if (loadPhpExtension('json')) {
187                 $json_enc = json_encode($json);
188             } else {
189                 require_once 'lib/pear/JSON.php';
190                 $j = new Services_JSON();
191                 $json_enc = $j->encode($json);
192             }
193             header("Content-Type: application/json");
194             die($json_enc);
195         } elseif ($format == 'rdf') { // all semantic relations and attributes
196             require_once 'lib/SemanticWeb.php';
197             $rdf = new RdfWriter($request, $pagelist);
198             $rdf->format();
199         } elseif ($format == 'rdfs') {
200             require_once 'lib/SemanticWeb.php';
201             $rdf = new RdfsWriter($request, $pagelist);
202             $rdf->format();
203         } elseif ($format == 'owl') { // or daml?
204             require_once 'lib/SemanticWeb.php';
205             $rdf = new OwlWriter($request, $pagelist);
206             $rdf->format();
207         } else {
208             if (!in_array($pagename, array(_("LinkDatabase"))))
209                 trigger_error(sprintf(_("Unsupported argument: %s=%s"), "format", $format),
210                     E_USER_WARNING);
211             $template = Template('browse', array('CONTENT' => $transformedContent));
212             GeneratePage($template, $pagetitle, $revision, $args);
213         }
214     }
215     $request->checkValidators();
216     flush();
217     return '';
218 }
219
220 function displayPage(&$request, $template = false)
221 {
222     global $WikiTheme;
223     global $robots;
224     $pagename = $request->getArg('pagename');
225     $version = $request->getArg('version');
226     $page = $request->getPage();
227
228     if ($version) {
229         $revision = $page->getRevision($version);
230         if (!$revision)
231             NoSuchRevision($request, $page, $version);
232         /* Tell Google (and others) to ignore old versions of pages */
233         $robots = "noindex,nofollow";
234         $toks['ROBOTS_META'] = $robots;
235     } else {
236         $revision = $page->getCurrentRevision();
237     }
238     $format = $request->getArg('format');
239     if ($format == 'xml') { // fast ajax: include page content asynchronously
240         global $charset;
241         header("Content-Type: text/xml");
242         echo "<", "?xml version=\"1.0\" encoding=\"$charset\"?", ">\n";
243         // DOCTYPE html needed to allow unencoded entities like &nbsp; without !CDATA[]
244         echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
245   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', "\n";
246         if ($page->exists()) {
247             header("Last-Modified: " . Rfc1123DateTime($revision->get('mtime')));
248             $request->cacheControl();
249             $request->setArg('format', '');
250             $page_content = $revision->getTransformedContent();
251             $page_content->printXML();
252             $request->_is_buffering_output = false; // avoid wrong Content-Length with errors
253             $request->finish();
254         } else {
255             $request->cacheControl();
256             echo('<div style="display:none;" />');
257             $request->_is_buffering_output = false; // avoid wrong Content-Length with errors
258             $request->finish();
259             exit();
260         }
261     }
262
263     if (isSubPage($pagename)) {
264         $pages = explode(SUBPAGE_SEPARATOR, $pagename);
265         $last_page = array_pop($pages); // deletes last element from array as side-effect
266         $pageheader = HTML::span(HTML::a(array('href' => WikiURL($pages[0]),
267                 'class' => 'pagetitle'
268             ),
269             $WikiTheme->maybeSplitWikiWord($pages[0] . SUBPAGE_SEPARATOR)));
270         $first_pages = $pages[0] . SUBPAGE_SEPARATOR;
271         array_shift($pages);
272         foreach ($pages as $p) {
273             $pageheader->pushContent(HTML::a(array('href' => WikiURL($first_pages . $p),
274                     'class' => 'backlinks'),
275                 $WikiTheme->maybeSplitWikiWord($p . SUBPAGE_SEPARATOR)));
276             $first_pages .= $p . SUBPAGE_SEPARATOR;
277         }
278         $backlink = HTML::a(array('href' => WikiURL($pagename,
279                 array('action' => _("BackLinks"))),
280                 'class' => 'backlinks'),
281             $WikiTheme->maybeSplitWikiWord($last_page));
282         $backlink->addTooltip(sprintf(_("BackLinks for %s"), $pagename));
283         $pageheader->pushContent($backlink);
284     } else {
285         $pageheader = HTML::a(array('href' => WikiURL($pagename,
286                 array('action' => _("BackLinks"))),
287                 'class' => 'backlinks'),
288             $WikiTheme->maybeSplitWikiWord($pagename));
289         $pageheader->addTooltip(sprintf(_("BackLinks for %s"), $pagename));
290         if ($request->getArg('frame'))
291             $pageheader->setAttr('target', '_top');
292     }
293
294     $pagetitle = SplitPagename($pagename);
295     if (($redirect_from = $request->getArg('redirectfrom'))) {
296         $redirect_message = HTML::span(array('class' => 'redirectfrom'),
297             fmt("(Redirected from %s)",
298                 RedirectorLink($redirect_from)));
299         // abuse the $redirected template var for some status update notice
300     } elseif ($request->getArg('errormsg')) {
301         $redirect_message = HTML::p(array('class' => 'error'),
302             $request->getArg('errormsg'));
303         $request->setArg('errormsg', false);
304     } elseif ($request->getArg('warningmsg')) {
305         $redirect_message = HTML::p(array('class' => 'warning_msg'),
306             $request->getArg('warningmsg'));
307         $request->setArg('errormsg', false);
308     }
309
310     $request->appendValidators(array('pagerev' => $revision->getVersion(),
311         '%mtime' => $revision->get('mtime')));
312     /*
313         // FIXME: This is also in the template...
314         if ($request->getArg('action') != 'pdf' and !headers_sent()) {
315           // FIXME: enable MathML/SVG/... support
316           if (ENABLE_XHTML_XML
317                  and (!isBrowserIE()
318                       and strstr($request->get('HTTP_ACCEPT'),'application/xhtml+xml')))
319                 header("Content-Type: application/xhtml+xml; charset=" . $GLOBALS['charset']);
320             else
321                 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
322         }
323     */
324
325     $toks['TITLE'] = $pagetitle; // <title> tag
326     $toks['HEADER'] = $pageheader; // h1 with backlink
327     $toks['revision'] = $revision;
328
329     // On external searchengine (google) referrer, highlight the searchterm and
330     // pass through the Searchhighlight actionpage.
331     if ($result = isExternalReferrer($request)) {
332         if (!empty($result['query'])) {
333             if (ENABLE_SEARCHHIGHLIGHT) {
334                 $request->_searchhighlight = $result;
335                 $request->appendValidators(array('%mtime' => time())); // force no cache(?)
336                 // Should be changed to check the engine and search term only
337                 // $request->setArg('nocache', 1);
338                 $page_content = new TransformedText($revision->getPage(),
339                     $revision->getPackedContent(),
340                     $revision->getMetaData());
341                 /* Now add the SearchHighlight plugin to the top of the page, in memory only.
342                    You can parametrize this by changing the SearchHighlight action page.
343                 */
344                 if ($actionpage = $request->findActionPage('SearchHighlight')) {
345                     $actionpage = $request->getPage($actionpage);
346                     $actionrev = $actionpage->getCurrentRevision();
347                     $pagetitle = HTML(fmt("%s: %s",
348                         $actionpage->getName(),
349                         $WikiTheme->linkExistingWikiWord($pagename, false, $version)));
350                     $request->appendValidators(array('actionpagerev' => $actionrev->getVersion(),
351                         '%mtime' => $actionrev->get('mtime')));
352                     $toks['SEARCH_ENGINE'] = $result['engine'];
353                     $toks['SEARCH_ENGINE_URL'] = $result['engine_url'];
354                     $toks['SEARCH_TERM'] = $result['query'];
355                     //$toks['HEADER'] = HTML($actionpage->getName(),": ",$pageheader); // h1 with backlink
356                     $actioncontent = new TransformedText($actionrev->getPage(),
357                         $actionrev->getPackedContent(),
358                         $actionrev->getMetaData());
359                     // prepend the actionpage in front of the hightlighted content
360                     $toks['CONTENT'] = HTML($actioncontent, $page_content);
361                 }
362             }
363         } else {
364             $page_content = $revision->getTransformedContent();
365         }
366     } else {
367         $page_content = $revision->getTransformedContent();
368     }
369
370     if ($pagename == _("SandBox")) {
371         $robots = "noindex,nofollow";
372         $toks['ROBOTS_META'] = $robots;
373     } elseif (isActionPage($pagename)) {
374         $robots = "noindex,nofollow";
375         $toks['ROBOTS_META'] = $robots;
376     } elseif (!isset($toks['ROBOTS_META'])) {
377         $robots = "index,follow";
378         $toks['ROBOTS_META'] = $robots;
379     }
380     if (!isset($toks['CONTENT']))
381         $toks['CONTENT'] = new Template('browse', $request, $page_content);
382     if (!empty($redirect_message))
383         $toks['redirected'] = $redirect_message;
384
385     // Massive performance problem parsing at run-time into all xml objects
386     // looking for p's. Should be optional, if not removed at all.
387     //$toks['PAGE_DESCRIPTION'] = $page_content->getDescription();
388     $toks['PAGE_KEYWORDS'] = GleanKeywords($page);
389     if (!$template)
390         $template = new Template('html', $request);
391
392     // Handle other formats: So far we had html only.
393     // xml is requested by loaddump, rss is handled by RecentChanges,
394     // pdf is a special action, but should be a format to dump multiple pages
395     // if the actionpage plugin returns a pagelist.
396     // rdf, owl, kbmodel, daml, ... are handled by SemanticWeb.
397     /* Only single page versions. rss only if not already handled by RecentChanges.
398      */
399     if (!$format or $format == 'html' or $format == 'sidebar' or $format == 'contribs') {
400         $template->printExpansion($toks);
401     } else {
402         // No pagelist here. Single page version only
403         require_once 'lib/PageList.php';
404         $pagelist = new PageList();
405         $pagelist->addPage($page);
406         if ($format == 'pdf') {
407             require_once 'lib/pdf.php';
408             $request->setArg('format', '');
409             ConvertAndDisplayPdfPageList($request, $pagelist);
410             // time-sorted rdf a la RecentChanges
411         } elseif (in_array($format, array("rss91", "rss2", "rss", "atom"))) {
412             //$request->setArg('format','');
413             if ($pagename == _("RecentChanges"))
414                 $template->printExpansion($toks);
415             else {
416                 require_once 'lib/plugin/RecentChanges.php';
417                 $plugin = new WikiPlugin_RecentChanges();
418                 $args = $request->getArgs();
419                 return $plugin->format($plugin->getChanges($request->_dbi, $args), $args);
420             }
421         } elseif ($format == 'rdf') { // all semantic relations and attributes
422             require_once 'lib/SemanticWeb.php';
423             $rdf = new RdfWriter($request, $pagelist);
424             $rdf->format();
425         } elseif ($format == 'owl') { // or daml?
426             require_once 'lib/SemanticWeb.php';
427             $rdf = new OwlWriter($request, $pagelist);
428             $rdf->format();
429         } elseif ($format == 'json') { // include page content asynchronously
430             $request->setArg('format', '');
431             if ($page->exists())
432                 $content = $page_content->asXML();
433             else
434                 $content = '';
435             $req_args = $request->args;
436             unset($req_args['format']);
437             // no meta-data so far, just the content
438             $json = array('content' => $content,
439                 'args' => $req_args,
440                 'phpwiki-version' => PHPWIKI_VERSION);
441             if (loadPhpExtension('json')) {
442                 $json_enc = json_encode($json);
443             } else {
444                 require_once 'lib/pear/JSON.php';
445                 $j = new Services_JSON();
446                 $json_enc = $j->encode($json);
447             }
448             header("Content-Type: application/json");
449             die($json_enc);
450         } else {
451             if (!in_array($pagename, array(_("LinkDatabase"))))
452                 trigger_error(sprintf(_("Unsupported argument: %s=%s"), "format", $format),
453                     E_USER_WARNING);
454             $template->printExpansion($toks);
455         }
456     }
457
458     $page->increaseHitCount();
459
460     if ($request->getArg('action') != 'pdf') {
461         $request->checkValidators();
462         flush();
463     }
464     return '';
465 }
466
467 // Local Variables:
468 // mode: php
469 // tab-width: 8
470 // c-basic-offset: 4
471 // c-hanging-comment-ender-p: nil
472 // indent-tabs-mode: nil
473 // End: