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