]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/Template.php
Replace tabs by spaces; remove EOL spaces
[SourceForge/phpwiki.git] / lib / plugin / Template.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /*
4  * Copyright 2005,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2008-2009 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
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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:   <?plugin 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  *     <?plugin Template page=TemplateFilm vars="title=Some Good Film&year=1999" ?>
55  */
56
57 class WikiPlugin_Template
58 extends WikiPlugin
59 {
60     function getName() {
61         return _("Template");
62     }
63
64     function getDescription() {
65         return _("Parametrized page inclusion.");
66     }
67
68     function getVersion() {
69         return preg_replace("/[Revision: $]/", '',
70                             "\$Revision$");
71     }
72
73     function getDefaultArguments() {
74         return array(
75                      'page'    => false, // the page to include
76                      'vars'    => false, // TODO: get rid of this, all remaining args should be vars
77                      'rev'     => false, // the revision (defaults to most recent)
78                      'section' => false, // just include a named section
79                      'sectionhead' => false // when including a named section show the heading
80                      );
81     }
82     function allow_undeclared_arg($name, $value) {
83             // either just allow it or you can store it here away also.
84             $this->vars[$name] = $value;
85             return $name != 'action';
86     }
87
88     // TODO: check if page can really be pulled from the args, or if it is just the basepage.
89     function getWikiPageLinks($argstr, $basepage) {
90         $args = $this->getArgs($argstr);
91         $page = @$args['page'];
92         if ($page) {
93             // Expand relative page names.
94             $page = new WikiPageName($page, $basepage);
95         }
96         if (!$page or !$page->name)
97             return false;
98         return array(array('linkto' => $page->name, 'relation' => 0));
99     }
100
101     function run($dbi, $argstr, &$request, $basepage) {
102             $this->vars = array();
103         $args = $this->getArgs($argstr, $request);
104         $vars = $args['vars'] ? $args['vars'] : $this->vars;
105         $page = $args['page'];
106         if ($page) {
107             // Expand relative page names.
108             $page = new WikiPageName($page, $basepage);
109             $page = $page->name;
110         }
111         if (!$page) {
112             return $this->error(_("no page specified"));
113         }
114
115         // If "Template:$page" exists, use it
116         // else if "Template/$page" exists, use it
117         // else use "$page"
118         if ($dbi->isWikiPage("Template:" . $page)) {
119             $page = "Template:" . $page;
120         } elseif ($dbi->isWikiPage("Template/" . $page)) {
121             $page = "Template/" . $page;
122         }
123
124         // Protect from recursive inclusion. A page can include itself once
125         static $included_pages = array();
126         if (in_array($page, $included_pages)) {
127             return $this->error(sprintf(_("recursive inclusion of page %s"),
128                                         $page));
129         }
130
131         // Check if page exists
132         if (!($dbi->isWikiPage($page))) {
133             return $this->error(sprintf(_("Page '%s' does not exist"), $page));
134         }
135
136         // Check if user is allowed to get the Page.
137         if (!mayAccessPage ('view', $page)) {
138                 return $this->error(sprintf(_("Illegal inclusion of page %s: no read access"),
139                                         $page));
140         }
141
142         $p = $dbi->getPage($page);
143         if ($args['rev']) {
144             $r = $p->getRevision($args['rev']);
145             if (!$r) {
146                 return $this->error(sprintf(_("%s(%d): no such revision"),
147                                             $page, $args['rev']));
148             }
149         } else {
150             $r = $p->getCurrentRevision();
151         }
152         $initial_content = $r->getPackedContent();
153
154         $content = $r->getContent();
155         // follow redirects
156         if ((preg_match('/<'.'\?plugin\s+RedirectTo\s+page=(\S+)\s*\?'.'>/', implode("\n", $content), $m))
157           or (preg_match('/<'.'\?plugin\s+RedirectTo\s+page=(.*?)\s*\?'.'>/', implode("\n", $content), $m))
158           or (preg_match('/<<\s*RedirectTo\s+page=(\S+)\s*>>/', implode("\n", $content), $m))
159           or (preg_match('/<<\s*RedirectTo\s+page="(.*?)"\s*>>/', implode("\n", $content), $m)))
160         {
161             // Strip quotes (simple or double) from page name if any
162             if ((string_starts_with($m[1], "'"))
163               or (string_starts_with($m[1], "\""))) {
164                 $m[1] = substr($m[1], 1, -1);
165             }
166             // trap recursive redirects
167             if (in_array($m[1], $included_pages)) {
168                 return $this->error(sprintf(_("recursive inclusion of page %s ignored"),
169                                                 $page.' => '.$m[1]));
170             }
171             $page = $m[1];
172             $p = $dbi->getPage($page);
173             $r = $p->getCurrentRevision();
174             $initial_content = $r->getPackedContent();
175         }
176
177         if ($args['section']) {
178             $c = explode("\n", $initial_content);
179             $c = extractSection($args['section'], $c, $page, $quiet, $args['sectionhead']);
180             $initial_content = implode("\n", $c);
181         }
182         // exclude from expansion
183         if (preg_match('/<noinclude>.+<\/noinclude>/s', $initial_content)) {
184             $initial_content = preg_replace("/<noinclude>.+?<\/noinclude>/s", "",
185                                             $initial_content);
186         }
187         // only in expansion
188         $initial_content = preg_replace("/<includeonly>(.+)<\/includeonly>/s", "\\1",
189                                         $initial_content);
190         $this->doVariableExpansion($initial_content, $vars, $basepage, $request);
191
192         array_push($included_pages, $page);
193
194         // If content is single-line, call TransformInline, else call TransformText
195         $initial_content = trim($initial_content, "\n");
196         if (preg_match("/\n/", $initial_content)) {
197             include_once('lib/BlockParser.php');
198             $content = TransformText($initial_content, $r->get('markup'), $page);
199         } else {
200             include_once('lib/InlineParser.php');
201             $content = TransformInline($initial_content, $r->get('markup'), $page);
202         }
203
204         array_pop($included_pages);
205
206         return $content;
207     }
208
209     /**
210      * Expand template variables. Used by the TemplatePlugin and the CreatePagePlugin
211      */
212     function doVariableExpansion(&$content, $vars, $basepage, &$request) {
213         if (preg_match('/%%\w+%%/', $content)) // need variable expansion
214         {
215             $dbi =& $request->_dbi;
216             $var = array();
217             if (is_string($vars) and !empty($vars)) {
218                 foreach (split("&",$vars) as $pair) {
219                     list($key,$val) = split("=",$pair);
220                     $var[$key] = $val;
221                 }
222             } elseif (is_array($vars)) {
223                 $var =& $vars;
224             }
225             $thispage = $dbi->getPage($basepage);
226             // pagename and userid are not overridable
227             $var['PAGENAME'] = $thispage->getName();
228             if (preg_match('/%%USERID%%/', $content))
229                 $var['USERID'] = $request->_user->getId();
230             if (empty($var['MTIME']) and preg_match('/%%MTIME%%/', $content)) {
231                 $thisrev  = $thispage->getCurrentRevision(false);
232                 $var['MTIME'] = $GLOBALS['WikiTheme']->formatDateTime($thisrev->get('mtime'));
233             }
234             if (empty($var['CTIME']) and preg_match('/%%CTIME%%/', $content)) {
235                 if ($first = $thispage->getRevision(1,false))
236                     $var['CTIME'] = $GLOBALS['WikiTheme']->formatDateTime($first->get('mtime'));
237             }
238             if (empty($var['AUTHOR']) and preg_match('/%%AUTHOR%%/', $content))
239                 $var['AUTHOR'] = $thispage->getAuthor();
240             if (empty($var['OWNER']) and preg_match('/%%OWNER%%/', $content))
241                 $var['OWNER'] = $thispage->getOwner();
242             if (empty($var['CREATOR']) and preg_match('/%%CREATOR%%/', $content))
243                 $var['CREATOR'] = $thispage->getCreator();
244             foreach (array("SERVER_URL", "DATA_PATH", "SCRIPT_NAME", "PHPWIKI_BASE_URL") as $c) {
245                 // constants are not overridable
246                 if (preg_match('/%%'.$c.'%%/', $content))
247                     $var[$c] = constant($c);
248             }
249             if (preg_match('/%%BASE_URL%%/', $content))
250                 $var['BASE_URL'] = PHPWIKI_BASE_URL;
251
252             foreach ($var as $key => $val) {
253                 //$content = preg_replace("/%%".preg_quote($key,"/")."%%/", $val, $content);
254                 $content = str_replace("%%".$key."%%", $val, $content);
255             }
256         }
257         return $content;
258     }
259 };
260
261 // For emacs users
262 // Local Variables:
263 // mode: php
264 // tab-width: 8
265 // c-basic-offset: 4
266 // c-hanging-comment-ender-p: nil
267 // indent-tabs-mode: nil
268 // End:
269 ?>