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