From bc13ebbc9b4bdb1e7c9630664cf5753555217b5d Mon Sep 17 00:00:00 2001 From: Uwe Tews Date: Sat, 1 Nov 2014 22:42:34 +0100 Subject: [PATCH] -bugfix and enhancement on subtemplate {include} and template {function} tags. * Calling a template which has a nocache section could fail if it was called from a cached and a not cached subtemplate. * Calling the same subtemplate cached and not cached with the $smarty->merge_compiled_includes enabled could cause problems * Many smaller related changes --- change_log.txt | 6 + libs/Smarty.class.php | 35 +--- libs/sysplugins/smarty_cacheresource.php | 20 +- .../smarty_internal_compile_block.php | 17 +- .../smarty_internal_compile_call.php | 54 +---- .../smarty_internal_compile_function.php | 191 +++++++++++------ .../smarty_internal_compile_include.php | 43 ++-- .../smarty_internal_function_call_handler.php | 50 ++--- libs/sysplugins/smarty_internal_parsetree.php | 17 +- ...smarty_internal_smartytemplatecompiler.php | 5 +- libs/sysplugins/smarty_internal_template.php | 194 ++++++++++++------ .../smarty_internal_templatebase.php | 39 +++- .../smarty_internal_templatecompilerbase.php | 87 +++++--- libs/sysplugins/smarty_resource.php | 6 +- 14 files changed, 456 insertions(+), 308 deletions(-) diff --git a/change_log.txt b/change_log.txt index 2bcfde27..e2e14e8e 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,4 +1,10 @@ ===== 3.1.22-dev ===== (xx.xx.2014) + 01.11.2014 + -bugfix and enhancement on subtemplate {include} and template {function} tags. + * Calling a template which has a nocache section could fail if it was called from a cached and a not cached subtemplate. + * Calling the same subtemplate cached and not cached with the $smarty->merge_compiled_includes enabled could cause problems + * Many smaller related changes + 30.10.2014 - bugfix access to class constant by object like {$object::CONST} or variable class name {$class::CONST} did not work (forum 25301) diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 23f3c2e4..f9fb7be0 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -2,7 +2,7 @@ /** * Project: Smarty: the PHP compiling template engine * File: Smarty.class.php - * + * SVN: $Id: Smarty.class.php 4897 2014-10-14 22:29:58Z Uwe.Tews@googlemail.com $ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -24,7 +24,7 @@ * @author Uwe Tews * @author Rodney Rehm * @package Smarty - * @version 3.1.22-dev + * @version 3.1-DEV */ /** @@ -110,8 +110,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = 'Smarty-3.1.22-dev/1'; - + const SMARTY_VERSION = 'Smarty-3.1.21-dev/2'; /** * define variable scopes @@ -493,12 +492,6 @@ class Smarty extends Smarty_Internal_TemplateBase /**#@-*/ - /** - * global template functions - * - * @var array - */ - public $template_functions = array(); /** * resource type used if none given * Must be an valid key of $registered_resources. @@ -657,19 +650,13 @@ class Smarty extends Smarty_Internal_TemplateBase * @var bool */ public $_parserdebug = false; - /** - * Saved parameter of merged templates during compilation - * - * @var array - */ - public $merged_templates_func = array(); /** * Cache of is_file results of loadPlugin() - * + * * @var array */ - public static $_is_file_cache= array(); + public static $_is_file_cache = array(); /**#@-*/ @@ -687,10 +674,10 @@ class Smarty extends Smarty_Internal_TemplateBase $this->start_time = microtime(true); // set default dirs $this->setTemplateDir('.' . DS . 'templates' . DS) - ->setCompileDir('.' . DS . 'templates_c' . DS) - ->setPluginsDir(SMARTY_PLUGINS_DIR) - ->setCacheDir('.' . DS . 'cache' . DS) - ->setConfigDir('.' . DS . 'configs' . DS); + ->setCompileDir('.' . DS . 'templates_c' . DS) + ->setPluginsDir(SMARTY_PLUGINS_DIR) + ->setCacheDir('.' . DS . 'cache' . DS) + ->setConfigDir('.' . DS . 'configs' . DS); $this->debug_tpl = 'file:' . dirname(__FILE__) . '/debug.tpl'; if (isset($_SERVER['SCRIPT_NAME'])) { @@ -986,8 +973,8 @@ class Smarty extends Smarty_Internal_TemplateBase /** * Add config directory(s) * - * @param string|array $config_dir directory(s) of config sources - * @param mixed $key key of the array element to assign the config dir to + * @param string|array $config_dir directory(s) of config sources + * @param mixed $key key of the array element to assign the config dir to * * @return Smarty current Smarty instance for chaining */ diff --git a/libs/sysplugins/smarty_cacheresource.php b/libs/sysplugins/smarty_cacheresource.php index 667bee44..0329295e 100644 --- a/libs/sysplugins/smarty_cacheresource.php +++ b/libs/sysplugins/smarty_cacheresource.php @@ -386,11 +386,7 @@ class Smarty_Template_Cached if ($smarty->debugging) { Smarty_Internal_Debug::start_cache($_template); } - if ($handler->process($_template, $this) === false) { - $this->valid = false; - } else { - $this->processed = true; - } + $this->process($_template); if ($smarty->debugging) { Smarty_Internal_Debug::end_cache($_template); } @@ -413,6 +409,20 @@ class Smarty_Template_Cached } } + /** + * Process cached template + * + * @param Smarty_Internal_Template $_template template object + */ + public function process(Smarty_Internal_Template $_template) + { + if ($this->handler->process($_template, $this) === false) { + $this->valid = false; + } else { + $this->processed = true; + } + } + /** * Write this cache object to handler * diff --git a/libs/sysplugins/smarty_internal_compile_block.php b/libs/sysplugins/smarty_internal_compile_block.php index 8c2fb975..02294147 100644 --- a/libs/sysplugins/smarty_internal_compile_block.php +++ b/libs/sysplugins/smarty_internal_compile_block.php @@ -143,7 +143,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase // if called by {$smarty.block.child} we must search the name of enclosing {block} if ($_name == null) { $stack_count = count($compiler->_tag_stack); - while (--$stack_count >= 0) { + while (-- $stack_count >= 0) { if ($compiler->_tag_stack[$stack_count][0] == 'block') { $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'"); break; @@ -173,20 +173,18 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase $_tpl->compiler->suppressHeader = true; $_tpl->compiler->suppressFilter = true; $_tpl->compiler->suppressTemplatePropertyHeader = true; - $_tpl->compiler->suppressMergedTemplates = true; $nocache = $compiler->nocache || $compiler->tag_nocache; if (strpos($compiler->template->block_data[$_name]['source'], self::parent) !== false) { - $_output = str_replace(self::parent, $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl, $nocache)); + $_output = str_replace(self::parent, $compiler->parser->current_buffer->to_smarty_php(), $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler)); } elseif ($compiler->template->block_data[$_name]['mode'] == 'prepend') { - $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache) . $compiler->parser->current_buffer->to_smarty_php(); + $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler) . $compiler->parser->current_buffer->to_smarty_php(); } elseif ($compiler->template->block_data[$_name]['mode'] == 'append') { - $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl, $nocache); + $_output = $compiler->parser->current_buffer->to_smarty_php() . $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler); } elseif (!empty($compiler->template->block_data[$_name])) { - $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache); + $_output = $_tpl->compiler->compileTemplate($_tpl, $nocache, $compiler->parent_compiler); } $compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $_tpl->properties['file_dependency']); - $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $_tpl->properties['function']); - $compiler->merged_templates = array_merge($compiler->merged_templates, $_tpl->compiler->merged_templates); + $compiler->template->properties['tpl_function'] = array_merge($compiler->template->properties['tpl_function'], $_tpl->properties['tpl_function']); $compiler->template->variable_filters = $_tpl->variable_filters; if ($_tpl->has_nocache_code) { $compiler->template->has_nocache_code = true; @@ -221,7 +219,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase // if called by {$smarty.block.parent} we must search the name of enclosing {block} if ($_name == null) { $stack_count = count($compiler->_tag_stack); - while (--$stack_count >= 0) { + while (-- $stack_count >= 0) { if ($compiler->_tag_stack[$stack_count][0] == 'block') { $_name = trim($compiler->_tag_stack[$stack_count][1][0]['name'], "\"'"); break; @@ -245,7 +243,6 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_CompileBase * * @param $compiler * @param string $source source text - * */ static function blockSource($compiler, $source) { diff --git a/libs/sysplugins/smarty_internal_compile_call.php b/libs/sysplugins/smarty_internal_compile_call.php index bfbd1f54..025ee3d7 100644 --- a/libs/sysplugins/smarty_internal_compile_call.php +++ b/libs/sysplugins/smarty_internal_compile_call.php @@ -55,13 +55,11 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase // output will be stored in a smarty variable instead of being displayed $_assign = $_attr['assign']; } - $_name = $_attr['name']; - if ($compiler->compiles_template_function) { - $compiler->called_functions[] = trim($_name, "'\""); - } + $_name = trim($_attr['name'], "'\""); unset($_attr['name'], $_attr['assign'], $_attr['nocache']); // set flag (compiled code of {function} must be included in cache file - if ($compiler->nocache || $compiler->tag_nocache) { + if (!$compiler->template->caching || $compiler->nocache || $compiler->tag_nocache) { + $compiler->parent_compiler->templateProperties['tpl_function']['to_cache'][$_name] = true; $_nocache = 'true'; } else { $_nocache = 'false'; @@ -74,54 +72,14 @@ class Smarty_Internal_Compile_Call extends Smarty_Internal_CompileBase $_paramsArray[] = "'$_key'=>$_value"; } } - if (isset($compiler->template->properties['function'][$_name]['parameter'])) { - foreach ($compiler->template->properties['function'][$_name]['parameter'] as $_key => $_value) { - if (!isset($_attr[$_key])) { - if (is_int($_key)) { - $_paramsArray[] = "$_key=>$_value"; - } else { - $_paramsArray[] = "'$_key'=>$_value"; - } - } - } - } elseif (isset($compiler->smarty->template_functions[$_name]['parameter'])) { - foreach ($compiler->smarty->template_functions[$_name]['parameter'] as $_key => $_value) { - if (!isset($_attr[$_key])) { - if (is_int($_key)) { - $_paramsArray[] = "$_key=>$_value"; - } else { - $_paramsArray[] = "'$_key'=>$_value"; - } - } - } - } - //variable name? - if (!(strpos($_name, '$') === false)) { - $call_cache = $_name; - $call_function = '$tmp = "smarty_template_function_".' . $_name . '; $tmp'; - } else { - $_name = trim($_name, "'\""); - $call_cache = "'{$_name}'"; - $call_function = 'smarty_template_function_' . $_name; - } - $_params = 'array(' . implode(",", $_paramsArray) . ')'; - $_hash = str_replace('-', '_', $compiler->template->properties['nocache_hash']); + //$compiler->suppressNocacheProcessing = true; // was there an assign attribute if (isset($_assign)) { - if ($compiler->template->caching) { - $_output = "assign({$_assign}, ob_get_clean());?>\n"; - } else { - $_output = "assign({$_assign}, ob_get_clean());?>\n"; - } + $_output = "callTemplateFunction ('{$_name}', \$_smarty_tpl, {$_params}, {$_nocache}); \$_smarty_tpl->assign({$_assign}, ob_get_clean());?>\n"; } else { - if ($compiler->template->caching) { - $_output = "\n"; - } else { - $_output = "\n"; - } + $_output = "callTemplateFunction ('{$_name}', \$_smarty_tpl, {$_params}, {$_nocache});?>\n"; } - return $_output; } } diff --git a/libs/sysplugins/smarty_internal_compile_function.php b/libs/sysplugins/smarty_internal_compile_function.php index 298eb16f..0b6566a4 100644 --- a/libs/sysplugins/smarty_internal_compile_function.php +++ b/libs/sysplugins/smarty_internal_compile_function.php @@ -56,39 +56,18 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); } unset($_attr['nocache']); - $save = array($_attr, $compiler->parser->current_buffer, - $compiler->template->has_nocache_code, $compiler->template->required_plugins); - $this->openTag($compiler, 'function', $save); $_name = trim($_attr['name'], "'\""); - unset($_attr['name']); + + $save = array($_attr, $compiler->parser->current_buffer, + $compiler->template->has_nocache_code, $compiler->template->required_plugins, $compiler->template->caching); + $this->openTag($compiler, 'function', $save); // set flag that we are compiling a template function $compiler->compiles_template_function = true; - $compiler->template->properties['function'][$_name]['parameter'] = array(); - /** @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $compiler->template; - foreach ($_attr as $_key => $_data) { - eval ('$tmp=' . $_data . ';'); - $compiler->template->properties['function'][$_name]['parameter'][$_key] = $tmp; - } - $compiler->smarty->template_functions[$_name]['parameter'] = $compiler->template->properties['function'][$_name]['parameter']; - if ($compiler->template->caching) { - $output = ''; - } else { - $output = "tpl_vars; - foreach (\$_smarty_tpl->smarty->template_functions['{$_name}']['parameter'] as \$key => \$value) {\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);}; - foreach (\$params as \$key => \$value) {\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);}?>"; - } // Init temporary context $compiler->template->required_plugins = array('compiled' => array(), 'nocache' => array()); $compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser); - $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $output)); $compiler->template->has_nocache_code = false; - $compiler->has_code = false; - $compiler->template->properties['function'][$_name]['compiled'] = ''; + $compiler->template->caching = true; return true; } } @@ -101,6 +80,13 @@ class Smarty_Internal_Compile_Function extends Smarty_Internal_CompileBase */ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase { + /** + * Compiler object + * + * @var object + */ + private $compiler = null; + /** * Compiles code for the {/function} tag * @@ -112,51 +98,120 @@ class Smarty_Internal_Compile_Functionclose extends Smarty_Internal_CompileBase */ public function compile($args, $compiler, $parameter) { - $_attr = $this->getAttributes($compiler, $args); + $this->compiler = $compiler; $saved_data = $this->closeTag($compiler, array('function')); - $_name = trim($saved_data[0]['name'], "'\""); - // build plugin include code - $plugins_string = ''; - if (!empty($compiler->template->required_plugins['compiled'])) { - $plugins_string = 'template->required_plugins['compiled'] as $tmp) { - foreach ($tmp as $data) { - $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n"; - } - } - $plugins_string .= '?>'; - } - if (!empty($compiler->template->required_plugins['nocache'])) { - $plugins_string .= "template->properties['nocache_hash']}%%*/template->required_plugins['nocache'] as $tmp) { - foreach ($tmp as $data) { - $plugins_string .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n"; - } - } - $plugins_string .= "?>/*/%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/';?>\n"; - } - // if caching save template function for possible nocache call - if ($compiler->template->caching) { - $compiler->template->properties['function'][$_name]['compiled'] .= $plugins_string - . $compiler->parser->current_buffer->to_smarty_php(); - $compiler->template->properties['function'][$_name]['nocache_hash'] = $compiler->template->properties['nocache_hash']; - $compiler->template->properties['function'][$_name]['has_nocache_code'] = $compiler->template->has_nocache_code; - $compiler->template->properties['function'][$_name]['called_functions'] = $compiler->called_functions; - $compiler->called_functions = array(); - $compiler->smarty->template_functions[$_name] = $compiler->template->properties['function'][$_name]; - $compiler->has_code = false; - $output = true; - } else { - $output = $plugins_string . $compiler->parser->current_buffer->to_smarty_php() . "tpl_vars = \$saved_tpl_vars; -foreach (Smarty::\$global_tpl_vars as \$key => \$value) if(!isset(\$_smarty_tpl->tpl_vars[\$key])) \$_smarty_tpl->tpl_vars[\$key] = \$value;}}?>\n"; - } + $_attr = $saved_data[0]; + $_name = trim($_attr['name'], "'\""); // reset flag that we are compiling a template function $compiler->compiles_template_function = false; - // restore old compiler status - $compiler->parser->current_buffer = $saved_data[1]; - $compiler->template->has_nocache_code = $compiler->template->has_nocache_code | $saved_data[2]; - $compiler->template->required_plugins = $saved_data[3]; + $compiler->parent_compiler->templateProperties['tpl_function']['param'][$_name]['called_functions'] = $compiler->called_functions; + $compiler->parent_compiler->templateProperties['tpl_function']['param'][$_name]['compiled_filepath'] = $compiler->parent_compiler->template->compiled->filepath; + $compiler->called_functions = array(); + $_parameter = $_attr; + unset($_parameter['name']); + // default parameter + $_paramsArray = array(); + foreach ($_parameter as $_key => $_value) { + if (is_int($_key)) { + $_paramsArray[] = "$_key=>$_value"; + } else { + $_paramsArray[] = "'$_key'=>$_value"; + } + } + if (!empty($_paramsArray)) { + $_params = 'array(' . implode(",", $_paramsArray) . ')'; + $_paramsCode = "\$params = array_merge(($_params), \$params);\n"; + } else { + $_paramsCode = ''; + } + $_functionCode = $compiler->parser->current_buffer->to_smarty_php(); + // setup buffer for template function code + $compiler->parser->current_buffer = new _smarty_template_buffer($compiler->parser); - return $output; + $_funcName = "smarty_template_function_{$_name}_{$compiler->template->properties['nocache_hash']}"; + $_funcNameCaching = $_funcName . '_nocache'; + if ($compiler->template->has_nocache_code) { + $compiler->parent_compiler->templateProperties['tpl_function']['param'][$_name]['call_name_caching'] = $_funcNameCaching; + $output = "template->required_plugins['compiled'])) { + foreach ($compiler->template->required_plugins['compiled'] as $tmp) { + foreach ($tmp as $data) { + $output .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n"; + } + } + } + if (!empty($compiler->template->required_plugins['nocache'])) { + $output .= "echo '/*%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/template->required_plugins['nocache'] as $tmp) { + foreach ($tmp as $data) { + $output .= "if (!is_callable(\'{$data['function']}\')) include \'{$data['file']}\';\n"; + } + } + $output .= "?>/*/%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%*/';\n"; + } + $output .= "\$saved_tpl_vars = \$_smarty_tpl->tpl_vars;\n"; + $output .= $_paramsCode; + $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);\n}\n"; + $output .= "ob_start();\n?>"; + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $output)); + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $_functionCode)); + $output = "template->properties['nocache_hash']}', \"{\$_smarty_tpl->properties['nocache_hash']}\", ob_get_clean());\n"; + $output .= "\$_smarty_tpl->tpl_vars = \$saved_tpl_vars; +foreach (Smarty::\$global_tpl_vars as \$key => \$value) if(!isset(\$_smarty_tpl->tpl_vars[\$key])) \$_smarty_tpl->tpl_vars[\$key] = \$value;\n}\n}\n"; + $output .= "/*/ {$_funcName}_nocache */\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $output)); + $_functionCode = preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->properties['nocache_hash']}%%\*\/';(\?>\n)?)/", array($this, 'removeNocache'), $_functionCode); + } + $compiler->parent_compiler->templateProperties['tpl_function']['param'][$_name]['call_name'] = $_funcName; + $output = "template->required_plugins['nocache'])) { + $compiler->template->required_plugins['compiled'] = array_merge($compiler->template->required_plugins['compiled'], $compiler->template->required_plugins['nocache']); + } + if (!empty($compiler->template->required_plugins['compiled'])) { + foreach ($compiler->template->required_plugins['compiled'] as $tmp) { + foreach ($tmp as $data) { + $output .= "if (!is_callable('{$data['function']}')) include '{$data['file']}';\n"; + } + } + } + $output .= "\$saved_tpl_vars = \$_smarty_tpl->tpl_vars;\n"; + $output .= $_paramsCode; + $output .= "foreach (\$params as \$key => \$value) {\n\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);\n}?>"; + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $output)); + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $_functionCode)); + $output = "tpl_vars = \$saved_tpl_vars; +foreach (Smarty::\$global_tpl_vars as \$key => \$value) if(!isset(\$_smarty_tpl->tpl_vars[\$key])) \$_smarty_tpl->tpl_vars[\$key] = \$value;\n}\n}\n"; + $output .= "/*/ {$_funcName} */\n"; + $output .= "?>\n"; + $compiler->parser->current_buffer->append_subtree(new _smarty_tag($compiler->parser, $output)); + $compiler->parent_compiler->templateFunctionCode .= $compiler->parser->current_buffer->to_smarty_php(); + // restore old buffer + $compiler->parser->current_buffer = $saved_data[1]; + // restore old status + $compiler->template->has_nocache_code = $saved_data[2]; + $compiler->template->required_plugins = $saved_data[3]; + $compiler->template->caching = $saved_data[4]; + return true; + } + + /** + * @param $match + * + * @return mixed + */ + function removeNocache($match) + { + $code = preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->properties['nocache_hash']}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->properties['nocache_hash']}%%\*\/';(\?>\n)?)/", '', $match[0]); + $code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code); + return $code; } } diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php index 35067f78..94ff9d19 100644 --- a/libs/sysplugins/smarty_internal_compile_include.php +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -89,11 +89,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase if ($_attr['nocache'] === true) { $compiler->tag_nocache = true; - } + } // set default when in nocache mode if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) { - //if ($compiler->template->caching && ((!$compiler->inheritance && !$compiler->nocache && !$compiler->tag_nocache) || ($compiler->inheritance && ($compiler->nocache || $compiler->tag_nocache)))) { + //if ($compiler->template->caching && ((!$compiler->inheritance && !$compiler->nocache && !$compiler->tag_nocache) || ($compiler->inheritance && ($compiler->nocache || $compiler->tag_nocache)))) { $_caching = self::CACHING_NOCACHE_CODE; } /* @@ -149,13 +149,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase } if ($merge_compiled_includes) { if ($compiler->template->caching && ($compiler->tag_nocache || $compiler->nocache) && $_caching != self::CACHING_NOCACHE_CODE) { -// $merge_compiled_includes = false; + // $merge_compiled_includes = false; if ($compiler->inheritance && $compiler->smarty->inheritance_merge_compiled_includes) { $compiler->trigger_template_error(' invalid caching mode of subtemplate within {block} tags'); } } - } - if ($merge_compiled_includes) { // we must observe different compile_id and caching $uid = sha1($_compile_id . ($_caching ? '--caching' : '--nocaching')); $tpl_name = null; @@ -164,13 +162,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase */ $_smarty_tpl = $compiler->template; eval("\$tpl_name = $include_file;"); - if (!isset($compiler->smarty->merged_templates_func[$tpl_name][$uid])) { + if (!isset($compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid])) { $tpl = new $compiler->smarty->template_class ($tpl_name, $compiler->smarty, $compiler->template, $compiler->template->cache_id, $compiler->template->compile_id, $_caching); // save unique function name - $compiler->smarty->merged_templates_func[$tpl_name][$uid]['func'] = $tpl->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); - // use current nocache hash for inlined code - $compiler->smarty->merged_templates_func[$tpl_name][$uid]['nocache_hash'] = $tpl->properties['nocache_hash'] = $compiler->template->properties['nocache_hash']; - if ($compiler->inheritance) { + $compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func'] = $tpl->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); + if ($compiler->inheritance) { $tpl->compiler->inheritance = true; } // make sure whole chain gets compiled @@ -178,11 +174,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase if (!($tpl->source->uncompiled) && $tpl->source->exists) { // get compiled code - $compiled_code = $tpl->compiler->compileTemplate($tpl); - // release compiler object to free memory + $compiled_code = $tpl->compiler->compileTemplate($tpl, null, $compiler->parent_compiler); + $compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['nocache_hash'] = $tpl->properties['nocache_hash']; unset($tpl->compiler); // merge compiled code for {function} tags - $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['function']); + $compiler->template->properties['tpl_function'] = array_merge($compiler->template->properties['tpl_function'], $tpl->properties['tpl_function']); // merge filedependency $tpl->properties['file_dependency'][$tpl->source->uid] = array($tpl->source->filepath, $tpl->source->timestamp, $tpl->source->type); $compiler->template->properties['file_dependency'] = array_merge($compiler->template->properties['file_dependency'], $tpl->properties['file_dependency']); @@ -193,7 +189,7 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase $compiled_code = str_replace("{$tpl->properties['nocache_hash']}", $compiler->template->properties['nocache_hash'], $compiled_code); $compiler->template->has_nocache_code = true; } - $compiler->merged_templates[$tpl->properties['unifunc']] = $compiled_code; + $compiler->parent_compiler->mergedSubTemplatesCode[$tpl->properties['unifunc']] = $compiled_code; $has_compiled_template = true; unset ($tpl); } @@ -222,24 +218,21 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase if ($has_compiled_template) { // never call inline templates in nocache mode $compiler->suppressNocacheProcessing = true; - $_hash = $compiler->smarty->merged_templates_func[$tpl_name][$uid]['nocache_hash']; + $_hash = $compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['nocache_hash']; $_output = "caching) { $compiler->suppressNocacheProcessing = false; - $_output .= substr($compiler->processNocacheCode('\n", true), 6, -3); + $_output .= substr($compiler->processNocacheCode('\n", true), 6, - 3); $compiler->suppressNocacheProcessing = true; } - $_output .= " \$_smarty_tpl = \$_smarty_tpl->setupInlineSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, '$_hash');\n"; if (isset($_assign)) { - $_output .= 'ob_start(); '; + $_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_variable(\$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, '{$_hash}', '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}'));\n"; + } else { + $_output .= "echo \$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, '{$_hash}', '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}');\n"; } - $_output .= $compiler->smarty->merged_templates_func[$tpl_name][$uid]['func'] . "(\$_smarty_tpl);\n"; - $_output .= "\$_smarty_tpl = array_pop(\$_tpl_stack); "; - if (isset($_assign)) { - $_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_variable(ob_get_clean());"; - } - $_output .= "\n/* End of included template \"" . $tpl_name . "\" */?>"; + // $_output .= "\$_smarty_tpl = array_pop(\$_tpl_stack); "; + $_output .= "/* End of included template \"" . $tpl_name . "\" */?>\n"; return $_output; } diff --git a/libs/sysplugins/smarty_internal_function_call_handler.php b/libs/sysplugins/smarty_internal_function_call_handler.php index a81ff728..a8d68c85 100644 --- a/libs/sysplugins/smarty_internal_function_call_handler.php +++ b/libs/sysplugins/smarty_internal_function_call_handler.php @@ -19,34 +19,36 @@ class Smarty_Internal_Function_Call_Handler * This function handles calls to template functions defined by {function} * It does create a PHP function at the first call * - * @param string $_name template function name - * @param Smarty_Internal_Template $_template template object - * @param array $_params Smarty variables passed as call parameter - * @param string $_hash nocache hash value - * @param bool $_nocache nocache flag + * @param string $_name template function name + * @param Smarty_Internal_Template $_smarty_tpl + * @param $_function + * @param array $_params Smarty variables passed as call parameter + * @param bool $_nocache nocache flag + * + * @return bool */ - public static function call($_name, Smarty_Internal_Template $_template, $_params, $_hash, $_nocache) + public static function call($_name, Smarty_Internal_Template $_smarty_tpl, $_function, $_params, $_nocache) { - if ($_nocache) { - $_function = "smarty_template_function_{$_name}_nocache"; - } else { - $_function = "smarty_template_function_{$_hash}_{$_name}"; + $funcParam = $_smarty_tpl->properties['tpl_function']['param'][$_name]; + $code = file_get_contents($funcParam['compiled_filepath']); + if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) { + $output = "\n"; + $output .= $match[0]; + $output .= "?>\n"; } - if (!is_callable($_function)) { - $_code = "function {$_function}(\$_smarty_tpl,\$params) { - \$saved_tpl_vars = \$_smarty_tpl->tpl_vars; - foreach (\$_smarty_tpl->smarty->template_functions['{$_name}']['parameter'] as \$key => \$value) {\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);}; - foreach (\$params as \$key => \$value) {\$_smarty_tpl->tpl_vars[\$key] = new Smarty_variable(\$value);}?>"; - if ($_nocache) { - $_code .= preg_replace(array("!<\?php echo \\'/\*%%SmartyNocache:{$_template->smarty->template_functions[$_name]['nocache_hash']}%%\*/|/\*/%%SmartyNocache:{$_template->smarty->template_functions[$_name]['nocache_hash']}%%\*/\\';\?>!", - "!\\\'!"), array('', "'"), $_template->smarty->template_functions[$_name]['compiled']); - $_template->smarty->template_functions[$_name]['called_nocache'] = true; - } else { - $_code .= preg_replace("/{$_template->smarty->template_functions[$_name]['nocache_hash']}/", $_template->properties['nocache_hash'], $_template->smarty->template_functions[$_name]['compiled']); + unset($code, $match); + eval($output); + if (function_exists($_function)) { + $_function ($_smarty_tpl, $_params); + $tplPtr = $_smarty_tpl; + while (isset($tplPtr->parent) && !isset($tplPtr->parent->cached)) { + $tplPtr = $tplPtr->parent; } - $_code .= "tpl_vars = \$saved_tpl_vars;}"; - eval($_code); + if (isset($tplPtr->parent->cached)) { + $cached = $tplPtr->parent->cached; + } + return true; } - $_function($_template, $_params); + return false; } } diff --git a/libs/sysplugins/smarty_internal_parsetree.php b/libs/sysplugins/smarty_internal_parsetree.php index 18667102..f93d0970 100644 --- a/libs/sysplugins/smarty_internal_parsetree.php +++ b/libs/sysplugins/smarty_internal_parsetree.php @@ -90,8 +90,8 @@ class _smarty_tag extends _smarty_parsetree */ public function assign_to_var() { - $var = sprintf('$_tmp%d', ++Smarty_Internal_Templateparser::$prefix_number); - $this->parser->compiler->prefix_code[] = sprintf("", preg_replace(array('/^\s*<\?php\s+/','/\s*\?>\s*$/'), '', $this->data), $var); + $var = sprintf('$_tmp%d', ++ Smarty_Internal_Templateparser::$prefix_number); + $this->parser->compiler->prefix_code[] = sprintf("", preg_replace(array('/^\s*<\?php\s+/', '/\s*\?>\s*$/'), '', $this->data), $var); return $var; } @@ -287,8 +287,8 @@ class _smarty_template_buffer extends _smarty_parsetree for ($key = 0, $cnt = count($this->subtrees); $key < $cnt; $key ++) { if ($this->subtrees[$key] instanceof _smarty_text) { $subtree = $this->subtrees[$key]->to_smarty_php(); - while ($key + 1 < $cnt && ($this->subtrees[$key+1] instanceof _smarty_text || $this->subtrees[$key +1]->data == '')) { - $key++; + while ($key + 1 < $cnt && ($this->subtrees[$key + 1] instanceof _smarty_text || $this->subtrees[$key + 1]->data == '')) { + $key ++; if ($this->subtrees[$key]->data == '') { continue; } @@ -302,14 +302,14 @@ class _smarty_template_buffer extends _smarty_parsetree } if ($this->subtrees[$key] instanceof _smarty_tag) { $subtree = $this->subtrees[$key]->to_smarty_php(); - while ($key + 1 < $cnt && ($this->subtrees[$key+1] instanceof _smarty_tag || $this->subtrees[$key +1]->data == '')) { - $key++; + while ($key + 1 < $cnt && ($this->subtrees[$key + 1] instanceof _smarty_tag || $this->subtrees[$key + 1]->data == '')) { + $key ++; if ($this->subtrees[$key]->data == '') { continue; } $newCode = $this->subtrees[$key]->to_smarty_php(); - if ((preg_match('/^\s*<\?php\s+/', $newCode) && preg_match('/\s*\?>\s*$/', $subtree))) { - $subtree = preg_replace('/\s*\?>\s*$/', "\n", $subtree); + if ((preg_match('/^\s*<\?php\s+/', $newCode) && preg_match('/\s*\?>\s*$/', $subtree))) { + $subtree = preg_replace('/\s*\?>\s*$/', "", $subtree); $subtree .= preg_replace('/^\s*<\?php\s+/', '', $newCode); } else { $subtree .= $newCode; @@ -325,7 +325,6 @@ class _smarty_template_buffer extends _smarty_parsetree } return $code; } - } /** diff --git a/libs/sysplugins/smarty_internal_smartytemplatecompiler.php b/libs/sysplugins/smarty_internal_smartytemplatecompiler.php index 50bd16ef..2fc48007 100644 --- a/libs/sysplugins/smarty_internal_smartytemplatecompiler.php +++ b/libs/sysplugins/smarty_internal_smartytemplatecompiler.php @@ -86,7 +86,7 @@ class Smarty_Internal_SmartyTemplateCompiler extends Smarty_Internal_TemplateCom * * @return bool true if compiling succeeded, false if it failed */ - protected function doCompile($_content) + protected function doCompile($_content, $isTemplateSource = false) { /* here is where the compiling takes place. Smarty tags in the templates are replaces with PHP code, @@ -94,6 +94,9 @@ class Smarty_Internal_SmartyTemplateCompiler extends Smarty_Internal_TemplateCom // init the lexer/parser to compile the template $this->lex = new $this->lexer_class($_content, $this); $this->parser = new $this->parser_class($this->lex, $this); + if ($isTemplateSource) { + $this->parser->insertPhpCode("properties['nocache_hash'] = '{$this->nocache_hash}';\n?>\n"); + } if ($this->inheritance_child) { // start state on child templates $this->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY); diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index f1a73a4a..28a68d77 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -67,7 +67,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public $properties = array('file_dependency' => array(), 'nocache_hash' => '', - 'function' => array()); + 'tpl_function' => array(), + 'type' => 'compiled', + ); /** * required plugins * @@ -126,7 +128,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null) { - $this->smarty = & $smarty; + $this->smarty = &$smarty; // Smarty parameter $this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id; $this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id; @@ -238,11 +240,12 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase /** @var Smarty_Internal_Template $_smarty_tpl * used in evaluated code */ - $_smarty_tpl = $this; - eval("?>" . $content); - $this->cached->valid = true; - $this->cached->processed = true; - + /** + * $_smarty_tpl = $this; + * eval("?>" . $content); + * $this->cached->valid = true; + * $this->cached->processed = true; + */ return $this->cached->write($this, $content); } @@ -275,6 +278,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase // clone cached template object because of possible recursive call $tpl = clone $this->smarty->template_objects[$_templateId]; $tpl->parent = $this; + if ((bool) $tpl->caching !== (bool) $caching) { + unset($tpl->compiled); + } $tpl->caching = $caching; $tpl->cache_lifetime = $cache_lifetime; } else { @@ -285,13 +291,13 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $tpl->tpl_vars = $this->tpl_vars; $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty']; } elseif ($parent_scope == Smarty::SCOPE_PARENT) { - $tpl->tpl_vars = & $this->tpl_vars; + $tpl->tpl_vars = &$this->tpl_vars; } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { - $tpl->tpl_vars = & Smarty::$global_tpl_vars; + $tpl->tpl_vars = &Smarty::$global_tpl_vars; } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { - $tpl->tpl_vars = & $this->tpl_vars; + $tpl->tpl_vars = &$this->tpl_vars; } else { - $tpl->tpl_vars = & $scope_ptr->tpl_vars; + $tpl->tpl_vars = &$scope_ptr->tpl_vars; } $tpl->config_vars = $this->config_vars; if (!empty($data)) { @@ -316,24 +322,25 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase * @param int $parent_scope scope in which {include} should execute * @param string $hash nocache hash code * - * @returns string template content + * @returns object template object */ public function setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash) { $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); $tpl->properties['nocache_hash'] = $hash; + $tpl->properties['tpl_function'] = $this->properties['tpl_function']; // get variables from calling scope if ($parent_scope == Smarty::SCOPE_LOCAL) { $tpl->tpl_vars = $this->tpl_vars; $tpl->tpl_vars['smarty'] = clone $this->tpl_vars['smarty']; } elseif ($parent_scope == Smarty::SCOPE_PARENT) { - $tpl->tpl_vars = & $this->tpl_vars; + $tpl->tpl_vars = &$this->tpl_vars; } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { - $tpl->tpl_vars = & Smarty::$global_tpl_vars; + $tpl->tpl_vars = &Smarty::$global_tpl_vars; } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { - $tpl->tpl_vars = & $this->tpl_vars; + $tpl->tpl_vars = &$this->tpl_vars; } else { - $tpl->tpl_vars = & $scope_ptr->tpl_vars; + $tpl->tpl_vars = &$scope_ptr->tpl_vars; } $tpl->config_vars = $this->config_vars; if (!empty($data)) { @@ -346,6 +353,62 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase return $tpl; } + /** + * Template code runtime function to set up an inline subtemplate + * + * @param string $template the resource handle of the template file + * @param mixed $cache_id cache id to be used with this template + * @param mixed $compile_id compile id to be used with this template + * @param integer $caching cache mode + * @param integer $cache_lifetime life time of cache data + * @param $data + * @param int $parent_scope scope in which {include} should execute + * @param string $hash nocache hash code + * @param string $content_func name of content function + * + * @returns object template content + */ + public function getInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash, $content_func) + { + $tpl = $this->setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash); + ob_start(); + $content_func($tpl); + return str_replace($tpl->properties['nocache_hash'], $this->properties['nocache_hash'], ob_get_clean()); + } + + /** + * Call template function + * + * @param string $name template function name + * @param object $_smarty_tpl template object + * @param array $params parameter array + * @param bool $nocache true if called nocache + */ + public function callTemplateFunction($name, $_smarty_tpl, $params, $nocache) + { + if (isset($_smarty_tpl->properties['tpl_function']['param'][$name])) { + if (!$_smarty_tpl->caching || ($_smarty_tpl->caching && $nocache) || $_smarty_tpl->properties['type'] !== 'cache') { + $_smarty_tpl->properties['tpl_function']['to_cache'][$name] = true; + $function = $_smarty_tpl->properties['tpl_function']['param'][$name]['call_name']; + } else { + if (isset($_smarty_tpl->properties['tpl_function']['param'][$name]['call_name_caching'])) { + $function = $_smarty_tpl->properties['tpl_function']['param'][$name]['call_name_caching']; + } else { + $function = $_smarty_tpl->properties['tpl_function']['param'][$name]['call_name']; + } + } + if (function_exists($function)) { + $function ($_smarty_tpl, $params); + return; + } + // try to load template function dynamically + if (Smarty_Internal_Function_Call_Handler::call($name, $_smarty_tpl, $function, $params, $nocache)) { + return; + } + } + throw new SmartyException("Unable to find template function '{$name}'"); + } + /** * Create code frame for compiled and cached templates * @@ -391,32 +454,17 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } // build property code $this->properties['has_nocache_code'] = $this->has_nocache_code; - $output = ''; + $output = 'source->recompiled) { - $output = "properties['nocache_hash']}%%*/"; + $output .= "/*%%SmartyHeaderCode:{$this->properties['nocache_hash']}%%*/"; if ($this->smarty->direct_access_security) { $output .= "if(!defined('SMARTY_DIR')) exit('no direct access allowed');\n"; } } if ($cache) { - // remove compiled code of{function} definition - unset($this->properties['function']); - if (!empty($this->smarty->template_functions)) { - // copy code of {function} tags called in nocache mode - foreach ($this->smarty->template_functions as $name => $function_data) { - if (isset($function_data['called_nocache'])) { - foreach ($function_data['called_functions'] as $func_name) { - $this->smarty->template_functions[$func_name]['called_nocache'] = true; - } - } - } - foreach ($this->smarty->template_functions as $name => $function_data) { - if (isset($function_data['called_nocache'])) { - unset($function_data['called_nocache'], $function_data['called_functions'], $this->smarty->template_functions[$name]['called_nocache']); - $this->properties['function'][$name] = $function_data; - } - } - } + $this->properties['type'] = 'cache'; + } else { + $this->properties['type'] = 'compiled'; } $this->properties['version'] = Smarty::SMARTY_VERSION; if (!isset($this->properties['unifunc'])) { @@ -424,14 +472,34 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } if (!$this->source->recompiled) { $output .= "\$_valid = \$_smarty_tpl->decodeProperties(" . var_export($this->properties, true) . ',' . ($cache ? 'true' : 'false') . "); /*/%%SmartyHeaderCode%%*/?>\n"; - $output .= 'properties['unifunc'] . '\')) {function ' . $this->properties['unifunc'] . '($_smarty_tpl) {?>'; + $output .= "properties['unifunc']}')) {function {$this->properties['unifunc']} (\$_smarty_tpl) {\n"; } - $output .= $plugins_string; - $output .= $content; + $output .= "\$_saved_type = \$_smarty_tpl->properties['type'];\n"; + $output .= "\$_smarty_tpl->properties['type'] = \$_smarty_tpl->caching ? 'cache' : 'compiled';?>\n"; + $output .= $plugins_string . $content; + $output .= "properties['type'] = \$_saved_type;?>\n"; if (!$this->source->recompiled) { $output .= "\n"; } - + if ($cache && isset($this->properties['tpl_function']['param'])) { + $requiredFunctions = array(); + foreach ($this->properties['tpl_function']['param'] as $name => $param) { + if (isset($this->properties['tpl_function']['to_cache'][$name])) { + $requiredFunctions[$param['compiled_filepath']][$name] = $param; + } + } + foreach ($requiredFunctions as $filepath => $functions) { + $code = file_get_contents($filepath); + foreach ($functions as $name => $param) { + if (preg_match("/\/\* {$param['call_name']} \*\/([\S\s]*?)\/\*\/ {$param['call_name']} \*\//", $code, $match)) { + $output .= "\n"; + } + } + unset($code, $match); + } + } return $output; } @@ -447,26 +515,14 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public function decodeProperties($properties, $cache = false) { - $this->has_nocache_code = $properties['has_nocache_code']; - $this->properties['nocache_hash'] = $properties['nocache_hash']; - if (isset($properties['cache_lifetime'])) { - $this->properties['cache_lifetime'] = $properties['cache_lifetime']; - } - if (isset($properties['file_dependency'])) { - $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']); - } - if (!empty($properties['function'])) { - $this->properties['function'] = array_merge($this->properties['function'], $properties['function']); - $this->smarty->template_functions = array_merge($this->smarty->template_functions, $properties['function']); - } - $this->properties['version'] = (isset($properties['version'])) ? $properties['version'] : ''; - $this->properties['unifunc'] = $properties['unifunc']; - // check file dependencies at compiled code + $properties['version'] = (isset($properties['version'])) ? $properties['version'] : ''; $is_valid = true; - if ($this->properties['version'] != Smarty::SMARTY_VERSION) { + if (Smarty::SMARTY_VERSION != $properties['version']) { + // new version must rebuild $is_valid = false; - } elseif (((!$cache && $this->smarty->compile_check && empty($this->compiled->_properties) && !$this->compiled->isCompiled) || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($this->properties['file_dependency'])) { - foreach ($this->properties['file_dependency'] as $_file_to_check) { + } elseif (((!$cache && $this->smarty->compile_check && empty($this->compiled->_properties) && !$this->compiled->isCompiled) || $cache && ($this->smarty->compile_check === true || $this->smarty->compile_check === Smarty::COMPILECHECK_ON)) && !empty($properties['file_dependency'])) { + // check file dependencies at compiled code + foreach ($properties['file_dependency'] as $_file_to_check) { if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'php') { if ($this->source->filepath == $_file_to_check[0] && isset($this->source->timestamp)) { // do not recheck current template @@ -490,8 +546,8 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if ($cache) { // CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc if ($this->caching === Smarty::CACHING_LIFETIME_SAVED && - $this->properties['cache_lifetime'] >= 0 && - (time() > ($this->cached->timestamp + $this->properties['cache_lifetime'])) + $properties['cache_lifetime'] >= 0 && + (time() > ($this->cached->timestamp + $properties['cache_lifetime'])) ) { $is_valid = false; } @@ -503,7 +559,23 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if (!$cache) { $this->compiled->_properties = $properties; } - + if ($is_valid) { + $this->has_nocache_code = $properties['has_nocache_code']; + // $this->properties['nocache_hash'] = $properties['nocache_hash']; + if (isset($properties['cache_lifetime'])) { + $this->properties['cache_lifetime'] = $properties['cache_lifetime']; + } + if (isset($properties['file_dependency'])) { + $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $properties['file_dependency']); + } + $this->properties['tpl_function']['param'] = isset($this->parent->properties['tpl_function']['param']) ? $this->parent->properties['tpl_function']['param'] : array(); + if (isset($properties['tpl_function']['param'])) { + $this->properties['tpl_function']['param'] = array_merge($this->properties['tpl_function']['param'], $properties['tpl_function']['param']); + } + $this->properties['version'] = $properties['version']; + $this->properties['unifunc'] = $properties['unifunc']; + $this->properties['type'] = $properties['type']; + } return $is_valid; } diff --git a/libs/sysplugins/smarty_internal_templatebase.php b/libs/sysplugins/smarty_internal_templatebase.php index a1e561cb..38862e3c 100644 --- a/libs/sysplugins/smarty_internal_templatebase.php +++ b/libs/sysplugins/smarty_internal_templatebase.php @@ -112,8 +112,6 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data } } } - // must reset merge template date - $_template->smarty->merged_templates_func = array(); // get rendered template // disable caching for evaluated code if ($_template->source->recompiled) { @@ -220,6 +218,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data } if ($_template->parent instanceof Smarty_Internal_Template) { $_template->parent->properties['file_dependency'] = array_merge($_template->parent->properties['file_dependency'], $_template->properties['file_dependency']); + $_template->parent->properties['tpl_function'] = array_merge($_template->parent->properties['tpl_function'], $_template->properties['tpl_function']); foreach ($_template->required_plugins as $code => $tmp1) { foreach ($tmp1 as $name => $tmp) { foreach ($tmp as $type => $data) { @@ -249,7 +248,8 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data if (isset($cache_parts[0][$curr_idx])) { $_template->properties['has_nocache_code'] = true; // remove nocache tags from cache output - $output .= preg_replace("!/\*/?%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]); + //$output .= preg_replace("!/\*/?%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!", '', $cache_parts[0][$curr_idx]); + $output .= $cache_parts[1][$curr_idx]; } } if (!$no_output_filter && !$_template->has_nocache_code && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) { @@ -259,18 +259,45 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data /** @var Smarty_Internal_Template $_smarty_tpl * used in evaluated code */ + $_smarty_tpl = $_template; + // $_template->properties['type'] = 'cache'; + /// $_template->properties['cache_lifetime'] = $this->cache_lifetime; + // $_template->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); + // $content = $_template->createTemplateCodeFrame($output, true); + try { ob_start(); eval("?>" . $output); + ob_get_clean(); + } + catch (Exception $e) { + ob_get_clean(); + throw $e; + } + + // write cache file content + $_template->writeCachedContent($output); + unset($output); + $_template->cached->handler->process($_template); + try { + ob_start(); + array_unshift($_template->_capture_stack, array()); + // + // render cached template + // + $_template->properties['unifunc']($_template); + // any unclosed {capture} tags ? + if (isset($_template->_capture_stack[0][0])) { + $_template->capture_error(); + } + array_shift($_template->_capture_stack); $_output = ob_get_clean(); } catch (Exception $e) { ob_get_clean(); throw $e; } - // write cache file content - $_template->writeCachedContent($output); if ($this->smarty->debugging) { Smarty_Internal_Debug::end_cache($_template); } @@ -849,7 +876,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data } } else { throw new SmartyException("property '$property_name' does not exist."); - } + } } if ($name == 'Smarty') { throw new SmartyException("PHP5 requires you to call __construct() instead of Smarty()"); diff --git a/libs/sysplugins/smarty_internal_templatecompilerbase.php b/libs/sysplugins/smarty_internal_templatecompilerbase.php index d00bfb8f..5b07c143 100644 --- a/libs/sysplugins/smarty_internal_templatecompilerbase.php +++ b/libs/sysplugins/smarty_internal_templatecompilerbase.php @@ -22,7 +22,7 @@ abstract class Smarty_Internal_TemplateCompilerBase * * @var mixed */ - private $nocache_hash = null; + public $nocache_hash = null; /** * suppress generation of nocache code @@ -31,13 +31,6 @@ abstract class Smarty_Internal_TemplateCompilerBase */ public $suppressNocacheProcessing = false; - /** - * suppress generation of merged template code - * - * @var bool - */ - public $suppressMergedTemplates = false; - /** * compile tag objects * @@ -60,11 +53,25 @@ abstract class Smarty_Internal_TemplateCompilerBase public $template = null; /** - * merged templates + * merged included sub template data * * @var array */ - public $merged_templates = array(); + public $mergedSubTemplatesData = array(); + + /** + * merged sub template code + * + * @var array + */ + public $mergedSubTemplatesCode = array(); + + /** + * collected template properties during compilation + * + * @var array + */ + public $templateProperties = array(); /** * sources which must be compiled @@ -178,12 +185,18 @@ abstract class Smarty_Internal_TemplateCompilerBase public $compiles_template_function = false; /** - * called subfuntions from template function + * called sub functions from template function * * @var array */ public $called_functions = array(); + /** + * compiled template function code + * + * @var string + */ + public $templateFunctionCode = ''; /** * flags for used modifier plugins * @@ -198,6 +211,13 @@ abstract class Smarty_Internal_TemplateCompilerBase */ public $known_modifier_type = array(); + /** + * parent compiler object for merged subtemplates and template functions + * + * @var Smarty_Internal_TemplateCompilerBase + */ + public $parent_compiler = null; + /** * method to compile a Smarty template * @@ -212,7 +232,7 @@ abstract class Smarty_Internal_TemplateCompilerBase */ public function __construct() { - $this->nocache_hash = str_replace(array('.', ','), '-', uniqid(rand(), true)); + $this->nocache_hash = str_replace(array('.', ','), '_', uniqid(rand(), true)); } /** @@ -223,13 +243,16 @@ abstract class Smarty_Internal_TemplateCompilerBase * * @return bool true if compiling succeeded, false if it failed */ - public function compileTemplate(Smarty_Internal_Template $template, $nocache = false) + public function compileTemplate(Smarty_Internal_Template $template, $nocache = null, $parent_compiler = null) { + $this->parent_compiler = $parent_compiler ? $parent_compiler : $this; + $nocache = isset($nocache) ? $nocache : false; if (empty($template->properties['nocache_hash'])) { $template->properties['nocache_hash'] = $this->nocache_hash; } else { $this->nocache_hash = $template->properties['nocache_hash']; } + $template->properties['type'] = $template->caching ? 'cache' : 'compiled'; // flag for nochache sections $this->nocache = $nocache; $this->tag_nocache = false; @@ -280,7 +303,7 @@ abstract class Smarty_Internal_TemplateCompilerBase $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template); } // call compiler - $_compiled_code = $this->doCompile($_content); + $_compiled_code = $this->doCompile($_content, true); } } while ($this->abort_and_recompile); if ($this->smarty->debugging) { @@ -292,12 +315,12 @@ abstract class Smarty_Internal_TemplateCompilerBase unset($save_source); $this->smarty->_current_file = $this->template->source->filepath; // free memory - unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex, $this->template); + unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex); self::$_tag_objects = array(); // return compiled code to template object $merged_code = ''; - if (!$this->suppressMergedTemplates && !empty($this->merged_templates)) { - foreach ($this->merged_templates as $code) { + if (!empty($this->mergedSubTemplatesCode)) { + foreach ($this->mergedSubTemplatesCode as $code) { $merged_code .= $code; } } @@ -305,15 +328,27 @@ abstract class Smarty_Internal_TemplateCompilerBase if ((isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) && !$this->suppressFilter && $_compiled_code != '') { $_compiled_code = Smarty_Internal_Filter_Handler::runFilter('post', $_compiled_code, $template); } + if (!empty($this->templateProperties)) { + $this->template->properties['tpl_function'] = $this->templateProperties['tpl_function']; + } if ($this->suppressTemplatePropertyHeader) { - $code = $_compiled_code . $merged_code; + $_compiled_code .= $merged_code; } else { - $code = $template_header . $template->createTemplateCodeFrame($_compiled_code) . $merged_code; + $_compiled_code = $template_header . $template->createTemplateCodeFrame($_compiled_code) . $merged_code; + } + if (!empty($this->templateFunctionCode)) { + // run postfilter if required on compiled template code + if ((isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) && !$this->suppressFilter) { + $_compiled_code .= Smarty_Internal_Filter_Handler::runFilter('post', $this->templateFunctionCode, $template); + } else { + $_compiled_code .= $this->templateFunctionCode; + } } // unset content because template inheritance could have replace source with parent code unset ($template->source->content); - - return $code; + $this->parent_compiler = null; + $this->template = null; + return $_compiled_code; } /** @@ -347,7 +382,7 @@ abstract class Smarty_Internal_TemplateCompilerBase } // compile the smarty tag (required compile classes to compile the tag are autoloaded) if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) { - if (isset($this->smarty->template_functions[$tag])) { + if (isset($this->parent_compiler->templateProperties['tpl_function']['param'][$tag])) { // template defined by {template} tag $args['_attr']['name'] = "'" . $tag . "'"; $_output = $this->callTagCompiler('call', $args, $parameter); @@ -735,10 +770,10 @@ abstract class Smarty_Internal_TemplateCompilerBase /** * push current file and line offset on stack for tracing {block} source lines * - * @param string $file new filename - * @param string $uid uid of file - * @param int $line line offset to source - * @param bool $debug false debug end_compile shall not be called + * @param string $file new filename + * @param string $uid uid of file + * @param int $line line offset to source + * @param bool $debug false debug end_compile shall not be called */ public function pushTrace($file, $uid, $line, $debug = true) { diff --git a/libs/sysplugins/smarty_resource.php b/libs/sysplugins/smarty_resource.php index f478a533..b8b78ca6 100644 --- a/libs/sysplugins/smarty_resource.php +++ b/libs/sysplugins/smarty_resource.php @@ -762,7 +762,11 @@ class Smarty_Template_Source public function getCompiled($_template) { // check runtime cache - $_cache_key = $this->unique_resource . '#' . $_template->compile_id; + $_cache_key = $this->unique_resource . '#'; + if ($_template->caching) { + $_cache_key .= 'caching#'; + } + $_cache_key .= $_template->compile_id; if (isset(Smarty_Resource::$compileds[$_cache_key])) { return Smarty_Resource::$compileds[$_cache_key]; }