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