PageRenderTime 288ms CodeModel.GetById 101ms app.highlight 74ms RepoModel.GetById 107ms app.codeStats 0ms

/app/libraries/smarty/sysplugins/smarty_internal_templatecompilerbase.php

https://bitbucket.org/nanomites_webdev/heroframework
PHP | 429 lines | 308 code | 7 blank | 114 comment | 93 complexity | 62e5d47e1cc4d293f3cf83b45893ae70 MD5 | raw file
  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 compiler class
 14 */
 15class Smarty_Internal_TemplateCompilerBase {
 16    // hash for nocache sections
 17    private $nocache_hash = null; 
 18    // suppress generation of nocache code
 19    public $suppressNocacheProcessing = false; 
 20    // compile tag objects
 21    static $_tag_objects = array(); 
 22    // tag stack
 23    public $_tag_stack = array(); 
 24    // current template
 25    public $template = null;
 26    // optional log of tag/attributes
 27    public $used_tags = array();
 28
 29    /**
 30     * Initialize compiler
 31     */
 32    public function __construct()
 33    {
 34        $this->nocache_hash = str_replace('.', '-', uniqid(rand(), true));
 35    } 
 36    // abstract function doCompile($_content);
 37    /**
 38     * Methode to compile a Smarty template
 39     * 
 40     * @param  $template template object to compile
 41     * @return bool true if compiling succeeded, false if it failed
 42     */
 43    public function compileTemplate($template)
 44    {
 45        if (empty($template->properties['nocache_hash'])) {
 46            $template->properties['nocache_hash'] = $this->nocache_hash;
 47        } else {
 48            $this->nocache_hash = $template->properties['nocache_hash'];
 49        } 
 50        // flag for nochache sections
 51        $this->nocache = false;
 52        $this->tag_nocache = false; 
 53        // save template object in compiler class
 54        $this->template = $template;
 55        $this->smarty->_current_file = $this->template->getTemplateFilepath(); 
 56        // template header code
 57        $template_header = '';
 58        if (!$template->suppressHeader) {
 59            $template_header .= "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";
 60            $template_header .= "         compiled from \"" . $this->template->getTemplateFilepath() . "\" */ ?>\n";
 61        } 
 62
 63        do {
 64            // flag for aborting current and start recompile
 65            $this->abort_and_recompile = false; 
 66            // get template source
 67            $_content = $template->getTemplateSource(); 
 68            // run prefilter if required
 69            if (isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) {
 70                $template->template_source = $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template);
 71            } 
 72            // on empty template just return header
 73            if ($_content == '') {
 74                if ($template->suppressFileDependency) {
 75                    $template->compiled_template = '';
 76                } else {
 77                    $template->compiled_template = $template_header . $template->createPropertyHeader();
 78                } 
 79                return true;
 80            } 
 81            // call compiler
 82            $_compiled_code = $this->doCompile($_content);
 83        } while ($this->abort_and_recompile); 
 84        // return compiled code to template object
 85        if ($template->suppressFileDependency) {
 86            $template->compiled_template = $_compiled_code;
 87        } else {
 88            $template->compiled_template = $template_header . $template->createPropertyHeader() . $_compiled_code;
 89        } 
 90        // run postfilter if required
 91        if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) {
 92            $template->compiled_template = Smarty_Internal_Filter_Handler::runFilter('post', $template->compiled_template, $template);
 93        } 
 94    } 
 95
 96    /**
 97     * Compile Tag
 98     * 
 99     * This is a call back from the lexer/parser
100     * It executes the required compile plugin for the Smarty tag
101     * 
102     * @param string $tag tag name
103     * @param array $args array with tag attributes
104     * @param array $parameter array with compilation parameter
105     * @return string compiled code
106     */
107    public function compileTag($tag, $args, $parameter = array())
108    { 
109        // $args contains the attributes parsed and compiled by the lexer/parser
110        // assume that tag does compile into code, but creates no HTML output
111        $this->has_code = true;
112        $this->has_output = false;
113        // log tag/attributes
114        if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) {
115        	$this->used_tags[] = array($tag,$args);
116        } 
117		// check nocache option flag
118        if (in_array("'nocache'",$args) || in_array(array('nocache'=>'true'),$args)
119        		|| in_array(array('nocache'=>'"true"'),$args) || in_array(array('nocache'=>"'true'"),$args)) {
120        	$this->tag_nocache = true;
121        }
122        // compile the smarty tag (required compile classes to compile the tag are autoloaded)
123        if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
124            if (isset($this->smarty->template_functions[$tag])) {
125                // template defined by {template} tag
126                $args['_attr']['name'] = "'" . $tag . "'";
127                $_output = $this->callTagCompiler('call', $args, $parameter);
128            } 
129        } 
130        if ($_output !== false) {
131            if ($_output !== true) {
132                // did we get compiled code
133                if ($this->has_code) {
134                    // Does it create output?
135                    if ($this->has_output) {
136                        $_output .= "\n";
137                    } 
138                    // return compiled code
139                    return $_output;
140                } 
141            } 
142            // tag did not produce compiled code
143            return '';
144        } else {
145            // map_named attributes
146            if (isset($args['_attr'])) {
147                foreach ($args['_attr'] as $key => $attribute) {
148                    if (is_array($attribute)) {
149                        $args = array_merge($args, $attribute);
150                    } 
151                } 
152            } 
153            // not an internal compiler tag
154            if (strlen($tag) < 6 || substr($tag, -5) != 'close') {
155                // check if tag is a registered object
156                if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_methode'])) {
157                    $methode = $parameter['object_methode'];
158                    if (!in_array($methode, $this->smarty->registered_objects[$tag][3]) &&
159                            (empty($this->smarty->registered_objects[$tag][1]) || in_array($methode, $this->smarty->registered_objects[$tag][1]))) {
160                        return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $methode);
161                    } elseif (in_array($methode, $this->smarty->registered_objects[$tag][3])) {
162                        return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode);
163                    } else {
164                        return $this->trigger_template_error ('unallowed methode "' . $methode . '" in registered object "' . $tag . '"', $this->lex->taglineno);
165                    } 
166                } 
167                // check if tag is registered
168                foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $type) {
169                    if (isset($this->smarty->registered_plugins[$type][$tag])) {
170                        // if compiler function plugin call it now
171                        if ($type == Smarty::PLUGIN_COMPILER) {
172                            $new_args = array();
173                            foreach ($args as $mixed) {
174                                $new_args = array_merge($new_args, $mixed);
175                            } 
176                            if (!$this->smarty->registered_plugins[$type][$tag][1]) {
177                                $this->tag_nocache = true;
178                            } 
179                            $function = $this->smarty->registered_plugins[$type][$tag][0];
180                            if (!is_array($function)) {
181                                return $function($new_args, $this);
182                            } else if (is_object($function[0])) {
183                                return $this->smarty->registered_plugins[$type][$tag][0][0]->$function[1]($new_args, $this);
184                            } else {
185                                return call_user_func_array($this->smarty->registered_plugins[$type][$tag][0], array($new_args, $this));
186                            } 
187                        } 
188                        // compile registered function or block function
189                        if ($type == Smarty::PLUGIN_FUNCTION || $type == Smarty::PLUGIN_BLOCK) {
190                            return $this->callTagCompiler('private_registered_' . $type, $args, $parameter, $tag);
191                        } 
192                    } 
193                } 
194                // check plugins from plugins folder
195                foreach ($this->smarty->plugin_search_order as $plugin_type) {
196                    if ($plugin_type == Smarty::PLUGIN_BLOCK && $this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
197                        $plugin = 'smarty_compiler_' . $tag;
198                        if (is_callable($plugin)) {
199                            return $plugin($args, $this->smarty);
200                        } 
201                        if (class_exists($plugin, false)) {
202                            $plugin_object = new $plugin;
203                            if (method_exists($plugin_object, 'compile')) {
204                                return $plugin_object->compile($args, $this);
205                            } 
206                        } 
207                        throw new SmartyException("Plugin \"{$tag}\" not callable");
208                    } else {
209                        if ($function = $this->getPlugin($tag, $plugin_type)) {
210                            return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function);
211                        } 
212                    } 
213                } 
214            } else {
215                // compile closing tag of block function
216                $base_tag = substr($tag, 0, -5); 
217                // check if closing tag is a registered object
218                if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_methode'])) {
219                    $methode = $parameter['object_methode'];
220                    if (in_array($methode, $this->smarty->registered_objects[$base_tag][3])) {
221                        return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode);
222                    } else {
223                        return $this->trigger_template_error ('unallowed closing tag methode "' . $methode . '" in registered object "' . $base_tag . '"', $this->lex->taglineno);
224                    } 
225                } 
226                // registered block tag ?
227                if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
228                    return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
229                } 
230                // block plugin?
231                if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
232                    return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
233                } 
234                if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
235                    $plugin = 'smarty_compiler_' . $tag;
236                    if (is_callable($plugin)) {
237                        return $plugin($args, $this->smarty);
238                    } 
239                    if (class_exists($plugin, false)) {
240                        $plugin_object = new $plugin;
241                        if (method_exists($plugin_object, 'compile')) {
242                            return $plugin_object->compile($args, $this);
243                        } 
244                    } 
245                    throw new SmartyException("Plugin \"{$tag}\" not callable");
246                } 
247            } 
248            $this->trigger_template_error ("unknown tag \"" . $tag . "\"", $this->lex->taglineno);
249        } 
250    } 
251
252    /**
253     * lazy loads internal compile plugin for tag and calls the compile methode
254     * 
255     * compile objects cached for reuse.
256     * class name format:  Smarty_Internal_Compile_TagName
257     * plugin filename format: Smarty_Internal_Tagname.php
258     * 
259     * @param  $tag string tag name
260     * @param  $args array with tag attributes
261     * @param  $param1 optional parameter
262     * @param  $param2 optional parameter
263     * @param  $param3 optional parameter
264     * @return string compiled code
265     */
266    public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
267    { 
268        // re-use object if already exists
269        if (isset(self::$_tag_objects[$tag])) {
270            // compile this tag
271            return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
272        } 
273        // lazy load internal compiler plugin
274        $class_name = 'Smarty_Internal_Compile_' . $tag;
275        if ($this->smarty->loadPlugin($class_name)) {
276            // use plugin if found
277            self::$_tag_objects[$tag] = new $class_name; 
278            // compile this tag
279            return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
280        } 
281        // no internal compile plugin for this tag
282        return false;
283    } 
284
285    /**
286     * Check for plugins and return function name
287     * 
288     * @param  $pugin_name string name of plugin or function
289     * @param  $type string type of plugin
290     * @return string call name of function
291     */
292    public function getPlugin($plugin_name, $type)
293    {
294        $function = null;
295        if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
296            if (isset($this->template->required_plugins['nocache'][$plugin_name][$type])) {
297                $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];
298            } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
299                $this->template->required_plugins['nocache'][$plugin_name][$type] = $this->template->required_plugins['compiled'][$plugin_name][$type];
300                $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];
301            } 
302        } else {
303            if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
304                $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];
305            } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
306                $this->template->required_plugins['compiled'][$plugin_name][$type] = $this->template->required_plugins['nocache'][$plugin_name][$type];
307                $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];
308            } 
309        } 
310        if (isset($function)) {
311            if ($type == 'modifier') {
312                $this->template->saved_modifier[$plugin_name] = true;
313            } 
314            return $function;
315        } 
316        // loop through plugin dirs and find the plugin
317        $function = 'smarty_' . $type . '_' . $plugin_name;
318        $found = false;
319        foreach((array)$this->smarty->plugins_dir as $_plugin_dir) {
320            $file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php';
321            if (file_exists($file)) {
322                // require_once($file);
323                $found = true;
324                break;
325            } 
326        } 
327        if ($found) {
328            if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
329                $this->template->required_plugins['nocache'][$plugin_name][$type]['file'] = $file;
330                $this->template->required_plugins['nocache'][$plugin_name][$type]['function'] = $function;
331            } else {
332                $this->template->required_plugins['compiled'][$plugin_name][$type]['file'] = $file;
333                $this->template->required_plugins['compiled'][$plugin_name][$type]['function'] = $function;
334            } 
335            if ($type == 'modifier') {
336                $this->template->saved_modifier[$plugin_name] = true;
337            } 
338            return $function;
339        } 
340        if (is_callable($function)) {
341            // plugin function is defined in the script
342            return $function;
343        } 
344        return false;
345    } 
346    /**
347     * Inject inline code for nocache template sections
348     * 
349     * This method gets the content of each template element from the parser.
350     * If the content is compiled code and it should be not cached the code is injected
351     * into the rendered output.
352     * 
353     * @param string $content content of template element
354     * @param boolean $tag_nocache true if the parser detected a nocache situation
355     * @param boolean $is_code true if content is compiled code
356     * @return string content
357     */
358    public function processNocacheCode ($content, $is_code)
359    { 
360        // If the template is not evaluated and we have a nocache section and or a nocache tag
361        if ($is_code && !empty($content)) {
362            // generate replacement code
363            if ((!$this->template->resource_object->isEvaluated || $this->template->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing &&
364                    ($this->nocache || $this->tag_nocache || $this->template->forceNocache == 2)) {
365                $this->template->has_nocache_code = true;
366                $_output = str_replace("'", "\'", $content);
367                $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>"; 
368                // make sure we include modifer plugins for nocache code
369                if (isset($this->template->saved_modifier)) {
370                    foreach ($this->template->saved_modifier as $plugin_name => $dummy) {
371                        if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) {
372                            $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier'];
373                        } 
374                    } 
375                    $this->template->saved_modifier = null;
376                } 
377            } else {
378                $_output = $content;
379            } 
380        } else {
381            $_output = $content;
382        } 
383        $this->suppressNocacheProcessing = false;
384        $this->tag_nocache = false;
385        return $_output;
386    } 
387    /**
388     * display compiler error messages without dying
389     * 
390     * If parameter $args is empty it is a parser detected syntax error.
391     * In this case the parser is called to obtain information about expected tokens.
392     * 
393     * If parameter $args contains a string this is used as error message
394     * 
395     * @param  $args string individual error message or null
396     */
397    public function trigger_template_error($args = null, $line = null)
398    { 
399        // get template source line which has error
400        if (!isset($line)) {
401            $line = $this->lex->line;
402        } 
403        $match = preg_split("/\n/", $this->lex->data);
404        $error_text = 'Syntax Error in template "' . $this->template->getTemplateFilepath() . '"  on line ' . $line . ' "' . htmlspecialchars(trim(preg_replace('![\t\r\n]+!',' ',$match[$line-1]))) . '" ';
405        if (isset($args)) {
406            // individual error message
407            $error_text .= $args;
408        } else {
409            // expected token from parser
410            $error_text .= ' - Unexpected "' . $this->lex->value.'"';
411            if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4 ) {
412            	foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
413            	    $exp_token = $this->parser->yyTokenName[$token];
414            	    if (isset($this->lex->smarty_token_names[$exp_token])) {
415            	        // token type from lexer
416            	        $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"';
417            	    } else {
418            	        // otherwise internal token name
419            	        $expect[] = $this->parser->yyTokenName[$token];
420            	    } 
421            	} 
422            	$error_text .= ', expected one of: ' . implode(' , ', $expect);
423        	}
424        } 
425        throw new SmartyCompilerException($error_text);
426    } 
427} 
428
429?>