gluon-web-remote

Web remote Administration for big size of gluon routers
git clone git://archive.git.mtrnord.blog/MTRNord/gluon-web-remote.git
Log | Files | Refs | README

smarty_internal_templatecompilerbase.php (39929B)


      1 <?php
      2 
      3 /**
      4  * Smarty Internal Plugin Smarty Template Compiler Base
      5  * This file contains the basic classes and methods 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     /**
     22      * Smarty object
     23      *
     24      * @var Smarty
     25      */
     26     public $smarty = null;
     27 
     28     /**
     29      * hash for nocache sections
     30      *
     31      * @var mixed
     32      */
     33     public $nocache_hash = null;
     34 
     35     /**
     36      * suppress generation of nocache code
     37      *
     38      * @var bool
     39      */
     40     public $suppressNocacheProcessing = 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 included sub template data
     65      *
     66      * @var array
     67      */
     68     public $mergedSubTemplatesData = array();
     69 
     70     /**
     71      * merged sub template code
     72      *
     73      * @var array
     74      */
     75     public $mergedSubTemplatesCode = array();
     76 
     77     /**
     78      * collected template properties during compilation
     79      *
     80      * @var array
     81      */
     82     public $templateProperties = array();
     83 
     84     /**
     85      * sources which must be compiled
     86      *
     87      * @var array
     88      */
     89     public $sources = array();
     90 
     91     /**
     92      * flag that we are inside {block}
     93      *
     94      * @var bool
     95      */
     96     public $inheritance = false;
     97 
     98     /**
     99      * flag when compiling inheritance child template
    100      *
    101      * @var bool
    102      */
    103     public $inheritance_child = false;
    104 
    105     /**
    106      * uid of templates called by {extends} for recursion check
    107      *
    108      * @var array
    109      */
    110     public $extends_uid = array();
    111 
    112     /**
    113      * source line offset for error messages
    114      *
    115      * @var int
    116      */
    117     public $trace_line_offset = 0;
    118 
    119     /**
    120      * trace uid
    121      *
    122      * @var string
    123      */
    124     public $trace_uid = '';
    125 
    126     /**
    127      * trace file path
    128      *
    129      * @var string
    130      */
    131     public $trace_filepath = '';
    132 
    133     /**
    134      * stack for tracing file and line of nested {block} tags
    135      *
    136      * @var array
    137      */
    138     public $trace_stack = array();
    139 
    140     /**
    141      * plugins loaded by default plugin handler
    142      *
    143      * @var array
    144      */
    145     public $default_handler_plugins = array();
    146 
    147     /**
    148      * saved preprocessed modifier list
    149      *
    150      * @var mixed
    151      */
    152     public $default_modifier_list = null;
    153 
    154     /**
    155      * force compilation of complete template as nocache
    156      *
    157      * @var boolean
    158      */
    159     public $forceNocache = false;
    160 
    161     /**
    162      * suppress Smarty header code in compiled template
    163      *
    164      * @var bool
    165      */
    166     public $suppressHeader = false;
    167 
    168     /**
    169      * suppress template property header code in compiled template
    170      *
    171      * @var bool
    172      */
    173     public $suppressTemplatePropertyHeader = false;
    174 
    175     /**
    176      * suppress pre and post filter
    177      *
    178      * @var bool
    179      */
    180     public $suppressFilter = false;
    181 
    182     /**
    183      * flag if compiled template file shall we written
    184      *
    185      * @var bool
    186      */
    187     public $write_compiled_code = true;
    188 
    189     /**
    190      * flag if currently a template function is compiled
    191      *
    192      * @var bool
    193      */
    194     public $compiles_template_function = false;
    195 
    196     /**
    197      * called sub functions from template function
    198      *
    199      * @var array
    200      */
    201     public $called_functions = array();
    202 
    203     /**
    204      * compiled template function code
    205      *
    206      * @var string
    207      */
    208     public $templateFunctionCode = '';
    209 
    210     /**
    211      * php_handling setting either from Smarty or security
    212      *
    213      * @var int
    214      */
    215     public $php_handling = 0;
    216 
    217     /**
    218      * flags for used modifier plugins
    219      *
    220      * @var array
    221      */
    222     public $modifier_plugins = array();
    223 
    224     /**
    225      * type of already compiled modifier
    226      *
    227      * @var array
    228      */
    229     public $known_modifier_type = array();
    230 
    231     /**
    232      * parent compiler object for merged subtemplates and template functions
    233      *
    234      * @var Smarty_Internal_TemplateCompilerBase
    235      */
    236     public $parent_compiler = null;
    237 
    238     /**
    239      * Flag true when compiling nocache section
    240      *
    241      * @var bool
    242      */
    243     public $nocache = false;
    244 
    245     /**
    246      * Flag true when tag is compiled as nocache
    247      *
    248      * @var bool
    249      */
    250     public $tag_nocache = false;
    251 
    252     /**
    253      * Flag to restart parsing
    254      *
    255      * @var bool
    256      */
    257     public $abort_and_recompile = false;
    258 
    259     /**
    260      * Compiled tag prefix code
    261      *
    262      * @var array
    263      */
    264     public $prefix_code = array();
    265 
    266     /**
    267      * Prefix code  stack
    268      *
    269      * @var array
    270      */
    271     public $prefixCodeStack = array();
    272 
    273     /**
    274      * Tag has compiled code
    275      *
    276      * @var bool
    277      */
    278     public $has_code = false;
    279 
    280     /**
    281      * A variable string was compiled
    282      *
    283      * @var bool
    284      */
    285     public $has_variable_string = false;
    286 
    287     /**
    288      * Tag creates output
    289      *
    290      * @var bool
    291      */
    292     public $has_output = false;
    293 
    294     /**
    295      * Strip preg pattern
    296      *
    297      * @var string
    298      */
    299     public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';
    300 
    301     /**
    302      * method to compile a Smarty template
    303      *
    304      * @param  mixed $_content template source
    305      *
    306      * @return bool  true if compiling succeeded, false if it failed
    307      */
    308     abstract protected function doCompile($_content);
    309 
    310     /**
    311      * Initialize compiler
    312      */
    313     public function __construct()
    314     {
    315         $this->nocache_hash = str_replace(array('.', ','), '_', uniqid(rand(), true));
    316     }
    317 
    318     /**
    319      * Method to compile a Smarty template
    320      *
    321      * @param  Smarty_Internal_Template                 $template template object to compile
    322      * @param  bool                                     $nocache  true is shall be compiled in nocache mode
    323      * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
    324      *
    325      * @return bool true if compiling succeeded, false if it failed
    326      */
    327     public function compileTemplate(Smarty_Internal_Template $template, $nocache = null, $parent_compiler = null)
    328     {
    329         // save template object in compiler class
    330         $this->template = $template;
    331         if (isset($this->template->smarty->security_policy)) {
    332             $this->php_handling = $this->template->smarty->security_policy->php_handling;
    333         } else {
    334             $this->php_handling = $this->template->smarty->php_handling;
    335         }
    336         $this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
    337         $nocache = isset($nocache) ? $nocache : false;
    338         if (empty($template->properties['nocache_hash'])) {
    339             $template->properties['nocache_hash'] = $this->nocache_hash;
    340         } else {
    341             $this->nocache_hash = $template->properties['nocache_hash'];
    342         }
    343         $save_source = $this->template->source;
    344         // template header code
    345         $template_header = '';
    346         if (!$this->suppressHeader) {
    347             $template_header .= "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";
    348             $template_header .= "         compiled from \"" . $this->template->source->filepath . "\" */ ?>\n";
    349         }
    350 
    351         if (empty($this->template->source->components)) {
    352             $this->sources = array($template->source);
    353         } else {
    354             // we have array of inheritance templates by extends: resource
    355             $this->sources = array_reverse($template->source->components);
    356         }
    357         $loop = 0;
    358         // the $this->sources array can get additional elements while compiling by the {extends} tag
    359         while ($this->template->source = array_shift($this->sources)) {
    360             $this->smarty->_current_file = $this->template->source->filepath;
    361             if ($this->smarty->debugging) {
    362                 Smarty_Internal_Debug::start_compile($this->template);
    363             }
    364             $no_sources = count($this->sources);
    365             $this->parent_compiler->template->properties['file_dependency'][$this->template->source->uid] = array($this->template->source->filepath, $this->template->source->timestamp, $this->template->source->type);
    366             $loop ++;
    367             if ($no_sources) {
    368                 $this->inheritance_child = true;
    369             } else {
    370                 $this->inheritance_child = false;
    371             }
    372             do {
    373                 // flag for nochache sections
    374                 $this->nocache = $nocache;
    375                 $this->tag_nocache = false;
    376                 // reset has nocache code flag
    377                 $this->template->has_nocache_code = false;
    378                 $this->has_variable_string = false;
    379                 $this->prefix_code = array();
    380                 $_compiled_code = '';
    381                 // flag for aborting current and start recompile
    382                 $this->abort_and_recompile = false;
    383                 // get template source
    384                 $_content = $this->template->source->content;
    385                 if ($_content != '') {
    386                     // run prefilter if required
    387                     if ((isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) && !$this->suppressFilter) {
    388                         $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template);
    389                     }
    390                     // call compiler
    391                     $_compiled_code = $this->doCompile($_content, true);
    392                 }
    393             } while ($this->abort_and_recompile);
    394             if ($this->smarty->debugging) {
    395                 Smarty_Internal_Debug::end_compile($this->template);
    396             }
    397         }
    398         // restore source
    399         $this->template->source = $save_source;
    400         unset($save_source);
    401         $this->smarty->_current_file = $this->template->source->filepath;
    402         // free memory
    403         unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex);
    404         self::$_tag_objects = array();
    405         // return compiled code to template object
    406         $merged_code = '';
    407         if (!empty($this->mergedSubTemplatesCode)) {
    408             foreach ($this->mergedSubTemplatesCode as $code) {
    409                 $merged_code .= $code;
    410             }
    411         }
    412         // run postfilter if required on compiled template code
    413         if ((isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) && !$this->suppressFilter && $_compiled_code != '') {
    414             $_compiled_code = Smarty_Internal_Filter_Handler::runFilter('post', $_compiled_code, $template);
    415         }
    416         if ($this->suppressTemplatePropertyHeader) {
    417             $_compiled_code .= $merged_code;
    418         } else {
    419             $_compiled_code = $template_header . Smarty_Internal_Extension_CodeFrame::create($template, $_compiled_code) . $merged_code;
    420         }
    421         if (!empty($this->templateFunctionCode)) {
    422             // run postfilter if required on compiled template code
    423             if ((isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) && !$this->suppressFilter) {
    424                 $_compiled_code .= Smarty_Internal_Filter_Handler::runFilter('post', $this->templateFunctionCode, $template);
    425             } else {
    426                 $_compiled_code .= $this->templateFunctionCode;
    427             }
    428         }
    429         // unset content because template inheritance could have replace source with parent code
    430         unset ($template->source->content);
    431         $this->parent_compiler = null;
    432         $this->template = null;
    433         return $_compiled_code;
    434     }
    435 
    436     /**
    437      * Compile Tag
    438      * This is a call back from the lexer/parser
    439      *
    440      * Save current prefix code
    441      * Compile tag
    442      * Merge tag prefix code with saved one
    443      * (required nested tags in attributes)
    444      *
    445      * @param  string $tag       tag name
    446      * @param  array  $args      array with tag attributes
    447      * @param  array  $parameter array with compilation parameter
    448      *
    449      * @throws SmartyCompilerException
    450      * @throws SmartyException
    451      * @return string compiled code
    452      */
    453     public function compileTag($tag, $args, $parameter = array())
    454     {
    455         $this->prefixCodeStack[] = $this->prefix_code;
    456         $this->prefix_code = array();
    457         $result = $this->compileTag2($tag, $args, $parameter);
    458         $this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
    459         return $result;
    460     }
    461 
    462     /**
    463      * Compile Tag
    464      *
    465      * @param  string $tag       tag name
    466      * @param  array  $args      array with tag attributes
    467      * @param  array  $parameter array with compilation parameter
    468      *
    469      * @throws SmartyCompilerException
    470      * @throws SmartyException
    471      * @return string compiled code
    472      */
    473     private function compileTag2($tag, $args, $parameter)
    474     {
    475         $plugin_type = '';
    476         // $args contains the attributes parsed and compiled by the lexer/parser
    477         // assume that tag does compile into code, but creates no HTML output
    478         $this->has_code = true;
    479         $this->has_output = false;
    480         // log tag/attributes
    481         if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) {
    482             $this->template->used_tags[] = array($tag, $args);
    483         }
    484         // check nocache option flag
    485         if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args) || in_array(array('nocache' => '"true"'), $args) || in_array(array('nocache' => "'true'"), $args)
    486         ) {
    487             $this->tag_nocache = true;
    488         }
    489         // compile the smarty tag (required compile classes to compile the tag are autoloaded)
    490         if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
    491             if (isset($this->parent_compiler->templateProperties['tpl_function'][$tag])) {
    492                 // template defined by {template} tag
    493                 $args['_attr']['name'] = "'" . $tag . "'";
    494                 $_output = $this->callTagCompiler('call', $args, $parameter);
    495             }
    496         }
    497         if ($_output !== false) {
    498             if ($_output !== true) {
    499                 // did we get compiled code
    500                 if ($this->has_code) {
    501                     // Does it create output?
    502                     if ($this->has_output) {
    503                         $_output .= "\n";
    504                     }
    505                     // return compiled code
    506                     return $_output;
    507                 }
    508             }
    509             // tag did not produce compiled code
    510             return null;
    511         } else {
    512             // map_named attributes
    513             if (isset($args['_attr'])) {
    514                 foreach ($args['_attr'] as $key => $attribute) {
    515                     if (is_array($attribute)) {
    516                         $args = array_merge($args, $attribute);
    517                     }
    518                 }
    519             }
    520             // not an internal compiler tag
    521             if (strlen($tag) < 6 || substr($tag, - 5) != 'close') {
    522                 // check if tag is a registered object
    523                 if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_method'])) {
    524                     $method = $parameter['object_method'];
    525                     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]))
    526                     ) {
    527                         return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
    528                     } elseif (in_array($method, $this->smarty->registered_objects[$tag][3])) {
    529                         return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
    530                     } else {
    531                         // throw exception
    532                         $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' . $tag . '"', $this->lex->taglineno);
    533                     }
    534                 }
    535                 // check if tag is registered
    536                 foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) {
    537                     if (isset($this->smarty->registered_plugins[$plugin_type][$tag])) {
    538                         // if compiler function plugin call it now
    539                         if ($plugin_type == Smarty::PLUGIN_COMPILER) {
    540                             $new_args = array();
    541                             foreach ($args as $key => $mixed) {
    542                                 if (is_array($mixed)) {
    543                                     $new_args = array_merge($new_args, $mixed);
    544                                 } else {
    545                                     $new_args[$key] = $mixed;
    546                                 }
    547                             }
    548                             if (!$this->smarty->registered_plugins[$plugin_type][$tag][1]) {
    549                                 $this->tag_nocache = true;
    550                             }
    551                             $function = $this->smarty->registered_plugins[$plugin_type][$tag][0];
    552                             if (!is_array($function)) {
    553                                 return $function($new_args, $this);
    554                             } elseif (is_object($function[0])) {
    555                                 return $this->smarty->registered_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
    556                             } else {
    557                                 return call_user_func_array($function, array($new_args, $this));
    558                             }
    559                         }
    560                         // compile registered function or block function
    561                         if ($plugin_type == Smarty::PLUGIN_FUNCTION || $plugin_type == Smarty::PLUGIN_BLOCK) {
    562                             return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
    563                         }
    564                     }
    565                 }
    566                 // check plugins from plugins folder
    567                 foreach ($this->smarty->plugin_search_order as $plugin_type) {
    568                     if ($plugin_type == Smarty::PLUGIN_COMPILER && $this->smarty->loadPlugin('smarty_compiler_' . $tag) && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) {
    569                         $plugin = 'smarty_compiler_' . $tag;
    570                         if (is_callable($plugin)) {
    571                             // convert arguments format for old compiler plugins
    572                             $new_args = array();
    573                             foreach ($args as $key => $mixed) {
    574                                 if (is_array($mixed)) {
    575                                     $new_args = array_merge($new_args, $mixed);
    576                                 } else {
    577                                     $new_args[$key] = $mixed;
    578                                 }
    579                             }
    580 
    581                             return $plugin($new_args, $this->smarty);
    582                         }
    583                         if (class_exists($plugin, false)) {
    584                             $plugin_object = new $plugin;
    585                             if (method_exists($plugin_object, 'compile')) {
    586                                 return $plugin_object->compile($args, $this);
    587                             }
    588                         }
    589                         throw new SmartyException("Plugin \"{$tag}\" not callable");
    590                     } else {
    591                         if ($function = $this->getPlugin($tag, $plugin_type)) {
    592                             if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
    593                                 return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function);
    594                             }
    595                         }
    596                     }
    597                 }
    598                 if (is_callable($this->smarty->default_plugin_handler_func)) {
    599                     $found = false;
    600                     // look for already resolved tags
    601                     foreach ($this->smarty->plugin_search_order as $plugin_type) {
    602                         if (isset($this->default_handler_plugins[$plugin_type][$tag])) {
    603                             $found = true;
    604                             break;
    605                         }
    606                     }
    607                     if (!$found) {
    608                         // call default handler
    609                         foreach ($this->smarty->plugin_search_order as $plugin_type) {
    610                             if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
    611                                 $found = true;
    612                                 break;
    613                             }
    614                         }
    615                     }
    616                     if ($found) {
    617                         // if compiler function plugin call it now
    618                         if ($plugin_type == Smarty::PLUGIN_COMPILER) {
    619                             $new_args = array();
    620                             foreach ($args as $mixed) {
    621                                 $new_args = array_merge($new_args, $mixed);
    622                             }
    623                             $function = $this->default_handler_plugins[$plugin_type][$tag][0];
    624                             if (!is_array($function)) {
    625                                 return $function($new_args, $this);
    626                             } elseif (is_object($function[0])) {
    627                                 return $this->default_handler_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this);
    628                             } else {
    629                                 return call_user_func_array($function, array($new_args, $this));
    630                             }
    631                         } else {
    632                             return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag);
    633                         }
    634                     }
    635                 }
    636             } else {
    637                 // compile closing tag of block function
    638                 $base_tag = substr($tag, 0, - 5);
    639                 // check if closing tag is a registered object
    640                 if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_method'])) {
    641                     $method = $parameter['object_method'];
    642                     if (in_array($method, $this->smarty->registered_objects[$base_tag][3])) {
    643                         return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method);
    644                     } else {
    645                         // throw exception
    646                         $this->trigger_template_error('not allowed closing tag method "' . $method . '" in registered object "' . $base_tag . '"', $this->lex->taglineno);
    647                     }
    648                 }
    649                 // registered block tag ?
    650                 if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) || isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
    651                     return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
    652                 }
    653                 // block plugin?
    654                 if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
    655                     return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
    656                 }
    657                 // registered compiler plugin ?
    658                 if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) {
    659                     // if compiler function plugin call it now
    660                     $args = array();
    661                     if (!$this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][1]) {
    662                         $this->tag_nocache = true;
    663                     }
    664                     $function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0];
    665                     if (!is_array($function)) {
    666                         return $function($args, $this);
    667                     } elseif (is_object($function[0])) {
    668                         return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($args, $this);
    669                     } else {
    670                         return call_user_func_array($function, array($args, $this));
    671                     }
    672                 }
    673                 if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
    674                     $plugin = 'smarty_compiler_' . $tag;
    675                     if (is_callable($plugin)) {
    676                         return $plugin($args, $this->smarty);
    677                     }
    678                     if (class_exists($plugin, false)) {
    679                         $plugin_object = new $plugin;
    680                         if (method_exists($plugin_object, 'compile')) {
    681                             return $plugin_object->compile($args, $this);
    682                         }
    683                     }
    684                     throw new SmartyException("Plugin \"{$tag}\" not callable");
    685                 }
    686             }
    687             $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex->taglineno);
    688         }
    689     }
    690 
    691     /**
    692      * compile variable
    693      *
    694      * @param string $variable
    695      *
    696      * @return string
    697      */
    698     public function compileVariable($variable)
    699     {
    700         if (strpos($variable, '(') == 0) {
    701             // not a variable variable
    702             $var = trim($variable, '\'');
    703             $this->tag_nocache = $this->tag_nocache | $this->template->getVariable($var, null, true, false)->nocache;
    704             $this->template->properties['variables'][$var] = $this->tag_nocache | $this->nocache;
    705         }
    706         return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
    707     }
    708 
    709     /**
    710      * This method is called from parser to process a text content section
    711      * - remove text from inheritance child templates as they may generate output
    712      * - strip text if strip is enabled
    713      *
    714      * @param string $text
    715      *
    716      * @return null|\Smarty_Internal_ParseTree_Text
    717      */
    718     public function processText($text)
    719     {
    720         if ($this->parser->strip) {
    721             return new Smarty_Internal_ParseTree_Text($this->parser, preg_replace($this->stripRegEx, '', $text));
    722         } else {
    723             return new Smarty_Internal_ParseTree_Text($this->parser, $text);
    724         }
    725     }
    726 
    727     /**
    728      * lazy loads internal compile plugin for tag and calls the compile method
    729      * compile objects cached for reuse.
    730      * class name format:  Smarty_Internal_Compile_TagName
    731      * plugin filename format: Smarty_Internal_Tagname.php
    732      *
    733      * @param  string $tag    tag name
    734      * @param  array  $args   list of tag attributes
    735      * @param  mixed  $param1 optional parameter
    736      * @param  mixed  $param2 optional parameter
    737      * @param  mixed  $param3 optional parameter
    738      *
    739      * @return string compiled code
    740      */
    741     public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
    742     {
    743         // check if tag allowed by security
    744         if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) {
    745             // re-use object if already exists
    746             if (!isset(self::$_tag_objects[$tag])) {
    747                 // lazy load internal compiler plugin
    748                 $class_name = 'Smarty_Internal_Compile_' . $tag;
    749                 if ($this->smarty->loadPlugin($class_name)) {
    750                     self::$_tag_objects[$tag] = new $class_name;
    751                 } else {
    752                     return false;
    753                 }
    754             }
    755             // compile this tag
    756             return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
    757         }
    758         // no internal compile plugin for this tag
    759         return false;
    760     }
    761 
    762     /**
    763      * Check for plugins and return function name
    764      *
    765      * @param         $plugin_name
    766      * @param  string $plugin_type type of plugin
    767      *
    768      * @return string call name of function
    769      */
    770     public function getPlugin($plugin_name, $plugin_type)
    771     {
    772         $function = null;
    773         if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
    774             if (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) {
    775                 $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
    776             } elseif (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) {
    777                 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type] = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type];
    778                 $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
    779             }
    780         } else {
    781             if (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) {
    782                 $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
    783             } elseif (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) {
    784                 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type] = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type];
    785                 $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
    786             }
    787         }
    788         if (isset($function)) {
    789             if ($plugin_type == 'modifier') {
    790                 $this->modifier_plugins[$plugin_name] = true;
    791             }
    792 
    793             return $function;
    794         }
    795         // loop through plugin dirs and find the plugin
    796         $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
    797         $file = $this->smarty->loadPlugin($function, false);
    798 
    799         if (is_string($file)) {
    800             if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
    801                 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['file'] = $file;
    802                 $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function'] = $function;
    803             } else {
    804                 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] = $file;
    805                 $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] = $function;
    806             }
    807             if ($plugin_type == 'modifier') {
    808                 $this->modifier_plugins[$plugin_name] = true;
    809             }
    810 
    811             return $function;
    812         }
    813         if (is_callable($function)) {
    814             // plugin function is defined in the script
    815             return $function;
    816         }
    817 
    818         return false;
    819     }
    820 
    821     /**
    822      * Check for plugins by default plugin handler
    823      *
    824      * @param  string $tag         name of tag
    825      * @param  string $plugin_type type of plugin
    826      *
    827      * @return boolean true if found
    828      */
    829     public function getPluginFromDefaultHandler($tag, $plugin_type)
    830     {
    831         $callback = null;
    832         $script = null;
    833         $cacheable = true;
    834         $result = call_user_func_array($this->smarty->default_plugin_handler_func, array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable));
    835         if ($result) {
    836             $this->tag_nocache = $this->tag_nocache || !$cacheable;
    837             if ($script !== null) {
    838                 if (is_file($script)) {
    839                     if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
    840                         $this->template->required_plugins['nocache'][$tag][$plugin_type]['file'] = $script;
    841                         $this->template->required_plugins['nocache'][$tag][$plugin_type]['function'] = $callback;
    842                     } else {
    843                         $this->template->required_plugins['compiled'][$tag][$plugin_type]['file'] = $script;
    844                         $this->template->required_plugins['compiled'][$tag][$plugin_type]['function'] = $callback;
    845                     }
    846                     require_once $script;
    847                 } else {
    848                     $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
    849                 }
    850             }
    851             if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) {
    852                 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name");
    853             }
    854             if (is_callable($callback)) {
    855                 $this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array());
    856 
    857                 return true;
    858             } else {
    859                 $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable");
    860             }
    861         }
    862 
    863         return false;
    864     }
    865 
    866     /**
    867      * Append code segments and remove unneeded ?> <?php transitions
    868      *
    869      * @param string $left
    870      * @param string $right
    871      *
    872      * @return string
    873      */
    874     public function appendCode($left, $right)
    875     {
    876         if (preg_match('/\s*\?>\s*$/', $left) && preg_match('/^\s*<\?php\s+/', $right)) {
    877             $left = preg_replace('/\s*\?>\s*$/', "\n", $left);
    878             $left .= preg_replace('/^\s*<\?php\s+/', '', $right);
    879         } else {
    880             $left .= $right;
    881         }
    882         return $left;
    883     }
    884 
    885     /**
    886      * Inject inline code for nocache template sections
    887      * This method gets the content of each template element from the parser.
    888      * If the content is compiled code and it should be not cached the code is injected
    889      * into the rendered output.
    890      *
    891      * @param  string  $content content of template element
    892      * @param  boolean $is_code true if content is compiled code
    893      *
    894      * @return string  content
    895      */
    896     public function processNocacheCode($content, $is_code)
    897     {
    898         // If the template is not evaluated and we have a nocache section and or a nocache tag
    899         if ($is_code && !empty($content)) {
    900             // generate replacement code
    901             if ((!($this->template->source->recompiled) || $this->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)
    902             ) {
    903                 $this->template->has_nocache_code = true;
    904                 $_output = addcslashes($content, '\'\\');
    905                 $_output = str_replace("^#^", "'", $_output);
    906                 $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
    907                 // make sure we include modifier plugins for nocache code
    908                 foreach ($this->modifier_plugins as $plugin_name => $dummy) {
    909                     if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) {
    910                         $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier'];
    911                     }
    912                 }
    913             } else {
    914                 $_output = $content;
    915             }
    916         } else {
    917             $_output = $content;
    918         }
    919         $this->modifier_plugins = array();
    920         $this->suppressNocacheProcessing = false;
    921         $this->tag_nocache = false;
    922 
    923         return $_output;
    924     }
    925 
    926     /**
    927      * Generate nocache code string
    928      *
    929      * @param string $code PHP code
    930      *
    931      * @return string
    932      */
    933     public function makeNocacheCode($code)
    934     {
    935         return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " . str_replace("^#^", "'", addcslashes($code, '\'\\')) . "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
    936     }
    937 
    938     /**
    939      *  push current file and line offset on stack for tracing {block} source lines
    940      *
    941      * @param string $file  new filename
    942      * @param string $uid   uid of file
    943      * @param int    $line  line offset to source
    944      * @param bool   $debug false debug end_compile shall not be called
    945      */
    946     public function pushTrace($file, $uid, $line, $debug = true)
    947     {
    948         if ($this->smarty->debugging && $debug) {
    949             Smarty_Internal_Debug::end_compile($this->template);
    950         }
    951         array_push($this->trace_stack, array($this->smarty->_current_file, $this->trace_filepath, $this->trace_uid, $this->trace_line_offset));
    952         $this->trace_filepath = $this->smarty->_current_file = $file;
    953         $this->trace_uid = $uid;
    954         $this->trace_line_offset = $line;
    955         if ($this->smarty->debugging) {
    956             Smarty_Internal_Debug::start_compile($this->template);
    957         }
    958     }
    959 
    960     /**
    961      *  restore file and line offset
    962      */
    963     public function popTrace()
    964     {
    965         if ($this->smarty->debugging) {
    966             Smarty_Internal_Debug::end_compile($this->template);
    967         }
    968         $r = array_pop($this->trace_stack);
    969         $this->smarty->_current_file = $r[0];
    970         $this->trace_filepath = $r[1];
    971         $this->trace_uid = $r[2];
    972         $this->trace_line_offset = $r[3];
    973         if ($this->smarty->debugging) {
    974             Smarty_Internal_Debug::start_compile($this->template);
    975         }
    976     }
    977 
    978     /**
    979      * display compiler error messages without dying
    980      * If parameter $args is empty it is a parser detected syntax error.
    981      * In this case the parser is called to obtain information about expected tokens.
    982      * If parameter $args contains a string this is used as error message
    983      *
    984      * @param  string $args individual error message or null
    985      * @param  string $line line-number
    986      *
    987      * @throws SmartyCompilerException when an unexpected token is found
    988      */
    989     public function trigger_template_error($args = null, $line = null)
    990     {
    991         // get template source line which has error
    992         if (!isset($line)) {
    993             $line = $this->lex->line;
    994         }
    995         //        $line += $this->trace_line_offset;
    996         $match = preg_split("/\n/", $this->lex->data);
    997         $error_text = 'Syntax error in template "' . (empty($this->trace_filepath) ? $this->template->source->filepath : $this->trace_filepath) . '"  on line ' . ($line + $this->trace_line_offset) . ' "' . trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])) . '" ';
    998         if (isset($args)) {
    999             // individual error message
   1000             $error_text .= $args;
   1001         } else {
   1002             $expect = array();
   1003             // expected token from parser
   1004             $error_text .= ' - Unexpected "' . $this->lex->value . '"';
   1005             if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
   1006                 foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
   1007                     $exp_token = $this->parser->yyTokenName[$token];
   1008                     if (isset($this->lex->smarty_token_names[$exp_token])) {
   1009                         // token type from lexer
   1010                         $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"';
   1011                     } else {
   1012                         // otherwise internal token name
   1013                         $expect[] = $this->parser->yyTokenName[$token];
   1014                     }
   1015                 }
   1016                 $error_text .= ', expected one of: ' . implode(' , ', $expect);
   1017             }
   1018         }
   1019         $e = new SmartyCompilerException($error_text);
   1020         $e->line = $line;
   1021         $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1]));
   1022         $e->desc = $args;
   1023         $e->template = $this->template->source->filepath;
   1024         throw $e;
   1025     }
   1026 }