]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Template.php
ensure $revision to be ste for all templates
[SourceForge/phpwiki.git] / lib / Template.php
1 <?php //-*-php-*-
2 rcs_id('$Id: Template.php,v 1.74 2006-12-22 00:24:43 rurban Exp $');
3
4 require_once("lib/ErrorManager.php");
5
6
7 /** An HTML template.
8  */
9 class Template
10 {
11     /**
12      * name optionally of form "theme/template" to include parent templates in children
13      */
14     function Template ($name, &$request, $args = false) {
15         global $WikiTheme;
16
17         $this->_request =& $request;
18         $this->_basepage = $request->getArg('pagename');
19
20         if (strstr($name, "/")) {
21             $oldname  = $WikiTheme->_name;
22             $oldtheme = $WikiTheme->_theme;
23             list($themename, $name) = explode("/", $name);
24             $WikiTheme->_theme = "themes/$themename";
25         }
26         $this->_name = $name;
27         $file = $WikiTheme->findTemplate($name);
28         if (!$file) {
29             trigger_error("no template for $name found.", E_USER_WARNING);
30             return;
31         }
32         if (isset($oldname)) { 
33             $WikiTheme->_name = $oldname; 
34             $WikiTheme->_theme = $oldtheme; 
35         }
36         $fp = fopen($file, "rb");
37         if (!$fp) {
38             trigger_error("$file not found", E_USER_WARNING);
39             return;
40         }
41         $request->_TemplatesProcessed[$name] = 1;
42         $this->_tmpl = fread($fp, filesize($file));
43         fclose($fp);
44         //$userid = $request->_user->_userid;
45         if (is_array($args))
46             $this->_locals = $args;
47         elseif ($args)
48             $this->_locals = array('CONTENT' => $args);
49         else
50             $this->_locals = array();
51     }
52
53     function _munge_input($template) {
54
55         // Convert < ?plugin expr ? > to < ?php $this->_printPluginPI("expr"); ? >
56         $orig[] = '/<\?plugin.*?\?>/se';
57         $repl[] = "\$this->_mungePlugin('\\0')";
58         
59         // Convert < ?= expr ? > to < ?php $this->_print(expr); ? >
60         $orig[] = '/<\?=(.*?)\?>/s';
61         $repl[] = '<?php $this->_print(\1);?>';
62         
63         return preg_replace($orig, $repl, $template);
64     }
65
66     function _mungePlugin($pi) {
67         // HACK ALERT: PHP's preg_replace, with the /e option seems to
68         // escape both single and double quotes with backslashes.
69         // So we need to unescape the double quotes here...
70
71         $pi = preg_replace('/(?!<\\\\)\\\\"/x', '"', $pi);
72         return sprintf('<?php $this->_printPlugin(%s); ?>',
73                        "'" . str_replace("'", "\'", $pi) . "'");
74     }
75     
76     function _printPlugin ($pi) {
77         include_once("lib/WikiPlugin.php");
78         static $loader;
79
80         if (empty($loader))
81             $loader = new WikiPluginLoader;
82         
83         $this->_print($loader->expandPI($pi, $this->_request, $this, $this->_basepage));
84     }
85     
86     function _print ($val) {
87         if (isa($val, 'Template')) {
88             $this->_expandSubtemplate($val);
89         } else {
90             PrintXML($val);
91         }
92     }
93
94     function _expandSubtemplate (&$template) {
95         // FIXME: big hack!        
96         //if (!$template->_request)
97         //    $template->_request = &$this->_request;
98         if (DEBUG) {
99             echo "<!-- Begin $template->_name -->\n";
100         }
101         // Expand sub-template with defaults from this template.
102         $template->printExpansion($this->_vars);
103         if (DEBUG) {
104             echo "<!-- End $template->_name -->\n";
105         }
106     }
107         
108     /**
109      * Substitute HTML replacement text for tokens in template. 
110      *
111      * Constructs a new WikiTemplate based upon the named template.
112      *
113      * @access public
114      *
115      * @param $token string Name of token to substitute for.
116      *
117      * @param $replacement string Replacement HTML text.
118      */
119     function replace($varname, $value) {
120         $this->_locals[$varname] = $value;
121     }
122
123     
124     function printExpansion ($defaults = false) {
125         if (!is_array($defaults)) // HTML object or template object
126             $defaults = array('CONTENT' => $defaults);
127         $this->_vars = array_merge($defaults, $this->_locals);
128         extract($this->_vars);
129
130         global $request;
131         if (!isset($user))
132             $user = $request->getUser();
133         if (!isset($page))
134             $page = $request->getPage();
135
136         global $WikiTheme, $RCS_IDS, $charset; 
137         //$this->_dump_template();
138         $SEP = $WikiTheme->getButtonSeparator();
139
140         global $ErrorManager;
141         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
142
143         eval('?>' . $this->_munge_input($this->_tmpl));
144
145         $ErrorManager->popErrorHandler();
146     }
147
148     // FIXME (1.3.12)
149     // Find a way to do template expansion less memory intensive and faster.
150     // 1.3.4 needed no memory at all for dumphtml, now it needs +15MB.
151     // Smarty? As before?
152     function getExpansion ($defaults = false) {
153         ob_start();
154         $this->printExpansion($defaults);
155         $xml = ob_get_contents();
156         ob_end_clean();         // PHP problem: Doesn't release its memory?
157         return $xml;
158     }
159
160     function printXML () {
161         $this->printExpansion();
162     }
163
164     function asXML () {
165         return $this->getExpansion();
166     }
167     
168             
169     // Debugging:
170     function _dump_template () {
171         $lines = explode("\n", $this->_munge_input($this->_tmpl));
172         $pre = HTML::pre();
173         $n = 1;
174         foreach ($lines as $line)
175             $pre->pushContent(fmt("%4d  %s\n", $n++, $line));
176         $pre->printXML();
177     }
178
179     function _errorHandler($error) {
180         //if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
181         //    return false;
182
183         if (preg_match('/: eval\(\)\'d code$/', $error->errfile)) {
184             $error->errfile = "In template '$this->_name'";
185             // Hack alert: Ignore 'undefined variable' messages for variables
186             //  whose names are ALL_CAPS.
187             if (preg_match('/Undefined variable:\s*[_A-Z]+\s*$/', $error->errstr))
188                 return true;
189         }
190         // ignore recursively nested htmldump loop: browse -> body -> htmldump -> browse -> body ...
191         // FIXME for other possible loops also
192         elseif (strstr($error->errfile, "In template 'htmldump'")) {
193             ; //return $error;
194         }
195         elseif (strstr($error->errfile, "In template '")) { // merge
196             $error->errfile = preg_replace("/'(\w+)'\)$/", "'\\1' < '$this->_name')", $error->errfile);
197         }
198         else {
199             $error->errfile .= " (In template '$this->_name')";
200         }
201
202         if (!empty($this->_tmpl)) {
203             $lines = explode("\n", $this->_tmpl);
204             if (isset($lines[$error->errline - 1]))
205                 $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
206         }
207         return $error;
208     }
209 };
210
211 /**
212  * Get a templates
213  *
214  * This is a convenience function and is equivalent to:
215  * <pre>
216  *   new Template(...)
217  * </pre>
218  */
219 function Template($name, $args = false) {
220     global $request;
221     return new Template($name, $request, $args);
222 }
223
224 function alreadyTemplateProcessed($name) {
225     global $request;
226     return !empty($request->_TemplatesProcessed[$name]) ? true : false;
227 }
228 /**
229  * Make and expand the top-level template. 
230  *
231  *
232  * @param $content mixed html content to put into the page
233  * @param $title string page title
234  * @param $page_revision object A WikiDB_PageRevision object
235  * @param $args hash Extract args for top-level template
236  *
237  * @return string HTML expansion of template.
238  */
239 function GeneratePage($content, $title, $page_revision = false, $args = false) {
240     global $request;
241     
242     if (!is_array($args))
243         $args = array();
244
245     $args['CONTENT'] = $content;
246     $args['TITLE'] = $title;
247     $args['revision'] = $page_revision;
248     
249     if (!isset($args['HEADER']))
250         $args['HEADER'] = $title;
251     
252     printXML(new Template('html', $request, $args));
253 }
254
255
256 /**
257  * For dumping pages as html to a file.
258  */
259 function GeneratePageasXML($content, $title, $page_revision = false, $args = false) {
260     global $request;
261     
262     if (!is_array($args))
263         $args = array();
264
265     $content->_basepage = $title;
266     $args['CONTENT'] = $content;
267     $args['TITLE'] = SplitPagename($title);
268     $args['revision'] = $page_revision;
269     
270     if (!isset($args['HEADER']))
271         $args['HEADER'] = SplitPagename($title);
272     
273     global $HIDE_TOOLBARS, $NO_BASEHREF, $HTML_DUMP;
274     $HIDE_TOOLBARS = true;
275     $HTML_DUMP = true;
276
277     $html = asXML(new Template('htmldump', $request, $args));
278     
279     $HIDE_TOOLBARS = false;
280     $HTML_DUMP = false;
281     return $html;
282 }
283
284 // $Log: not supported by cvs2svn $
285 // Revision 1.73  2005/04/08 05:41:00  rurban
286 // fix Template("theme/name") inclusion
287 //
288 // Revision 1.72  2005/02/02 20:35:41  rurban
289 // add $SEP
290 //
291 // Revision 1.71  2005/02/02 19:29:30  rurban
292 // support theme overrides
293 //
294 // Revision 1.70  2005/01/25 07:01:26  rurban
295 // update comments about future plans
296 //
297 // Revision 1.69  2004/11/17 20:07:17  rurban
298 // just whitespace
299 //
300 // Revision 1.68  2004/11/09 17:11:04  rurban
301 // * revert to the wikidb ref passing. there's no memory abuse there.
302 // * use new wikidb->_cache->_id_cache[] instead of wikidb->_iwpcache, to effectively
303 //   store page ids with getPageLinks (GleanDescription) of all existing pages, which
304 //   are also needed at the rendering for linkExistingWikiWord().
305 //   pass options to pageiterator.
306 //   use this cache also for _get_pageid()
307 //   This saves about 8 SELECT count per page (num all pagelinks).
308 // * fix passing of all page fields to the pageiterator.
309 // * fix overlarge session data which got broken with the latest ACCESS_LOG_SQL changes
310 //
311 // Revision 1.67  2004/11/05 18:03:35  rurban
312 // shorten the template chain in errmsg
313 //
314 // Revision 1.66  2004/11/01 10:43:55  rurban
315 // seperate PassUser methods into seperate dir (memory usage)
316 // fix WikiUser (old) overlarge data session
317 // remove wikidb arg from various page class methods, use global ->_dbi instead
318 // ...
319 //
320 // Revision 1.65  2004/10/07 16:08:58  rurban
321 // fixed broken FileUser session handling.
322 //   thanks to Arnaud Fontaine for detecting this.
323 // enable file user Administrator membership.
324 //
325 // Revision 1.64  2004/10/04 23:40:35  rurban
326 // fix nested loops on htmldump errors
327 //
328 // Revision 1.63  2004/09/06 08:22:33  rurban
329 // prevent errorhandler to fail on empty templates
330 //
331 // Revision 1.62  2004/06/28 15:39:27  rurban
332 // fixed endless recursion in WikiGroup: isAdmin()
333 //
334 // Revision 1.61  2004/06/25 14:29:18  rurban
335 // WikiGroup refactoring:
336 //   global group attached to user, code for not_current user.
337 //   improved helpers for special groups (avoid double invocations)
338 // new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
339 // fixed a XHTML validation error on userprefs.tmpl
340 //
341 // Revision 1.60  2004/06/14 11:31:36  rurban
342 // renamed global $Theme to $WikiTheme (gforge nameclash)
343 // inherit PageList default options from PageList
344 //   default sortby=pagename
345 // use options in PageList_Selectable (limit, sortby, ...)
346 // added action revert, with button at action=diff
347 // added option regex to WikiAdminSearchReplace
348 //
349 // Revision 1.59  2004/05/18 16:23:39  rurban
350 // rename split_pagename to SplitPagename
351 //
352 // Revision 1.58  2004/05/15 19:48:33  rurban
353 // fix some too loose PagePerms for signed, but not authenticated users
354 //  (admin, owner, creator)
355 // no double login page header, better login msg.
356 // moved action_pdf to lib/pdf.php
357 //
358 // Revision 1.57  2004/05/01 18:20:05  rurban
359 // Add $charset to template locals (instead of constant CHARSET)
360 //
361 // Revision 1.56  2004/04/12 13:04:50  rurban
362 // added auth_create: self-registering Db users
363 // fixed IMAP auth
364 // removed rating recommendations
365 // ziplib reformatting
366 //
367 // Revision 1.55  2004/04/02 15:06:55  rurban
368 // fixed a nasty ADODB_mysql session update bug
369 // improved UserPreferences layout (tabled hints)
370 // fixed UserPreferences auth handling
371 // improved auth stability
372 // improved old cookie handling: fixed deletion of old cookies with paths
373 //
374 // Revision 1.54  2004/03/02 18:11:39  rurban
375 // CreateToc support: Pass the preparsed markup to each plugin as $dbi->_markup
376 // to be able to know about its context, and even let the plugin change it.
377 // (see CreateToc)
378 //
379 // Revision 1.53  2004/02/22 23:20:31  rurban
380 // fixed DumpHtmlToDir,
381 // enhanced sortby handling in PageList
382 //   new button_heading th style (enabled),
383 // added sortby and limit support to the db backends and plugins
384 //   for paging support (<<prev, next>> links on long lists)
385 //
386 // Revision 1.52  2003/12/20 23:59:19  carstenklapp
387 // Internal change: Added rcs Log tag & emacs php mode tag (sorry, forgot
388 // this in the last commit).
389 //
390
391 // Local Variables:
392 // mode: php
393 // tab-width: 8
394 // c-basic-offset: 4
395 // c-hanging-comment-ender-p: nil
396 // indent-tabs-mode: nil
397 // End:   
398 ?>