diff --git a/change_log.txt b/change_log.txt index a7c0f358..34c81406 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,4 +1,7 @@  ===== 3.1.30-dev ===== (xx.xx.xx) + 11.03.2014 + - optimization of capture and security handling + 10.03.2014 - optimization of resource processing diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 795c11c4..ccf06ac7 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '3.1.30-dev/55'; + const SMARTY_VERSION = '3.1.30-dev/56'; /** * define variable scopes diff --git a/libs/sysplugins/smarty_internal_compile_capture.php b/libs/sysplugins/smarty_internal_compile_capture.php index 3791ab36..e0bac311 100644 --- a/libs/sysplugins/smarty_internal_compile_capture.php +++ b/libs/sysplugins/smarty_internal_compile_capture.php @@ -32,51 +32,53 @@ class Smarty_Internal_Compile_Capture extends Smarty_Internal_CompileBase */ public $optional_attributes = array('name', 'assign', 'append'); + /** + * Compiles code for the {$smarty.capture.xxx} + * + * @param array $args array with attributes from parser + * @param \Smarty_Internal_TemplateCompilerBase$compiler compiler object + * @param array $parameter array with compilation parameter + * + * @return string compiled code + * @throws \SmartyCompilerException + */ + public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null) + { + // make all lower case + $parameter = array_map('strtolower', $parameter); + $tag = trim($parameter[ 0 ], '"\''); + $name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false; + if (!$name) { + $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true); + } + return "\$_smarty_tpl->ext->_capture->getBuffer(\$_smarty_tpl, '{$name}')"; + } + /** * Compiles code for the {capture} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param null $parameter * * @return string compiled code */ - public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter = null) { // check and get attributes - $_attr = $this->getAttributes($compiler, $args); + $_attr = $this->getAttributes($compiler, $args, $parameter, 'capture'); $buffer = isset($_attr[ 'name' ]) ? $_attr[ 'name' ] : "'default'"; $assign = isset($_attr[ 'assign' ]) ? $_attr[ 'assign' ] : 'null'; $append = isset($_attr[ 'append' ]) ? $_attr[ 'append' ] : 'null'; - $this->openTag($compiler, 'capture', array($buffer, $assign, $append, $compiler->nocache)); + $compiler->_cache[ 'capture_stack' ][] = array($compiler->nocache); // maybe nocache because of nocache variables $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; - $_output = - "smarty->_cache['capture_stack'][] = array($buffer, $assign, $append); ob_start(); ?>"; + $_output = "ext->_capture->open(\$_smarty_tpl, $buffer, $assign, $append);\n?>\n"; return $_output; } - - /** - * Compiles code for the {$smarty.capture.xxx} - * - * @param array $args array with attributes from parser - * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter - * - * @return string compiled code - * @throws \SmartyCompilerException - */ - public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) - { - $tag = strtolower(trim($parameter[ 0 ], '"\'')); - $name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false; - if (!$name) { - $compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true); - } - return "(isset(\$_smarty_tpl->smarty->_cache['__smarty_capture']['{$name}']) ? \$_smarty_tpl->smarty->_cache['__smarty_capture']['{$name}'] : null)"; - } } /** @@ -90,29 +92,23 @@ class Smarty_Internal_Compile_CaptureClose extends Smarty_Internal_CompileBase /** * Compiles code for the {/capture} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object + * @param null $parameter * * @return string compiled code */ - public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { // check and get attributes - $_attr = $this->getAttributes($compiler, $args); + $_attr = $this->getAttributes($compiler, $args, $parameter, '/capture'); // must endblock be nocache? if ($compiler->nocache) { $compiler->tag_nocache = true; } - list($buffer, $assign, $append, $compiler->nocache) = $this->closeTag($compiler, array('capture')); - $_output = - "smarty->_cache['capture_stack']);\n"; - $_output .= "if (!empty(\$_capture_buffer)) {\n"; - $_output .= " if (isset(\$_capture_assign)) \$_smarty_tpl->assign(\$_capture_assign, ob_get_contents());\n"; - $_output .= " if (isset( \$_capture_append)) \$_smarty_tpl->append( \$_capture_append, ob_get_contents());\n"; - $_output .= "\$_smarty_tpl->smarty->_cache['__smarty_capture'][\$_capture_buffer]=ob_get_clean();\n"; - $_output .= "} else \$_smarty_tpl->capture_error();?>"; + list($compiler->nocache) = array_pop($compiler->_cache[ 'capture_stack' ]); - return $_output; + return "ext->_capture->close(\$_smarty_tpl);\n?>\n"; } } diff --git a/libs/sysplugins/smarty_internal_runtime_capture.php b/libs/sysplugins/smarty_internal_runtime_capture.php new file mode 100644 index 00000000..e1ccfffe --- /dev/null +++ b/libs/sysplugins/smarty_internal_runtime_capture.php @@ -0,0 +1,155 @@ +isRegistered) { + $this->register($_template); + } + $this->captureStack[] = array($buffer, $assign, $append); + $this->captureCount ++; + ob_start(); + } + + /** + * Register callbacks in template class + * + * @param \Smarty_Internal_Template $_template + */ + private function register(Smarty_Internal_Template $_template) + { + $_template->startRenderCallbacks[] = array($this, 'startRender'); + $_template->endRenderCallbacks[] = array($this, 'endRender'); + $this->startRender($_template); + $this->isRegistered = true; + } + + /** + * Start render callback + * + * @param \Smarty_Internal_Template $_template + */ + public function startRender(Smarty_Internal_Template $_template) + { + $this->countStack[] = $this->captureCount; + $this->captureCount = 0; + $_template->_cache[ 'capture' ] = array(); + } + + /** + * Close capture section + * + * @param \Smarty_Internal_Template $_template + * + * @throws \SmartyException + */ + public function close(Smarty_Internal_Template $_template) + { + if ($this->captureCount) { + list($buffer, $assign, $append) = array_pop($this->captureStack); + $this->captureCount --; + if (isset($assign)) { + $_template->assign($assign, ob_get_contents()); + } + if (isset($append)) { + $_template->append($append, ob_get_contents()); + } + $_template->_cache[ 'capture' ][ $buffer ] = ob_get_clean(); + } else { + $this->error($_template); + } + } + + /** + * Error exception on not matching {capture}{/capture} + * + * @param \Smarty_Internal_Template $_template + * + * @throws \SmartyException + */ + public function error(Smarty_Internal_Template $_template) + { + throw new SmartyException("Not matching {capture}{/capture} in \"{$_template->template_resource}\""); + } + + /** + * Return content of named capture buffer + * + * @param \Smarty_Internal_Template $_template + * @param $name + * + * @return null + */ + public function getBuffer(Smarty_Internal_Template $_template, $name) + { + return isset($_template->_cache[ 'capture' ][ $name ]) ? $_template->_cache[ 'capture' ][ $name ] : null; + } + + /** + * End render callback + * + * @param \Smarty_Internal_Template $_template + * + * @throws \SmartyException + */ + public function endRender(Smarty_Internal_Template $_template) + { + if ($this->captureCount) { + $this->error($_template); + } else { + $this->captureCount = array_pop($this->countStack); + } + } + +} \ No newline at end of file diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index 866d2347..885de7ec 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -87,6 +87,21 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public $isRenderingCache = false; + /** + * Callbacks called before rendering template + * + * @var callback[] + */ + public $startRenderCallbacks = array(); + + /** + * Callbacks called after rendering template + * + * @var callback[] + */ + public $endRenderCallbacks = array(); + + /** * Create template data object * Some of the global Smarty settings copied to template scope @@ -120,6 +135,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $this->template_resource = $template_resource; $this->source = Smarty_Template_Source::load($this); parent::__construct(); + if ($smarty->security_policy && method_exists($smarty->security_policy, 'registerCallBacks')) { + $smarty->security_policy->registerCallBacks($this); + } } /** diff --git a/libs/sysplugins/smarty_internal_testinstall.php b/libs/sysplugins/smarty_internal_testinstall.php index adbe6559..926847b5 100644 --- a/libs/sysplugins/smarty_internal_testinstall.php +++ b/libs/sysplugins/smarty_internal_testinstall.php @@ -387,15 +387,21 @@ class Smarty_Internal_TestInstall 'smarty_internal_compile_make_nocache.php' => true, 'smarty_internal_compile_nocache.php' => true, 'smarty_internal_compile_private_block_plugin.php' => true, + 'smarty_internal_compile_private_compiler_plugin.php' => true, 'smarty_internal_compile_private_foreachsection.php' => true, 'smarty_internal_compile_private_function_plugin.php' => true, 'smarty_internal_compile_private_modifier.php' => true, + 'smarty_internal_compile_private_modifiercompiler_plugin.php' => true, + 'smarty_internal_compile_private_modifier_plugin.php' => true, + 'smarty_internal_compile_private_object.php' => true, 'smarty_internal_compile_private_object_block_function.php' => true, 'smarty_internal_compile_private_object_function.php' => true, 'smarty_internal_compile_private_php.php' => true, 'smarty_internal_compile_private_print_expression.php' => true, 'smarty_internal_compile_private_registered_block.php' => true, + 'smarty_internal_compile_private_registered_compiler.php' => true, 'smarty_internal_compile_private_registered_function.php' => true, + 'smarty_internal_compile_private_registered_modifier.php' => true, 'smarty_internal_compile_private_special_variable.php' => true, 'smarty_internal_compile_rdelim.php' => true, 'smarty_internal_compile_section.php' => true, @@ -469,7 +475,9 @@ class Smarty_Internal_TestInstall 'smarty_internal_resource_registered.php' => true, 'smarty_internal_resource_stream.php' => true, 'smarty_internal_resource_string.php' => true, + 'smarty_internal_runtime_assignindexed.php' => true, 'smarty_internal_runtime_cachemodify.php' => true, + 'smarty_internal_runtime_capture.php' => true, 'smarty_internal_runtime_codeframe.php' => true, 'smarty_internal_runtime_filterhandler.php' => true, 'smarty_internal_runtime_foreach.php' => true, diff --git a/libs/sysplugins/smarty_security.php b/libs/sysplugins/smarty_security.php index c51df4a1..e9fa163d 100644 --- a/libs/sysplugins/smarty_security.php +++ b/libs/sysplugins/smarty_security.php @@ -625,33 +625,7 @@ class Smarty_Security $this->_checkDir($this->smarty->_realpath($filepath, true), $this->_php_resource_dir); return true; } - - /** - * Start template processing - * - * @param $template - * - * @throws SmartyException - */ - public function startTemplate($template) - { - if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) { - throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'"); - } - } - - /** - * Exit template processing - * - * @internal param $template - */ - public function exitTemplate() - { - if ($this->max_template_nesting > 0) { - $this->_current_template_nesting --; - } - } - + /** * Check if file is inside a valid directory * @@ -716,4 +690,39 @@ class Smarty_Security } return; } + /** + * Start template processing + * + * @param $template + * + * @throws SmartyException + */ + public function startTemplate($template) + { + if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) { + throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'"); + } + } + + /** + * Exit template processing + * + */ + public function endTemplate() + { + if ($this->max_template_nesting > 0) { + $this->_current_template_nesting --; + } + } + + /** + * Register callback functions call at start/end of template rendering + * + * @param \Smarty_Internal_Template $template + */ + public function registerCallBacks(Smarty_Internal_Template $template) + { + $template->startRenderCallbacks[] = array($this, 'startTemplate'); + $template->endRenderCallbacks[] = array($this, 'endTemplate'); + } } diff --git a/libs/sysplugins/smarty_template_resource_base.php b/libs/sysplugins/smarty_template_resource_base.php index b9b7dee7..6b8aaaaf 100644 --- a/libs/sysplugins/smarty_template_resource_base.php +++ b/libs/sysplugins/smarty_template_resource_base.php @@ -121,23 +121,14 @@ abstract class Smarty_Template_Resource_Base if (empty($unifunc) || !function_exists($unifunc)) { throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'"); } - if (isset($smarty->security_policy)) { - $smarty->security_policy->startTemplate($_template); + if ($_template->startRenderCallbacks) { + foreach ($_template->startRenderCallbacks as $callback) { + call_user_func($callback, $_template); + } } - // - // render compiled or saved template code - // - if (!isset($_template->_cache[ 'capture_stack' ])) { - $_template->_cache[ 'capture_stack' ] = array(); - } - $_saved_capture_level = count($_template->_cache[ 'capture_stack' ]); $unifunc($_template); - // any unclosed {capture} tags ? - if ($_saved_capture_level != count($_template->_cache[ 'capture_stack' ])) { - $_template->capture_error(); - } - if (isset($smarty->security_policy)) { - $smarty->security_policy->exitTemplate(); + foreach ($_template->endRenderCallbacks as $callback) { + call_user_func($callback, $_template); } $_template->isRenderingCache = false; return null; @@ -148,7 +139,7 @@ abstract class Smarty_Template_Resource_Base ob_end_clean(); } if (isset($smarty->security_policy)) { - $smarty->security_policy->exitTemplate(); + $smarty->security_policy->endTemplate(); } throw $e; }