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