]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Template.php
include [all] Include and file path should be devided with single space. File path...
[SourceForge/phpwiki.git] / lib / Template.php
1 <?php //-*-php-*-
2
3
4 require_once 'lib/ErrorManager.php';
5
6 /** An HTML template.
7  */
8 class Template
9 {
10     /**
11      * name optionally of form "theme/template" to include parent templates in children
12      */
13     function Template ($name, &$request, $args = false) {
14         global $WikiTheme;
15
16         $this->_request =& $request;
17         $this->_basepage = $request->getArg('pagename');
18
19         if (strstr($name, "/")) {
20             $oldname = $WikiTheme->_name;
21             $oldtheme = $WikiTheme->_theme;
22             list($themename, $name) = explode("/", $name);
23             $WikiTheme->_theme = "themes/$themename";
24             $WikiTheme->_name = $name;
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         if ($fp) 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         // Convert < ?php echo expr ? > to < ?php $this->_print(expr); ? >
64         $orig[] = '/<\?php echo (.*?)\?>/s';
65         $repl[] = '<?php $this->_print(\1);?>';
66
67         return preg_replace($orig, $repl, $template);
68     }
69
70     function _mungePlugin($pi) {
71         // HACK ALERT: PHP's preg_replace, with the /e option seems to
72         // escape both single and double quotes with backslashes.
73         // So we need to unescape the double quotes here...
74
75         $pi = preg_replace('/(?!<\\\\)\\\\"/x', '"', $pi);
76         return sprintf('<?php $this->_printPlugin(%s); ?>',
77                        "'" . str_replace("'", "\'", $pi) . "'");
78     }
79
80     function _printPlugin ($pi) {
81     include_once 'lib/WikiPlugin.php';
82     static $loader;
83
84         if (empty($loader))
85             $loader = new WikiPluginLoader;
86
87         $this->_print($loader->expandPI($pi, $this->_request, $this, $this->_basepage));
88     }
89
90     function _print ($val) {
91         if (isa($val, 'Template')) {
92             $this->_expandSubtemplate($val);
93         } else {
94             PrintXML($val);
95         }
96     }
97
98     function _expandSubtemplate (&$template) {
99         // FIXME: big hack!
100         //if (!$template->_request)
101         //    $template->_request = &$this->_request;
102         if (DEBUG) {
103             echo "<!-- Begin $template->_name -->\n";
104         }
105         // Expand sub-template with defaults from this template.
106         $template->printExpansion($this->_vars);
107         if (DEBUG) {
108             echo "<!-- End $template->_name -->\n";
109         }
110     }
111
112     /**
113      * Substitute HTML replacement text for tokens in template.
114      *
115      * Constructs a new WikiTemplate based upon the named template.
116      *
117      * @access public
118      *
119      * @param $token string Name of token to substitute for.
120      *
121      * @param $replacement string Replacement HTML text.
122      */
123     function replace($varname, $value) {
124         $this->_locals[$varname] = $value;
125     }
126
127
128     function printExpansion ($defaults = false) {
129         if (!is_array($defaults)) // HTML object or template object
130             $defaults = array('CONTENT' => $defaults);
131         $this->_vars = array_merge($defaults, $this->_locals);
132         extract($this->_vars);
133
134         global $request;
135         if (!isset($user))
136             $user = $request->getUser();
137         if (!isset($page))
138             $page = $request->getPage();
139     // Speedup. I checked all templates
140         if (!isset($revision))
141         $revision = false;
142
143         global $WikiTheme, $charset;
144         //$this->_dump_template();
145         $SEP = $WikiTheme->getButtonSeparator();
146
147         global $ErrorManager;
148         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
149
150         eval('?>' . $this->_munge_input($this->_tmpl));
151
152         $ErrorManager->popErrorHandler();
153     }
154
155     // FIXME (1.3.12)
156     // Find a way to do template expansion less memory intensive and faster.
157     // 1.3.4 needed no memory at all for dumphtml, now it needs +15MB.
158     // Smarty? As before?
159     function getExpansion ($defaults = false) {
160         ob_start();
161         $this->printExpansion($defaults);
162         $xml = ob_get_contents();
163         ob_end_clean();     // PHP problem: Doesn't release its memory?
164         return $xml;
165     }
166
167     function printXML () {
168         $this->printExpansion();
169     }
170
171     function asXML () {
172         return $this->getExpansion();
173     }
174
175
176     // Debugging:
177     function _dump_template () {
178         $lines = explode("\n", $this->_munge_input($this->_tmpl));
179         $pre = HTML::pre();
180         $n = 1;
181         foreach ($lines as $line)
182             $pre->pushContent(fmt("%4d  %s\n", $n++, $line));
183         $pre->printXML();
184     }
185
186     function _errorHandler($error) {
187         //if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
188     //    return false;
189
190         if (preg_match('/: eval\(\)\'d code$/', $error->errfile)) {
191             $error->errfile = "In template '$this->_name'";
192             // Hack alert: Ignore 'undefined variable' messages for variables
193             //  whose names are ALL_CAPS.
194             if (preg_match('/Undefined variable:\s*[_A-Z]+\s*$/', $error->errstr))
195                 return true;
196         }
197         // ignore recursively nested htmldump loop: browse -> body -> htmldump -> browse -> body ...
198         // FIXME for other possible loops also
199         elseif (strstr($error->errfile, "In template 'htmldump'")) {
200             ; //return $error;
201         }
202         elseif (strstr($error->errfile, "In template '")) { // merge
203             $error->errfile = preg_replace("/'(\w+)'\)$/", "'\\1' < '$this->_name')",
204                                            $error->errfile);
205         }
206         else {
207             $error->errfile .= " (In template '$this->_name')";
208         }
209
210         if (!empty($this->_tmpl)) {
211             $lines = explode("\n", $this->_tmpl);
212             if (isset($lines[$error->errline - 1]))
213                 $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
214         }
215     return $error;
216     }
217 };
218
219 /**
220  * Get a templates
221  *
222  * This is a convenience function and is equivalent to:
223  * <pre>
224  *   new Template(...)
225  * </pre>
226  */
227 function Template($name, $args = false) {
228     global $request;
229     return new Template($name, $request, $args);
230 }
231
232 function alreadyTemplateProcessed($name) {
233     global $request;
234     return !empty($request->_TemplatesProcessed[$name]) ? true : false;
235 }
236 /**
237  * Make and expand the top-level template.
238  *
239  *
240  * @param $content mixed html content to put into the page
241  * @param $title string page title
242  * @param $page_revision object A WikiDB_PageRevision object or false
243  * @param $args hash Extract args for top-level template
244  *
245  * @return string HTML expansion of template.
246  */
247 function GeneratePage($content, $title, $page_revision = false, $args = false) {
248     global $request;
249
250     if (!is_array($args))
251         $args = array();
252
253     $args['CONTENT'] = $content;
254     $args['TITLE'] = $title;
255     $args['revision'] = $page_revision;
256
257     if (!isset($args['HEADER']))
258         $args['HEADER'] = $title;
259
260     printXML(new Template('html', $request, $args));
261 }
262
263
264 /**
265  * For dumping pages as html to a file.
266  * Used for action=dumphtml,action=ziphtml,format=pdf,format=xml
267  */
268 function GeneratePageasXML($content, $title, $page_revision = false, $args = false) {
269     global $request;
270
271     if (!is_array($args))
272         $args = array();
273
274     $content->_basepage = $title;
275     $args['CONTENT'] = $content;
276     $args['TITLE'] = SplitPagename($title);
277     $args['revision'] = $page_revision;
278
279     if (!isset($args['HEADER']))
280         $args['HEADER'] = SplitPagename($title);
281
282     global $HIDE_TOOLBARS, $NO_BASEHREF, $WikiTheme;
283     $HIDE_TOOLBARS = true;
284     if (!$WikiTheme->DUMP_MODE)
285     $WikiTheme->DUMP_MODE = 'HTML';
286
287     // FIXME: unfatal errors and login requirements
288     $html = asXML(new Template('htmldump', $request, $args));
289
290     $HIDE_TOOLBARS = false;
291     //$WikiTheme->DUMP_MODE = false;
292     return $html;
293 }
294
295 // Local Variables:
296 // mode: php
297 // tab-width: 8
298 // c-basic-offset: 4
299 // c-hanging-comment-ender-p: nil
300 // indent-tabs-mode: nil
301 // End: