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