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