]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/Template.php
function run: @return mixed
[SourceForge/phpwiki.git] / lib / plugin / Template.php
1 <?php
2
3 /*
4  * Copyright 2005,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2008-2011 Marc-Etienne Vargenau, Alcatel-Lucent
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 along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 /**
25  * Template: Parametrized blocks.
26  *    Include text from a wiki page and replace certain placeholders by parameters.
27  *    Similiar to CreatePage with the template argument, but at run-time.
28  *    Similiar to the mediawiki templates but not with the "|" parameter seperator.
29  * Usage:   <<Template page=TemplateFilm vars="title=rurban&year=1999" >>
30  * Author:  Reini Urban
31  * See also: http://meta.wikimedia.org/wiki/Help:Template
32  *
33  * Parameter expansion:
34  *   vars="var1=value1&var2=value2"
35  * We only support named parameters, not numbered ones as in mediawiki, and
36  * the placeholder is %%var%% and not {{{var}}} as in mediawiki.
37  *
38  * The following predefined uppercase variables are automatically expanded if existing:
39  *   PAGENAME
40  *   MTIME     - last modified date + time
41  *   CTIME     - creation date + time
42  *   AUTHOR    - last author
43  *   OWNER
44  *   CREATOR   - first author
45  *   SERVER_URL, DATA_PATH, SCRIPT_NAME, PHPWIKI_BASE_URL and BASE_URL
46  *
47  * <noinclude> .. </noinclude>     is stripped from the template expansion.
48  * <includeonly> .. </includeonly> is only expanded in pages using the template,
49  *                                 not in the template itself.
50  *
51  *   We support a mediawiki-style syntax extension which maps
52  *     {{TemplateFilm|title=Some Good Film|year=1999}}
53  *   to
54  *     <<Template page=TemplateFilm vars="title=Some Good Film&year=1999" >>
55  */
56
57 class WikiPlugin_Template
58     extends WikiPlugin
59 {
60     function getDescription()
61     {
62         return _("Parametrized page inclusion.");
63     }
64
65     function getDefaultArguments()
66     {
67         return array(
68             'page' => false, // the page to include
69             'vars' => false, // TODO: get rid of this, all remaining args should be vars
70             'rev' => false, // the revision (defaults to most recent)
71             'section' => false, // just include a named section
72             'sectionhead' => false // when including a named section show the heading
73         );
74     }
75
76     function allow_undeclared_arg($name, $value)
77     {
78         // either just allow it or you can store it here away also.
79         $this->vars[$name] = $value;
80         return $name != 'action';
81     }
82
83     // TODO: check if page can really be pulled from the args, or if it is just the basepage.
84     function getWikiPageLinks($argstr, $basepage)
85     {
86         $args = $this->getArgs($argstr);
87         $page = isset($args['page']) ? $args['page'] : '';
88         if ($page) {
89             // Expand relative page names.
90             $page = new WikiPageName($page, $basepage);
91         }
92         if (!$page or !$page->name)
93             return false;
94
95         global $backlinks;
96         if (empty($backlinks)) {
97             global $request;
98             $this->run($request->_dbi, $argstr, $request, $basepage);
99         }
100
101         $backlinks[] = array('linkto' => $page->name, 'relation' => 0); 
102         return $backlinks;
103     }
104
105     /**
106      * @param WikiDB $dbi
107      * @param string $argstr
108      * @param WikiRequest $request
109      * @param string $basepage
110      * @return mixed
111      */
112     function run($dbi, $argstr, &$request, $basepage)
113     {
114         $this->vars = array();
115         $args = $this->getArgs($argstr, $request);
116         $vars = $args['vars'] ? $args['vars'] : $this->vars;
117         $page = $args['page'];
118
119         if ($page) {
120             // Expand relative page names.
121             $page = new WikiPageName($page, $basepage);
122             $page = $page->name;
123         }
124         if (!$page) {
125             return $this->error(sprintf(_("A required argument ā€œ%sā€ is missing."), 'page'));
126         }
127
128         // If "Template:$page" exists, use it
129         // else if "Template/$page" exists, use it
130         // else use "$page"
131         if ($dbi->isWikiPage("Template:" . $page)) {
132             $page = "Template:" . $page;
133         } elseif ($dbi->isWikiPage("Template/" . $page)) {
134             $page = "Template/" . $page;
135         }
136
137         // Protect from recursive inclusion.
138         global $rootpage;
139         if ($rootpage == '') {
140             $rootpage = $basepage;
141         }
142         if ($page == $rootpage) {
143             return $this->error(sprintf(_("Recursive inclusion of page %s ignored"),
144                 $page));
145         }
146
147         // Check if page exists
148         if (!($dbi->isWikiPage($page))) {
149             return $this->error(sprintf(_("Page ā€œ%sā€ does not exist."), $page));
150         }
151
152         // Check if user is allowed to get the Page.
153         if (!mayAccessPage('view', $page)) {
154             return $this->error(sprintf(_("Illegal inclusion of page %s: no read access."),
155                 $page));
156         }
157
158         $p = $dbi->getPage($page);
159         if ($args['rev']) {
160             if (!is_whole_number($args['rev']) or !($args['rev'] > 0)) {
161                 return $this->error(_("Error: rev must be a positive integer."));
162             }
163             $r = $p->getRevision($args['rev']);
164             if ((!$r) || ($r->hasDefaultContents())) {
165                 return $this->error(sprintf(_("%s: no such revision %d."),
166                     $page, $args['rev']));
167             }
168         } else {
169             $r = $p->getCurrentRevision();
170         }
171         $initial_content = $r->getPackedContent();
172
173         $content = $r->getContent();
174         // follow redirects
175         if ((preg_match('/<' . '\?plugin\s+RedirectTo\s+page=(\S+)\s*\?' . '>/', implode("\n", $content), $m))
176             or (preg_match('/<' . '\?plugin\s+RedirectTo\s+page=(.*?)\s*\?' . '>/', implode("\n", $content), $m))
177             or (preg_match('/<<\s*RedirectTo\s+page=(\S+)\s*>>/', implode("\n", $content), $m))
178             or (preg_match('/<<\s*RedirectTo\s+page="(.*?)"\s*>>/', implode("\n", $content), $m))
179         ) {
180             // Strip quotes (simple or double) from page name if any
181             if ((string_starts_with($m[1], "'"))
182                 or (string_starts_with($m[1], "\""))
183             ) {
184                 $m[1] = substr($m[1], 1, -1);
185             }
186             // trap recursive redirects
187             if ($m[1] == $rootpage) {
188                 return $this->error(sprintf(_("Recursive inclusion of page %s ignored"),
189                     $page . ' => ' . $m[1]));
190             }
191             $page = $m[1];
192             $p = $dbi->getPage($page);
193             $r = $p->getCurrentRevision();
194             $initial_content = $r->getPackedContent();
195         }
196
197         if ($args['section']) {
198             $c = explode("\n", $initial_content);
199             $c = extractSection($args['section'], $c, $page, $quiet, $args['sectionhead']);
200             $initial_content = implode("\n", $c);
201         }
202         // exclude from expansion
203         if (preg_match('/<noinclude>.+<\/noinclude>/s', $initial_content)) {
204             $initial_content = preg_replace("/<noinclude>.+?<\/noinclude>/s", "",
205                 $initial_content);
206         }
207         // only in expansion
208         $initial_content = preg_replace("/<includeonly>(.+)<\/includeonly>/s", "\\1",
209             $initial_content);
210         $this->doVariableExpansion($initial_content, $vars, $basepage, $request);
211
212         // If content is single-line, call TransformInline, else call TransformText
213         $initial_content = trim($initial_content, "\n");
214         if (preg_match("/\n/", $initial_content)) {
215             include_once 'lib/BlockParser.php';
216             $content = TransformText($initial_content, $page);
217         } else {
218             include_once 'lib/InlineParser.php';
219             $content = TransformInline($initial_content, $page);
220         }
221
222         return $content;
223     }
224
225     /**
226      * Expand template variables. Used by the TemplatePlugin and the CreatePagePlugin
227      */
228     function doVariableExpansion(&$content, $vars, $basepage, &$request)
229     {
230         if (preg_match('/%%\w+%%/', $content)) // need variable expansion
231         {
232             $dbi =& $request->_dbi;
233             $var = array();
234             if (is_string($vars) and !empty($vars)) {
235                 foreach (explode("&", $vars) as $pair) {
236                     list($key, $val) = explode("=", $pair);
237                     $var[$key] = $val;
238                 }
239             } elseif (is_array($vars)) {
240                 $var =& $vars;
241             }
242             $thispage = $dbi->getPage($basepage);
243             // pagename and userid are not overridable
244             $var['PAGENAME'] = $thispage->getName();
245             if (preg_match('/%%USERID%%/', $content))
246                 $var['USERID'] = $request->_user->getId();
247             if (empty($var['MTIME']) and preg_match('/%%MTIME%%/', $content)) {
248                 $thisrev = $thispage->getCurrentRevision(false);
249                 $var['MTIME'] = $GLOBALS['WikiTheme']->formatDateTime($thisrev->get('mtime'));
250             }
251             if (empty($var['CTIME']) and preg_match('/%%CTIME%%/', $content)) {
252                 if ($first = $thispage->getRevision(1, false))
253                     $var['CTIME'] = $GLOBALS['WikiTheme']->formatDateTime($first->get('mtime'));
254             }
255             if (empty($var['AUTHOR']) and preg_match('/%%AUTHOR%%/', $content))
256                 $var['AUTHOR'] = $thispage->getAuthor();
257             if (empty($var['OWNER']) and preg_match('/%%OWNER%%/', $content))
258                 $var['OWNER'] = $thispage->getOwner();
259             if (empty($var['CREATOR']) and preg_match('/%%CREATOR%%/', $content))
260                 $var['CREATOR'] = $thispage->getCreator();
261             foreach (array("SERVER_URL", "DATA_PATH", "SCRIPT_NAME", "PHPWIKI_BASE_URL") as $c) {
262                 // constants are not overridable
263                 if (preg_match('/%%' . $c . '%%/', $content))
264                     $var[$c] = constant($c);
265             }
266             if (preg_match('/%%BASE_URL%%/', $content))
267                 $var['BASE_URL'] = PHPWIKI_BASE_URL;
268
269             foreach ($var as $key => $val) {
270                 // We have to decode the double quotes that have been encoded
271                 // in inline or block parser.
272                 $content = str_replace("%%" . $key . "%%", htmlspecialchars_decode($val), $content);
273             }
274         }
275         return $content;
276     }
277 }
278
279 // Local Variables:
280 // mode: php
281 // tab-width: 8
282 // c-basic-offset: 4
283 // c-hanging-comment-ender-p: nil
284 // indent-tabs-mode: nil
285 // End: