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