|
1 <?php |
|
2 |
|
3 /** |
|
4 * Smarty Internal Plugin Smarty Template Compiler Base |
|
5 * |
|
6 * This file contains the basic classes and methodes for compiling Smarty templates with lexer/parser |
|
7 * |
|
8 * @package Smarty |
|
9 * @subpackage Compiler |
|
10 * @author Uwe Tews |
|
11 */ |
|
12 |
|
13 /** |
|
14 * Main abstract compiler class |
|
15 * |
|
16 * @package Smarty |
|
17 * @subpackage Compiler |
|
18 */ |
|
19 abstract class Smarty_Internal_TemplateCompilerBase { |
|
20 |
|
21 /** |
|
22 * hash for nocache sections |
|
23 * |
|
24 * @var mixed |
|
25 */ |
|
26 private $nocache_hash = null; |
|
27 |
|
28 /** |
|
29 * suppress generation of nocache code |
|
30 * |
|
31 * @var bool |
|
32 */ |
|
33 public $suppressNocacheProcessing = false; |
|
34 |
|
35 /** |
|
36 * suppress generation of merged template code |
|
37 * |
|
38 * @var bool |
|
39 */ |
|
40 public $suppressMergedTemplates = false; |
|
41 |
|
42 /** |
|
43 * compile tag objects |
|
44 * |
|
45 * @var array |
|
46 */ |
|
47 public static $_tag_objects = array(); |
|
48 |
|
49 /** |
|
50 * tag stack |
|
51 * |
|
52 * @var array |
|
53 */ |
|
54 public $_tag_stack = array(); |
|
55 |
|
56 /** |
|
57 * current template |
|
58 * |
|
59 * @var Smarty_Internal_Template |
|
60 */ |
|
61 public $template = null; |
|
62 |
|
63 /** |
|
64 * merged templates |
|
65 * |
|
66 * @var array |
|
67 */ |
|
68 public $merged_templates = array(); |
|
69 |
|
70 /** |
|
71 * flag when compiling {block} |
|
72 * |
|
73 * @var bool |
|
74 */ |
|
75 public $inheritance = false; |
|
76 |
|
77 /** |
|
78 * plugins loaded by default plugin handler |
|
79 * |
|
80 * @var array |
|
81 */ |
|
82 public $default_handler_plugins = array(); |
|
83 |
|
84 /** |
|
85 * saved preprocessed modifier list |
|
86 * |
|
87 * @var mixed |
|
88 */ |
|
89 public $default_modifier_list = null; |
|
90 |
|
91 /** |
|
92 * force compilation of complete template as nocache |
|
93 * @var boolean |
|
94 */ |
|
95 public $forceNocache = false; |
|
96 |
|
97 /** |
|
98 * suppress Smarty header code in compiled template |
|
99 * @var bool |
|
100 */ |
|
101 public $suppressHeader = false; |
|
102 |
|
103 /** |
|
104 * suppress template property header code in compiled template |
|
105 * @var bool |
|
106 */ |
|
107 public $suppressTemplatePropertyHeader = false; |
|
108 |
|
109 /** |
|
110 * flag if compiled template file shall we written |
|
111 * @var bool |
|
112 */ |
|
113 public $write_compiled_code = true; |
|
114 |
|
115 /** |
|
116 * flag if currently a template function is compiled |
|
117 * @var bool |
|
118 */ |
|
119 public $compiles_template_function = false; |
|
120 |
|
121 /** |
|
122 * called subfuntions from template function |
|
123 * @var array |
|
124 */ |
|
125 public $called_functions = array(); |
|
126 |
|
127 /** |
|
128 * flags for used modifier plugins |
|
129 * @var array |
|
130 */ |
|
131 public $modifier_plugins = array(); |
|
132 |
|
133 /** |
|
134 * type of already compiled modifier |
|
135 * @var array |
|
136 */ |
|
137 public $known_modifier_type = array(); |
|
138 |
|
139 /** |
|
140 * Initialize compiler |
|
141 */ |
|
142 public function __construct() { |
|
143 $this->nocache_hash = str_replace('.', '-', uniqid(rand(), true)); |
|
144 } |
|
145 |
|
146 /** |
|
147 * Method to compile a Smarty template |
|
148 * |
|
149 * @param Smarty_Internal_Template $template template object to compile |
|
150 * @return bool true if compiling succeeded, false if it failed |
|
151 */ |
|
152 public function compileTemplate(Smarty_Internal_Template $template) { |
|
153 if (empty($template->properties['nocache_hash'])) { |
|
154 $template->properties['nocache_hash'] = $this->nocache_hash; |
|
155 } else { |
|
156 $this->nocache_hash = $template->properties['nocache_hash']; |
|
157 } |
|
158 // flag for nochache sections |
|
159 $this->nocache = false; |
|
160 $this->tag_nocache = false; |
|
161 // save template object in compiler class |
|
162 $this->template = $template; |
|
163 // reset has noche code flag |
|
164 $this->template->has_nocache_code = false; |
|
165 $this->smarty->_current_file = $saved_filepath = $this->template->source->filepath; |
|
166 // template header code |
|
167 $template_header = ''; |
|
168 if (!$this->suppressHeader) { |
|
169 $template_header .= "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n"; |
|
170 $template_header .= " compiled from \"" . $this->template->source->filepath . "\" */ ?>\n"; |
|
171 } |
|
172 |
|
173 do { |
|
174 // flag for aborting current and start recompile |
|
175 $this->abort_and_recompile = false; |
|
176 // get template source |
|
177 $_content = $template->source->content; |
|
178 // run prefilter if required |
|
179 if (isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) { |
|
180 $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template); |
|
181 } |
|
182 // on empty template just return header |
|
183 if ($_content == '') { |
|
184 if ($this->suppressTemplatePropertyHeader) { |
|
185 $code = ''; |
|
186 } else { |
|
187 $code = $template_header . $template->createTemplateCodeFrame(); |
|
188 } |
|
189 return $code; |
|
190 } |
|
191 // call compiler |
|
192 $_compiled_code = $this->doCompile($_content); |
|
193 } while ($this->abort_and_recompile); |
|
194 $this->template->source->filepath = $saved_filepath; |
|
195 // free memory |
|
196 unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex, $this->template); |
|
197 self::$_tag_objects = array(); |
|
198 // return compiled code to template object |
|
199 $merged_code = ''; |
|
200 if (!$this->suppressMergedTemplates && !empty($this->merged_templates)) { |
|
201 foreach ($this->merged_templates as $code) { |
|
202 $merged_code .= $code; |
|
203 } |
|
204 // run postfilter if required on merged code |
|
205 if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) { |
|
206 $merged_code = Smarty_Internal_Filter_Handler::runFilter('post', $merged_code, $template); |
|
207 } |
|
208 } |
|
209 // run postfilter if required on compiled template code |
|
210 if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) { |
|
211 $_compiled_code = Smarty_Internal_Filter_Handler::runFilter('post', $_compiled_code, $template); |
|
212 } |
|
213 if ($this->suppressTemplatePropertyHeader) { |
|
214 $code = $_compiled_code . $merged_code; |
|
215 } else { |
|
216 $code = $template_header . $template->createTemplateCodeFrame($_compiled_code) . $merged_code; |
|
217 } |
|
218 // unset content because template inheritance could have replace source with parent code |
|
219 unset ($template->source->content); |
|
220 return $code; |
|
221 } |
|
222 |
|
223 /** |
|
224 * Compile Tag |
|
225 * |
|
226 * This is a call back from the lexer/parser |
|
227 * It executes the required compile plugin for the Smarty tag |
|
228 * |
|
229 * @param string $tag tag name |
|
230 * @param array $args array with tag attributes |
|
231 * @param array $parameter array with compilation parameter |
|
232 * @return string compiled code |
|
233 */ |
|
234 public function compileTag($tag, $args, $parameter = array()) { |
|
235 // $args contains the attributes parsed and compiled by the lexer/parser |
|
236 // assume that tag does compile into code, but creates no HTML output |
|
237 $this->has_code = true; |
|
238 $this->has_output = false; |
|
239 // log tag/attributes |
|
240 if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) { |
|
241 $this->template->used_tags[] = array($tag, $args); |
|
242 } |
|
243 // check nocache option flag |
|
244 if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args) |
|
245 || in_array(array('nocache' => '"true"'), $args) || in_array(array('nocache' => "'true'"), $args)) { |
|
246 $this->tag_nocache = true; |
|
247 } |
|
248 // compile the smarty tag (required compile classes to compile the tag are autoloaded) |
|
249 if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) { |
|
250 if (isset($this->smarty->template_functions[$tag])) { |
|
251 // template defined by {template} tag |
|
252 $args['_attr']['name'] = "'" . $tag . "'"; |
|
253 $_output = $this->callTagCompiler('call', $args, $parameter); |
|
254 } |
|
255 } |
|
256 if ($_output !== false) { |
|
257 if ($_output !== true) { |
|
258 // did we get compiled code |
|
259 if ($this->has_code) { |
|
260 // Does it create output? |
|
261 if ($this->has_output) { |
|
262 $_output .= "\n"; |
|
263 } |
|
264 // return compiled code |
|
265 return $_output; |
|
266 } |
|
267 } |
|
268 // tag did not produce compiled code |
|
269 return ''; |
|
270 } else { |
|
271 // map_named attributes |
|
272 if (isset($args['_attr'])) { |
|
273 foreach ($args['_attr'] as $key => $attribute) { |
|
274 if (is_array($attribute)) { |
|
275 $args = array_merge($args, $attribute); |
|
276 } |
|
277 } |
|
278 } |
|
279 // not an internal compiler tag |
|
280 if (strlen($tag) < 6 || substr($tag, -5) != 'close') { |
|
281 // check if tag is a registered object |
|
282 if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_methode'])) { |
|
283 $methode = $parameter['object_methode']; |
|
284 if (!in_array($methode, $this->smarty->registered_objects[$tag][3]) && |
|
285 (empty($this->smarty->registered_objects[$tag][1]) || in_array($methode, $this->smarty->registered_objects[$tag][1]))) { |
|
286 return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $methode); |
|
287 } elseif (in_array($methode, $this->smarty->registered_objects[$tag][3])) { |
|
288 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode); |
|
289 } else { |
|
290 return $this->trigger_template_error('unallowed methode "' . $methode . '" in registered object "' . $tag . '"', $this->lex->taglineno); |
|
291 } |
|
292 } |
|
293 // check if tag is registered |
|
294 foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) { |
|
295 if (isset($this->smarty->registered_plugins[$plugin_type][$tag])) { |
|
296 // if compiler function plugin call it now |
|
297 if ($plugin_type == Smarty::PLUGIN_COMPILER) { |
|
298 $new_args = array(); |
|
299 foreach ($args as $key => $mixed) { |
|
300 if (is_array($mixed)) { |
|
301 $new_args = array_merge($new_args, $mixed); |
|
302 } else { |
|
303 $new_args[$key] = $mixed; |
|
304 } |
|
305 } |
|
306 if (!$this->smarty->registered_plugins[$plugin_type][$tag][1]) { |
|
307 $this->tag_nocache = true; |
|
308 } |
|
309 $function = $this->smarty->registered_plugins[$plugin_type][$tag][0]; |
|
310 if (!is_array($function)) { |
|
311 return $function($new_args, $this); |
|
312 } else if (is_object($function[0])) { |
|
313 return $this->smarty->registered_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this); |
|
314 } else { |
|
315 return call_user_func_array($function, array($new_args, $this)); |
|
316 } |
|
317 } |
|
318 // compile registered function or block function |
|
319 if ($plugin_type == Smarty::PLUGIN_FUNCTION || $plugin_type == Smarty::PLUGIN_BLOCK) { |
|
320 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag); |
|
321 } |
|
322 } |
|
323 } |
|
324 // check plugins from plugins folder |
|
325 foreach ($this->smarty->plugin_search_order as $plugin_type) { |
|
326 if ($plugin_type == Smarty::PLUGIN_BLOCK && $this->smarty->loadPlugin('smarty_compiler_' . $tag) && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) { |
|
327 $plugin = 'smarty_compiler_' . $tag; |
|
328 if (is_callable($plugin)) { |
|
329 // convert arguments format for old compiler plugins |
|
330 $new_args = array(); |
|
331 foreach ($args as $key => $mixed) { |
|
332 if (is_array($mixed)) { |
|
333 $new_args = array_merge($new_args, $mixed); |
|
334 } else { |
|
335 $new_args[$key] = $mixed; |
|
336 } |
|
337 } |
|
338 return $plugin($new_args, $this->smarty); |
|
339 } |
|
340 if (class_exists($plugin, false)) { |
|
341 $plugin_object = new $plugin; |
|
342 if (method_exists($plugin_object, 'compile')) { |
|
343 return $plugin_object->compile($args, $this); |
|
344 } |
|
345 } |
|
346 throw new SmartyException("Plugin \"{$tag}\" not callable"); |
|
347 } else { |
|
348 if ($function = $this->getPlugin($tag, $plugin_type)) { |
|
349 if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { |
|
350 return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function); |
|
351 } |
|
352 } |
|
353 } |
|
354 } |
|
355 if (is_callable($this->smarty->default_plugin_handler_func)) { |
|
356 $found = false; |
|
357 // look for already resolved tags |
|
358 foreach ($this->smarty->plugin_search_order as $plugin_type) { |
|
359 if (isset($this->default_handler_plugins[$plugin_type][$tag])) { |
|
360 $found = true; |
|
361 break; |
|
362 } |
|
363 } |
|
364 if (!$found) { |
|
365 // call default handler |
|
366 foreach ($this->smarty->plugin_search_order as $plugin_type) { |
|
367 if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) { |
|
368 $found = true; |
|
369 break; |
|
370 } |
|
371 } |
|
372 } |
|
373 if ($found) { |
|
374 // if compiler function plugin call it now |
|
375 if ($plugin_type == Smarty::PLUGIN_COMPILER) { |
|
376 $new_args = array(); |
|
377 foreach ($args as $mixed) { |
|
378 $new_args = array_merge($new_args, $mixed); |
|
379 } |
|
380 $function = $this->default_handler_plugins[$plugin_type][$tag][0]; |
|
381 if (!is_array($function)) { |
|
382 return $function($new_args, $this); |
|
383 } else if (is_object($function[0])) { |
|
384 return $this->default_handler_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this); |
|
385 } else { |
|
386 return call_user_func_array($function, array($new_args, $this)); |
|
387 } |
|
388 } else { |
|
389 return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag); |
|
390 } |
|
391 } |
|
392 } |
|
393 } else { |
|
394 // compile closing tag of block function |
|
395 $base_tag = substr($tag, 0, -5); |
|
396 // check if closing tag is a registered object |
|
397 if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_methode'])) { |
|
398 $methode = $parameter['object_methode']; |
|
399 if (in_array($methode, $this->smarty->registered_objects[$base_tag][3])) { |
|
400 return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode); |
|
401 } else { |
|
402 return $this->trigger_template_error('unallowed closing tag methode "' . $methode . '" in registered object "' . $base_tag . '"', $this->lex->taglineno); |
|
403 } |
|
404 } |
|
405 // registered block tag ? |
|
406 if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) || isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) { |
|
407 return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag); |
|
408 } |
|
409 // block plugin? |
|
410 if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) { |
|
411 return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function); |
|
412 } |
|
413 // registered compiler plugin ? |
|
414 if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) { |
|
415 // if compiler function plugin call it now |
|
416 $args = array(); |
|
417 if (!$this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][1]) { |
|
418 $this->tag_nocache = true; |
|
419 } |
|
420 $function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0]; |
|
421 if (!is_array($function)) { |
|
422 return $function($args, $this); |
|
423 } else if (is_object($function[0])) { |
|
424 return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($args, $this); |
|
425 } else { |
|
426 return call_user_func_array($function, array($args, $this)); |
|
427 } |
|
428 } |
|
429 if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) { |
|
430 $plugin = 'smarty_compiler_' . $tag; |
|
431 if (is_callable($plugin)) { |
|
432 return $plugin($args, $this->smarty); |
|
433 } |
|
434 if (class_exists($plugin, false)) { |
|
435 $plugin_object = new $plugin; |
|
436 if (method_exists($plugin_object, 'compile')) { |
|
437 return $plugin_object->compile($args, $this); |
|
438 } |
|
439 } |
|
440 throw new SmartyException("Plugin \"{$tag}\" not callable"); |
|
441 } |
|
442 } |
|
443 $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex->taglineno); |
|
444 } |
|
445 } |
|
446 |
|
447 /** |
|
448 * lazy loads internal compile plugin for tag and calls the compile methode |
|
449 * |
|
450 * compile objects cached for reuse. |
|
451 * class name format: Smarty_Internal_Compile_TagName |
|
452 * plugin filename format: Smarty_Internal_Tagname.php |
|
453 * |
|
454 * @param string $tag tag name |
|
455 * @param array $args list of tag attributes |
|
456 * @param mixed $param1 optional parameter |
|
457 * @param mixed $param2 optional parameter |
|
458 * @param mixed $param3 optional parameter |
|
459 * @return string compiled code |
|
460 */ |
|
461 public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null) { |
|
462 // re-use object if already exists |
|
463 if (isset(self::$_tag_objects[$tag])) { |
|
464 // compile this tag |
|
465 return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); |
|
466 } |
|
467 // lazy load internal compiler plugin |
|
468 $class_name = 'Smarty_Internal_Compile_' . $tag; |
|
469 if ($this->smarty->loadPlugin($class_name)) { |
|
470 // check if tag allowed by security |
|
471 if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { |
|
472 // use plugin if found |
|
473 self::$_tag_objects[$tag] = new $class_name; |
|
474 // compile this tag |
|
475 return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); |
|
476 } |
|
477 } |
|
478 // no internal compile plugin for this tag |
|
479 return false; |
|
480 } |
|
481 |
|
482 /** |
|
483 * Check for plugins and return function name |
|
484 * |
|
485 * @param string $pugin_name name of plugin or function |
|
486 * @param string $plugin_type type of plugin |
|
487 * @return string call name of function |
|
488 */ |
|
489 public function getPlugin($plugin_name, $plugin_type) { |
|
490 $function = null; |
|
491 if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { |
|
492 if (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) { |
|
493 $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function']; |
|
494 } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) { |
|
495 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type] = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]; |
|
496 $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function']; |
|
497 } |
|
498 } else { |
|
499 if (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) { |
|
500 $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function']; |
|
501 } else if (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) { |
|
502 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type] = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]; |
|
503 $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function']; |
|
504 } |
|
505 } |
|
506 if (isset($function)) { |
|
507 if ($plugin_type == 'modifier') { |
|
508 $this->modifier_plugins[$plugin_name] = true; |
|
509 } |
|
510 return $function; |
|
511 } |
|
512 // loop through plugin dirs and find the plugin |
|
513 $function = 'smarty_' . $plugin_type . '_' . $plugin_name; |
|
514 $file = $this->smarty->loadPlugin($function, false); |
|
515 |
|
516 if (is_string($file)) { |
|
517 if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { |
|
518 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['file'] = $file; |
|
519 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function'] = $function; |
|
520 } else { |
|
521 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] = $file; |
|
522 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] = $function; |
|
523 } |
|
524 if ($plugin_type == 'modifier') { |
|
525 $this->modifier_plugins[$plugin_name] = true; |
|
526 } |
|
527 return $function; |
|
528 } |
|
529 if (is_callable($function)) { |
|
530 // plugin function is defined in the script |
|
531 return $function; |
|
532 } |
|
533 return false; |
|
534 } |
|
535 |
|
536 /** |
|
537 * Check for plugins by default plugin handler |
|
538 * |
|
539 * @param string $tag name of tag |
|
540 * @param string $plugin_type type of plugin |
|
541 * @return boolean true if found |
|
542 */ |
|
543 public function getPluginFromDefaultHandler($tag, $plugin_type) { |
|
544 $callback = null; |
|
545 $script = null; |
|
546 $cacheable = true; |
|
547 $result = call_user_func_array( |
|
548 $this->smarty->default_plugin_handler_func, array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable) |
|
549 ); |
|
550 if ($result) { |
|
551 $this->tag_nocache = $this->tag_nocache || !$cacheable; |
|
552 if ($script !== null) { |
|
553 if (is_file($script)) { |
|
554 if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { |
|
555 $this->template->required_plugins['nocache'][$tag][$plugin_type]['file'] = $script; |
|
556 $this->template->required_plugins['nocache'][$tag][$plugin_type]['function'] = $callback; |
|
557 } else { |
|
558 $this->template->required_plugins['compiled'][$tag][$plugin_type]['file'] = $script; |
|
559 $this->template->required_plugins['compiled'][$tag][$plugin_type]['function'] = $callback; |
|
560 } |
|
561 include_once $script; |
|
562 } else { |
|
563 $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found"); |
|
564 } |
|
565 } |
|
566 if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) { |
|
567 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name"); |
|
568 } |
|
569 if (is_callable($callback)) { |
|
570 $this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array()); |
|
571 return true; |
|
572 } else { |
|
573 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable"); |
|
574 } |
|
575 } |
|
576 return false; |
|
577 } |
|
578 |
|
579 /** |
|
580 * Inject inline code for nocache template sections |
|
581 * |
|
582 * This method gets the content of each template element from the parser. |
|
583 * If the content is compiled code and it should be not cached the code is injected |
|
584 * into the rendered output. |
|
585 * |
|
586 * @param string $content content of template element |
|
587 * @param boolean $is_code true if content is compiled code |
|
588 * @return string content |
|
589 */ |
|
590 public function processNocacheCode($content, $is_code) { |
|
591 // If the template is not evaluated and we have a nocache section and or a nocache tag |
|
592 if ($is_code && !empty($content)) { |
|
593 // generate replacement code |
|
594 if ((!($this->template->source->recompiled) || $this->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing && |
|
595 ($this->nocache || $this->tag_nocache || $this->forceNocache == 2)) { |
|
596 $this->template->has_nocache_code = true; |
|
597 $_output = addcslashes($content,'\'\\'); |
|
598 $_output = str_replace("^#^", "'", $_output); |
|
599 $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n"; |
|
600 // make sure we include modifer plugins for nocache code |
|
601 foreach ($this->modifier_plugins as $plugin_name => $dummy) { |
|
602 if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) { |
|
603 $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier']; |
|
604 } |
|
605 } |
|
606 } else { |
|
607 $_output = $content; |
|
608 } |
|
609 } else { |
|
610 $_output = $content; |
|
611 } |
|
612 $this->modifier_plugins = array(); |
|
613 $this->suppressNocacheProcessing = false; |
|
614 $this->tag_nocache = false; |
|
615 return $_output; |
|
616 } |
|
617 |
|
618 /** |
|
619 * display compiler error messages without dying |
|
620 * |
|
621 * If parameter $args is empty it is a parser detected syntax error. |
|
622 * In this case the parser is called to obtain information about expected tokens. |
|
623 * |
|
624 * If parameter $args contains a string this is used as error message |
|
625 * |
|
626 * @param string $args individual error message or null |
|
627 * @param string $line line-number |
|
628 * @throws SmartyCompilerException when an unexpected token is found |
|
629 */ |
|
630 public function trigger_template_error($args = null, $line = null) { |
|
631 // get template source line which has error |
|
632 if (!isset($line)) { |
|
633 $line = $this->lex->line; |
|
634 } |
|
635 $match = preg_split("/\n/", $this->lex->data); |
|
636 $error_text = 'Syntax Error in template "' . $this->template->source->filepath . '" on line ' . $line . ' "' . htmlspecialchars(trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1]))) . '" '; |
|
637 if (isset($args)) { |
|
638 // individual error message |
|
639 $error_text .= $args; |
|
640 } else { |
|
641 // expected token from parser |
|
642 $error_text .= ' - Unexpected "' . $this->lex->value . '"'; |
|
643 if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) { |
|
644 foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) { |
|
645 $exp_token = $this->parser->yyTokenName[$token]; |
|
646 if (isset($this->lex->smarty_token_names[$exp_token])) { |
|
647 // token type from lexer |
|
648 $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"'; |
|
649 } else { |
|
650 // otherwise internal token name |
|
651 $expect[] = $this->parser->yyTokenName[$token]; |
|
652 } |
|
653 } |
|
654 $error_text .= ', expected one of: ' . implode(' , ', $expect); |
|
655 } |
|
656 } |
|
657 throw new SmartyCompilerException($error_text); |
|
658 } |
|
659 |
|
660 } |
|
661 |
|
662 ?> |