Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/*** Smarty Internal Plugin Smarty Template Compiler Base* This file contains the basic classes and methods for compiling Smarty templates with lexer/parser** @package Smarty* @subpackage Compiler* @author Uwe Tews*//*** Main abstract compiler class** @package Smarty* @subpackage Compiler** @property Smarty_Internal_SmartyTemplateCompiler $prefixCompiledCode = ''* @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = ''* @method registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false)* @method unregisterPostCompileCallback($key)*/abstract class Smarty_Internal_TemplateCompilerBase{/*** compile tag objects cache** @var array*/public static $_tag_objects = array();/*** counter for prefix variable number** @var int*/public static $prefixVariableNumber = 0;/*** Smarty object** @var Smarty*/public $smarty = null;/*** Parser object** @var Smarty_Internal_Templateparser*/public $parser = null;/*** hash for nocache sections** @var mixed*/public $nocache_hash = null;/*** suppress generation of nocache code** @var bool*/public $suppressNocacheProcessing = false;/*** caching enabled (copied from template object)** @var int*/public $caching = 0;/*** tag stack** @var array*/public $_tag_stack = array();/*** tag stack count** @var array*/public $_tag_stack_count = array();/*** Plugins used by template** @var array*/public $required_plugins = array('compiled' => array(), 'nocache' => array());/*** Required plugins stack** @var array*/public $required_plugins_stack = array();/*** current template** @var Smarty_Internal_Template*/public $template = null;/*** merged included sub template data** @var array*/public $mergedSubTemplatesData = array();/*** merged sub template code** @var array*/public $mergedSubTemplatesCode = array();/*** collected template properties during compilation** @var array*/public $templateProperties = array();/*** source line offset for error messages** @var int*/public $trace_line_offset = 0;/*** trace uid** @var string*/public $trace_uid = '';/*** trace file path** @var string*/public $trace_filepath = '';/*** stack for tracing file and line of nested {block} tags** @var array*/public $trace_stack = array();/*** plugins loaded by default plugin handler** @var array*/public $default_handler_plugins = array();/*** saved preprocessed modifier list** @var mixed*/public $default_modifier_list = null;/*** force compilation of complete template as nocache** @var boolean*/public $forceNocache = false;/*** flag if compiled template file shall we written** @var bool*/public $write_compiled_code = true;/*** Template functions** @var array*/public $tpl_function = array();/*** called sub functions from template function** @var array*/public $called_functions = array();/*** compiled template or block function code** @var string*/public $blockOrFunctionCode = '';/*** flags for used modifier plugins** @var array*/public $modifier_plugins = array();/*** type of already compiled modifier** @var array*/public $known_modifier_type = array();/*** parent compiler object for merged subtemplates and template functions** @var Smarty_Internal_TemplateCompilerBase*/public $parent_compiler = null;/*** Flag true when compiling nocache section** @var bool*/public $nocache = false;/*** Flag true when tag is compiled as nocache** @var bool*/public $tag_nocache = false;/*** Compiled tag prefix code** @var array*/public $prefix_code = array();/*** used prefix variables by current compiled tag** @var array*/public $usedPrefixVariables = array();/*** Prefix code stack** @var array*/public $prefixCodeStack = array();/*** Tag has compiled code** @var bool*/public $has_code = false;/*** A variable string was compiled** @var bool*/public $has_variable_string = false;/*** Stack for {setfilter} {/setfilter}** @var array*/public $variable_filter_stack = array();/*** variable filters for {setfilter} {/setfilter}** @var array*/public $variable_filters = array();/*** Nesting count of looping tags like {foreach}, {for}, {section}, {while}** @var int*/public $loopNesting = 0;/*** Strip preg pattern** @var string*/public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';/*** plugin search order** @var array*/public $plugin_search_order = array('function','block','compiler','class');/*** General storage area for tag compiler plugins** @var array*/public $_cache = array();/*** Lexer preg pattern for left delimiter** @var string*/private $ldelPreg = '[{]';/*** Lexer preg pattern for right delimiter** @var string*/private $rdelPreg = '[}]';/*** Length of right delimiter** @var int*/private $rdelLength = 0;/*** Length of left delimiter** @var int*/private $ldelLength = 0;/*** Lexer preg pattern for user literals** @var string*/private $literalPreg = '';/*** Initialize compiler** @param Smarty $smarty global instance*/public function __construct(Smarty $smarty){$this->smarty = $smarty;$this->nocache_hash = str_replace(array('.',','),'_',uniqid(mt_rand(), true));}/*** Method to compile a Smarty template** @param Smarty_Internal_Template $template template object to compile* @param bool $nocache true is shall be compiled in nocache mode* @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler** @return bool true if compiling succeeded, false if it failed* @throws \Exception*/public function compileTemplate(Smarty_Internal_Template $template,$nocache = null,Smarty_Internal_TemplateCompilerBase $parent_compiler = null) {// get code frame of compiled template$_compiled_code = $template->smarty->ext->_codeFrame->create($template,$this->compileTemplateSource($template,$nocache,$parent_compiler),$this->postFilter($this->blockOrFunctionCode) .join('', $this->mergedSubTemplatesCode),false,$this);return $_compiled_code;}/*** Compile template source and run optional post filter** @param \Smarty_Internal_Template $template* @param null|bool $nocache flag if template must be compiled in nocache mode* @param \Smarty_Internal_TemplateCompilerBase $parent_compiler** @return string* @throws \Exception*/public function compileTemplateSource(Smarty_Internal_Template $template,$nocache = null,Smarty_Internal_TemplateCompilerBase $parent_compiler = null) {try {// save template object in compiler class$this->template = $template;if ($this->smarty->debugging) {if (!isset($this->smarty->_debug)) {$this->smarty->_debug = new Smarty_Internal_Debug();}$this->smarty->_debug->start_compile($this->template);}$this->parent_compiler = $parent_compiler ? $parent_compiler : $this;$nocache = isset($nocache) ? $nocache : false;if (empty($template->compiled->nocache_hash)) {$template->compiled->nocache_hash = $this->nocache_hash;} else {$this->nocache_hash = $template->compiled->nocache_hash;}$this->caching = $template->caching;// flag for nocache sections$this->nocache = $nocache;$this->tag_nocache = false;// reset has nocache code flag$this->template->compiled->has_nocache_code = false;$this->has_variable_string = false;$this->prefix_code = array();// add file dependencyif ($this->smarty->merge_compiled_includes || $this->template->source->handler->checkTimestamps()) {$this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =array($this->template->source->filepath,$this->template->source->getTimeStamp(),$this->template->source->type,);}$this->smarty->_current_file = $this->template->source->filepath;// get template sourceif (!empty($this->template->source->components)) {// we have array of inheritance templates by extends: resource// generate corresponding source code sequence$_content =Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template);} else {// get template source$_content = $this->template->source->getContent();}$_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true));if (!empty($this->required_plugins[ 'compiled' ]) || !empty($this->required_plugins[ 'nocache' ])) {$_compiled_code = '<?php ' . $this->compileRequiredPlugins() . "?>\n" . $_compiled_code;}} catch (Exception $e) {if ($this->smarty->debugging) {$this->smarty->_debug->end_compile($this->template);}$this->_tag_stack = array();// free memory$this->parent_compiler = null;$this->template = null;$this->parser = null;throw $e;}if ($this->smarty->debugging) {$this->smarty->_debug->end_compile($this->template);}$this->parent_compiler = null;$this->parser = null;return $_compiled_code;}/*** Optionally process compiled code by post filter** @param string $code compiled code** @return string* @throws \SmartyException*/public function postFilter($code){// run post filter if on codeif (!empty($code)&& (isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ]))) {return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template);} else {return $code;}}/*** Run optional prefilter** @param string $_content template source** @return string* @throws \SmartyException*/public function preFilter($_content){// run pre filter if requiredif ($_content !== ''&& ((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ])))) {return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template);} else {return $_content;}}/*** Compile Tag* This is a call back from the lexer/parser** Save current prefix code* Compile tag* Merge tag prefix code with saved one* (required nested tags in attributes)** @param string $tag tag name* @param array $args array with tag attributes* @param array $parameter array with compilation parameter** @throws SmartyCompilerException* @throws SmartyException* @return string compiled code*/public function compileTag($tag, $args, $parameter = array()){$this->prefixCodeStack[] = $this->prefix_code;$this->prefix_code = array();$result = $this->compileTag2($tag, $args, $parameter);$this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));return $result;}/*** compile variable** @param string $variable** @return string*/public function compileVariable($variable){if (!strpos($variable, '(')) {// not a variable variable$var = trim($variable, '\'');$this->tag_nocache = $this->tag_nocache |$this->template->ext->getTemplateVars->_getVariable($this->template,$var,null,true,false)->nocache;// todo $this->template->compiled->properties['variables'][$var] = $this->tag_nocache | $this->nocache;}return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';}/*** compile config variable** @param string $variable** @return string*/public function compileConfigVariable($variable){// return '$_smarty_tpl->config_vars[' . $variable . ']';return '$_smarty_tpl->smarty->ext->configLoad->_getConfigVariable($_smarty_tpl, ' . $variable . ')';}/*** compile PHP function call** @param string $name* @param array $parameter** @return string* @throws \SmartyCompilerException*/public function compilePHPFunctionCall($name, $parameter){if (!$this->smarty->security_policy || $this->smarty->security_policy->isTrustedPhpFunction($name, $this)) {if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0|| strcasecmp($name, 'array') === 0 || is_callable($name)) {$func_name = smarty_strtolower_ascii($name);if ($func_name === 'isset') {if (count($parameter) === 0) {$this->trigger_template_error('Illegal number of parameter in "isset()"');}$pa = array();foreach ($parameter as $p) {$pa[] = $this->syntaxMatchesVariable($p) ? 'isset(' . $p . ')' : '(' . $p . ' !== null )';}return '(' . implode(' && ', $pa) . ')';} elseif (in_array($func_name,array('empty','reset','current','end','prev','next'))) {if (count($parameter) !== 1) {$this->trigger_template_error("Illegal number of parameter in '{$func_name()}'");}if ($func_name === 'empty') {return $func_name . '(' .str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')';} else {return $func_name . '(' . $parameter[ 0 ] . ')';}} else {return $name . '(' . implode(',', $parameter) . ')';}} else {$this->trigger_template_error("unknown function '{$name}'");}}}/*** Determines whether the passed string represents a valid (PHP) variable.* This is important, because `isset()` only works on variables and `empty()` can only be passed* a variable prior to php5.5* @param $string* @return bool*/private function syntaxMatchesVariable($string) {static $regex_pattern = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\[.*]*\])*$/';return 1 === preg_match($regex_pattern, trim($string));}/*** This method is called from parser to process a text content section if strip is enabled* - remove text from inheritance child templates as they may generate output** @param string $text** @return string*/public function processText($text){if (strpos($text, '<') === false) {return preg_replace($this->stripRegEx, '', $text);}$store = array();$_store = 0;// capture html elements not to be messed with$_offset = 0;if (preg_match_all('#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',$text,$matches,PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {foreach ($matches as $match) {$store[] = $match[ 0 ][ 0 ];$_length = strlen($match[ 0 ][ 0 ]);$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);$_offset += $_length - strlen($replace);$_store++;}}$expressions = array(// replace multiple spaces between tags by a single space'#(:SMARTY@!@|>)[\040\011]+(?=@!@SMARTY:|<)#s' => '\1 \2',// remove newline between tags'#(:SMARTY@!@|>)[\040\011]*[\n]\s*(?=@!@SMARTY:|<)#s' => '\1\2',// remove multiple spaces between attributes (but not in attribute values!)'#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5','#>[\040\011]+$#Ss' => '> ','#>[\040\011]*[\n]\s*$#Ss' => '>',$this->stripRegEx => '',);$text = preg_replace(array_keys($expressions), array_values($expressions), $text);$_offset = 0;if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is',$text,$matches,PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {foreach ($matches as $match) {$_length = strlen($match[ 0 ][ 0 ]);$replace = $store[ $match[ 1 ][ 0 ] ];$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);$_offset += strlen($replace) - $_length;$_store++;}}return $text;}/*** lazy loads internal compile plugin for tag and calls the compile method* compile objects cached for reuse.* class name format: Smarty_Internal_Compile_TagName* plugin filename format: Smarty_Internal_TagName.php** @param string $tag tag name* @param array $args list of tag attributes* @param mixed $param1 optional parameter* @param mixed $param2 optional parameter* @param mixed $param3 optional parameter** @return bool|string compiled code or false* @throws \SmartyCompilerException*/public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null){/* @var Smarty_Internal_CompileBase $tagCompiler */$tagCompiler = $this->getTagCompiler($tag);// compile this tagreturn $tagCompiler === false ? false : $tagCompiler->compile($args, $this, $param1, $param2, $param3);}/*** lazy loads internal compile plugin for tag compile objects cached for reuse.** class name format: Smarty_Internal_Compile_TagName* plugin filename format: Smarty_Internal_TagName.php** @param string $tag tag name** @return bool|\Smarty_Internal_CompileBase tag compiler object or false if not found*/public function getTagCompiler($tag){// re-use object if already existsif (!isset(self::$_tag_objects[ $tag ])) {// lazy load internal compiler plugin$_tag = explode('_', $tag);$_tag = array_map('smarty_ucfirst_ascii', $_tag);$class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);if (class_exists($class_name)&& (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) {self::$_tag_objects[ $tag ] = new $class_name;} else {self::$_tag_objects[ $tag ] = false;}}return self::$_tag_objects[ $tag ];}/*** Check for plugins and return function name** @param $plugin_name* @param string $plugin_type type of plugin** @return string call name of function* @throws \SmartyException*/public function getPlugin($plugin_name, $plugin_type){$function = null;if ($this->caching && ($this->nocache || $this->tag_nocache)) {if (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {$function =$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];} elseif (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] =$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ];$function =$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];}} else {if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {$function =$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];} elseif (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] =$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ];$function =$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];}}if (isset($function)) {if ($plugin_type === 'modifier') {$this->modifier_plugins[ $plugin_name ] = true;}return $function;}// loop through plugin dirs and find the plugin$function = 'smarty_' . $plugin_type . '_' . $plugin_name;$file = $this->smarty->loadPlugin($function, false);if (is_string($file)) {if ($this->caching && ($this->nocache || $this->tag_nocache)) {$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] =$file;$this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] =$function;} else {$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] =$file;$this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] =$function;}if ($plugin_type === 'modifier') {$this->modifier_plugins[ $plugin_name ] = true;}return $function;}if (is_callable($function)) {// plugin function is defined in the scriptreturn $function;}return false;}/*** Check for plugins by default plugin handler** @param string $tag name of tag* @param string $plugin_type type of plugin** @return bool true if found* @throws \SmartyCompilerException*/public function getPluginFromDefaultHandler($tag, $plugin_type){$callback = null;$script = null;$cacheable = true;$result = call_user_func_array($this->smarty->default_plugin_handler_func,array($tag,$plugin_type,$this->template,&$callback,&$script,&$cacheable,));if ($result) {$this->tag_nocache = $this->tag_nocache || !$cacheable;if ($script !== null) {if (is_file($script)) {if ($this->caching && ($this->nocache || $this->tag_nocache)) {$this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] =$script;$this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] =$callback;} else {$this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] =$script;$this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] =$callback;}include_once $script;} else {$this->trigger_template_error("Default plugin handler: Returned script file '{$script}' for '{$tag}' not found");}}if (is_callable($callback)) {$this->default_handler_plugins[ $plugin_type ][ $tag ] = array($callback,true,array());return true;} else {$this->trigger_template_error("Default plugin handler: Returned callback for '{$tag}' not callable");}}return false;}/*** Append code segments and remove unneeded ?> <?php transitions** @param string $left* @param string $right** @return string*/public function appendCode($left, $right){if (preg_match('/\s*\?>\s?$/D', $left) && preg_match('/^<\?php\s+/', $right)) {$left = preg_replace('/\s*\?>\s?$/D', "\n", $left);$left .= preg_replace('/^<\?php\s+/', '', $right);} else {$left .= $right;}return $left;}/*** Inject inline code for nocache template sections* This method gets the content of each template element from the parser.* If the content is compiled code and it should be not cached the code is injected* into the rendered output.** @param string $content content of template element* @param boolean $is_code true if content is compiled code** @return string content*/public function processNocacheCode($content, $is_code){// If the template is not evaluated and we have a nocache section and or a nocache tagif ($is_code && !empty($content)) {// generate replacement codeif ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->caching&& !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)) {$this->template->compiled->has_nocache_code = true;$_output = addcslashes($content, '\'\\');$_output = str_replace('^#^', '\'', $_output);$_output ="<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/{$_output}/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";// make sure we include modifier plugins for nocache codeforeach ($this->modifier_plugins as $plugin_name => $dummy) {if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) {$this->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] =$this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ];}}} else {$_output = $content;}} else {$_output = $content;}$this->modifier_plugins = array();$this->suppressNocacheProcessing = false;$this->tag_nocache = false;return $_output;}/*** Get Id** @param string $input** @return bool|string*/public function getId($input){if (preg_match('~^([\'"]*)([0-9]*[a-zA-Z_]\w*)\1$~', $input, $match)) {return $match[ 2 ];}return false;}/*** Get variable name from string** @param string $input** @return bool|string*/public function getVariableName($input){if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {return $match[ 1 ];}return false;}/*** Set nocache flag in variable or create new variable** @param string $varName*/public function setNocacheInVariable($varName){// create nocache var to make it know for further compilingif ($_var = $this->getId($varName)) {if (isset($this->template->tpl_vars[ $_var ])) {$this->template->tpl_vars[ $_var ] = clone $this->template->tpl_vars[ $_var ];$this->template->tpl_vars[ $_var ]->nocache = true;} else {$this->template->tpl_vars[ $_var ] = new Smarty_Variable(null, true);}}}/*** @param array $_attr tag attributes* @param array $validScopes** @return int|string* @throws \SmartyCompilerException*/public function convertScope($_attr, $validScopes){$_scope = 0;if (isset($_attr[ 'scope' ])) {$_scopeName = trim($_attr[ 'scope' ], '\'"');if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {$_scope = $_scopeName;} elseif (is_string($_scopeName)) {$_scopeName = trim($_scopeName, '\'"');$_scope = isset($validScopes[ $_scopeName ]) ? $validScopes[ $_scopeName ] : false;} else {$_scope = false;}if ($_scope === false) {$err = var_export($_scopeName, true);$this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);}}return $_scope;}/*** Generate nocache code string** @param string $code PHP code** @return string*/public function makeNocacheCode($code){return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " .str_replace('^#^', '\'', addcslashes($code, '\'\\')) ."?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";}/*** display compiler error messages without dying* If parameter $args is empty it is a parser detected syntax error.* In this case the parser is called to obtain information about expected tokens.* If parameter $args contains a string this is used as error message** @param string $args individual error message or null* @param string $line line-number* @param null|bool $tagline if true the line number of last tag** @throws \SmartyCompilerException when an unexpected token is found*/public function trigger_template_error($args = null, $line = null, $tagline = null){$lex = $this->parser->lex;if ($tagline === true) {// get line number of Tag$line = $lex->taglineno;} elseif (!isset($line)) {// get template source line which has error$line = $lex->line;} else {$line = (int)$line;}if (in_array($this->template->source->type,array('eval','string'))) {$templateName = $this->template->source->type . ':' . trim(preg_replace('![\t\r\n]+!',' ',strlen($lex->data) > 40 ?substr($lex->data, 0, 40) .'...' : $lex->data));} else {$templateName = $this->template->source->type . ':' . $this->template->source->filepath;}// $line += $this->trace_line_offset;$match = preg_split("/\n/", $lex->data);$error_text ='Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) .'" on line ' . ($line + $this->trace_line_offset) . ' "' .trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" ';if (isset($args)) {// individual error message$error_text .= $args;} else {$expect = array();// expected token from parser$error_text .= ' - Unexpected "' . $lex->value . '"';if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {$exp_token = $this->parser->yyTokenName[ $token ];if (isset($lex->smarty_token_names[ $exp_token ])) {// token type from lexer$expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"';} else {// otherwise internal token name$expect[] = $this->parser->yyTokenName[ $token ];}}$error_text .= ', expected one of: ' . implode(' , ', $expect);}}if ($this->smarty->_parserdebug) {$this->parser->errorRunDown();echo ob_get_clean();flush();}$e = new SmartyCompilerException($error_text,0,$this->template->source->filepath,$line);$e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));$e->desc = $args;$e->template = $this->template->source->filepath;throw $e;}/*** Return var_export() value with all white spaces removed** @param mixed $value** @return string*/public function getVarExport($value){return preg_replace('/\s/', '', var_export($value, true));}/*** enter double quoted string* - save tag stack count*/public function enterDoubleQuote(){array_push($this->_tag_stack_count, $this->getTagStackCount());}/*** Return tag stack count** @return int*/public function getTagStackCount(){return count($this->_tag_stack);}/*** @param $lexerPreg** @return mixed*/public function replaceDelimiter($lexerPreg){return str_replace(array('SMARTYldel', 'SMARTYliteral', 'SMARTYrdel', 'SMARTYautoliteral', 'SMARTYal'),array($this->ldelPreg, $this->literalPreg, $this->rdelPreg,$this->smarty->getAutoLiteral() ? '{1,}' : '{9}',$this->smarty->getAutoLiteral() ? '' : '\\s*'),$lexerPreg);}/*** Build lexer regular expressions for left and right delimiter and user defined literals*/public function initDelimiterPreg(){$ldel = $this->smarty->getLeftDelimiter();$this->ldelLength = strlen($ldel);$this->ldelPreg = '';foreach (str_split($ldel, 1) as $chr) {$this->ldelPreg .= '[' . preg_quote($chr,'/') . ']';}$rdel = $this->smarty->getRightDelimiter();$this->rdelLength = strlen($rdel);$this->rdelPreg = '';foreach (str_split($rdel, 1) as $chr) {$this->rdelPreg .= '[' . preg_quote($chr,'/') . ']';}$literals = $this->smarty->getLiterals();if (!empty($literals)) {foreach ($literals as $key => $literal) {$literalPreg = '';foreach (str_split($literal, 1) as $chr) {$literalPreg .= '[' . preg_quote($chr,'/') . ']';}$literals[ $key ] = $literalPreg;}$this->literalPreg = '|' . implode('|', $literals);} else {$this->literalPreg = '';}}/*** leave double quoted string* - throw exception if block in string was not closed** @throws \SmartyCompilerException*/public function leaveDoubleQuote(){if (array_pop($this->_tag_stack_count) !== $this->getTagStackCount()) {$tag = $this->getOpenBlockTag();$this->trigger_template_error("unclosed '{{$tag}}' in doubled quoted string",null,true);}}/*** Get left delimiter preg** @return string*/public function getLdelPreg(){return $this->ldelPreg;}/*** Get right delimiter preg** @return string*/public function getRdelPreg(){return $this->rdelPreg;}/*** Get length of left delimiter** @return int*/public function getLdelLength(){return $this->ldelLength;}/*** Get length of right delimiter** @return int*/public function getRdelLength(){return $this->rdelLength;}/*** Get name of current open block tag** @return string|boolean*/public function getOpenBlockTag(){$tagCount = $this->getTagStackCount();if ($tagCount) {return $this->_tag_stack[ $tagCount - 1 ][ 0 ];} else {return false;}}/*** Check if $value contains variable elements** @param mixed $value** @return bool|int*/public function isVariable($value){if (is_string($value)) {return preg_match('/[$(]/', $value);}if (is_bool($value) || is_numeric($value)) {return false;}if (is_array($value)) {foreach ($value as $k => $v) {if ($this->isVariable($k) || $this->isVariable($v)) {return true;}}return false;}return false;}/*** Get new prefix variable name** @return string*/public function getNewPrefixVariable(){++self::$prefixVariableNumber;return $this->getPrefixVariable();}/*** Get current prefix variable name** @return string*/public function getPrefixVariable(){return '$_prefixVariable' . self::$prefixVariableNumber;}/*** append code to prefix buffer** @param string $code*/public function appendPrefixCode($code){$this->prefix_code[] = $code;}/*** get prefix code string** @return string*/public function getPrefixCode(){$code = '';$prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));$this->prefixCodeStack[] = array();foreach ($prefixArray as $c) {$code = $this->appendCode($code, $c);}$this->prefix_code = array();return $code;}/*** Save current required plugins** @param bool $init if true init required plugins*/public function saveRequiredPlugins($init = false){$this->required_plugins_stack[] = $this->required_plugins;if ($init) {$this->required_plugins = array('compiled' => array(), 'nocache' => array());}}/*** Restore required plugins*/public function restoreRequiredPlugins(){$this->required_plugins = array_pop($this->required_plugins_stack);}/*** Compile code to call Smarty_Internal_Template::_checkPlugins()* for required plugins** @return string*/public function compileRequiredPlugins(){$code = $this->compileCheckPlugins($this->required_plugins[ 'compiled' ]);if ($this->caching && !empty($this->required_plugins[ 'nocache' ])) {$code .= $this->makeNocacheCode($this->compileCheckPlugins($this->required_plugins[ 'nocache' ]));}return $code;}/*** Compile code to call Smarty_Internal_Template::_checkPlugins* - checks if plugin is callable require otherwise** @param $requiredPlugins** @return string*/public function compileCheckPlugins($requiredPlugins){if (!empty($requiredPlugins)) {$plugins = array();foreach ($requiredPlugins as $plugin) {foreach ($plugin as $data) {$plugins[] = $data;}}return '$_smarty_tpl->_checkPlugins(' . $this->getVarExport($plugins) . ');' . "\n";} else {return '';}}/*** method to compile a Smarty template** @param mixed $_content template source* @param bool $isTemplateSource** @return bool true if compiling succeeded, false if it failed*/abstract protected function doCompile($_content, $isTemplateSource = false);public function cStyleComment($string) {return '/*' . str_replace('*/', '* /' , $string) . '*/';}/*** Compile Tag** @param string $tag tag name* @param array $args array with tag attributes* @param array $parameter array with compilation parameter** @throws SmartyCompilerException* @throws SmartyException* @return string compiled code*/private function compileTag2($tag, $args, $parameter){$plugin_type = '';// $args contains the attributes parsed and compiled by the lexer/parser// assume that tag does compile into code, but creates no HTML output$this->has_code = true;// log tag/attributesif (isset($this->smarty->_cache[ 'get_used_tags' ])) {$this->template->_cache[ 'used_tags' ][] = array($tag,$args);}// check nocache option flagforeach ($args as $arg) {if (!is_array($arg)) {if ($arg === "'nocache'" || $arg === 'nocache') {$this->tag_nocache = true;}} else {foreach ($arg as $k => $v) {if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") === 'true')) {$this->tag_nocache = true;}}}}// compile the smarty tag (required compile classes to compile the tag are auto loaded)if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {if (isset($this->parent_compiler->tpl_function[ $tag ])|| (isset($this->template->smarty->ext->_tplFunction)&& $this->template->smarty->ext->_tplFunction->getTplFunction($this->template, $tag) !== false)) {// template defined by {template} tag$args[ '_attr' ][ 'name' ] = "'{$tag}'";$_output = $this->callTagCompiler('call', $args, $parameter);}}if ($_output !== false) {if ($_output !== true) {// did we get compiled codeif ($this->has_code) {// return compiled codereturn $_output;}}// tag did not produce compiled codereturn null;} else {// map_named attributesif (isset($args[ '_attr' ])) {foreach ($args[ '_attr' ] as $key => $attribute) {if (is_array($attribute)) {$args = array_merge($args, $attribute);}}}// not an internal compiler tagif (strlen($tag) < 6 || substr($tag, -5) !== 'close') {// check if tag is a registered objectif (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) {$method = $parameter[ 'object_method' ];if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])&& (empty($this->smarty->registered_objects[ $tag ][ 1 ])|| in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ]))) {return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);} elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) {return $this->callTagCompiler('private_object_block_function',$args,$parameter,$tag,$method);} else {// throw exception$this->trigger_template_error('not allowed method "' . $method . '" in registered object "' .$tag . '"',null,true);}}// check if tag is registeredforeach (array(Smarty::PLUGIN_COMPILER,Smarty::PLUGIN_FUNCTION,Smarty::PLUGIN_BLOCK,) as $plugin_type) {if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {// if compiler function plugin call it nowif ($plugin_type === Smarty::PLUGIN_COMPILER) {$new_args = array();foreach ($args as $key => $mixed) {if (is_array($mixed)) {$new_args = array_merge($new_args, $mixed);} else {$new_args[ $key ] = $mixed;}}if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) {$this->tag_nocache = true;}return call_user_func_array($this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ],array($new_args,$this));}// compile registered function or block functionif ($plugin_type === Smarty::PLUGIN_FUNCTION || $plugin_type === Smarty::PLUGIN_BLOCK) {return $this->callTagCompiler('private_registered_' . $plugin_type,$args,$parameter,$tag);}}}// check plugins from plugins folderforeach ($this->plugin_search_order as $plugin_type) {if ($plugin_type === Smarty::PLUGIN_COMPILER&& $this->smarty->loadPlugin('smarty_compiler_' . $tag)&& (!isset($this->smarty->security_policy)|| $this->smarty->security_policy->isTrustedTag($tag, $this))) {$plugin = 'smarty_compiler_' . $tag;if (is_callable($plugin)) {// convert arguments format for old compiler plugins$new_args = array();foreach ($args as $key => $mixed) {if (is_array($mixed)) {$new_args = array_merge($new_args, $mixed);} else {$new_args[ $key ] = $mixed;}}return $plugin($new_args, $this->smarty);}if (class_exists($plugin, false)) {$plugin_object = new $plugin;if (method_exists($plugin_object, 'compile')) {return $plugin_object->compile($args, $this);}}throw new SmartyException("Plugin '{$tag}' not callable");} else {if ($function = $this->getPlugin($tag, $plugin_type)) {if (!isset($this->smarty->security_policy)|| $this->smarty->security_policy->isTrustedTag($tag, $this)) {return $this->callTagCompiler('private_' . $plugin_type . '_plugin',$args,$parameter,$tag,$function);}}}}if (is_callable($this->smarty->default_plugin_handler_func)) {$found = false;// look for already resolved tagsforeach ($this->plugin_search_order as $plugin_type) {if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) {$found = true;break;}}if (!$found) {// call default handlerforeach ($this->plugin_search_order as $plugin_type) {if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {$found = true;break;}}}if ($found) {// if compiler function plugin call it nowif ($plugin_type === Smarty::PLUGIN_COMPILER) {$new_args = array();foreach ($args as $key => $mixed) {if (is_array($mixed)) {$new_args = array_merge($new_args, $mixed);} else {$new_args[ $key ] = $mixed;}}return call_user_func_array($this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ],array($new_args,$this));} else {return $this->callTagCompiler('private_registered_' . $plugin_type,$args,$parameter,$tag);}}}} else {// compile closing tag of block function$base_tag = substr($tag, 0, -5);// check if closing tag is a registered objectif (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) {$method = $parameter[ 'object_method' ];if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) {return $this->callTagCompiler('private_object_block_function',$args,$parameter,$tag,$method);} else {// throw exception$this->trigger_template_error('not allowed closing tag method "' . $method .'" in registered object "' . $base_tag . '"',null,true);}}// registered block tag ?if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])|| isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])) {return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);}// registered function tag ?if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {return $this->callTagCompiler('private_registered_function', $args, $parameter, $tag);}// block plugin?if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);}// function plugin?if ($function = $this->getPlugin($tag, Smarty::PLUGIN_FUNCTION)) {if (!isset($this->smarty->security_policy)|| $this->smarty->security_policy->isTrustedTag($tag, $this)) {return $this->callTagCompiler('private_function_plugin', $args, $parameter, $tag, $function);}}// registered compiler plugin ?if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) {// if compiler function plugin call it now$args = array();if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) {$this->tag_nocache = true;}return call_user_func_array($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ],array($args,$this));}if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {$plugin = 'smarty_compiler_' . $tag;if (is_callable($plugin)) {return $plugin($args, $this->smarty);}if (class_exists($plugin, false)) {$plugin_object = new $plugin;if (method_exists($plugin_object, 'compile')) {return $plugin_object->compile($args, $this);}}throw new SmartyException("Plugin '{$tag}' not callable");}}$this->trigger_template_error("unknown tag '{$tag}'", null, true);}}}