diff --git a/change_log.txt b/change_log.txt index eb619321..82da50a4 100644 --- a/change_log.txt +++ b/change_log.txt @@ -4,6 +4,7 @@ - load seldom used Smarty API methods dynamically to reduce memory footprint - cache template object of {include} if same template is included several times - convert debug console processing to object + - use output buffers for better performance and less memory usage 06.08.2015 - avoid possible circular object references caused by parser/lexer objects diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index e35acab5..66252732 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -817,7 +817,22 @@ class Smarty extends Smarty_Internal_TemplateBase // set caching in template object $_template->caching = $this->caching; // fetch template content - return $_template->render(true, false, $display); + $level = ob_get_level(); + try { + $_smarty_old_error_level = isset($this->error_reporting) ? error_reporting($this->error_reporting) : null; + ob_start(); + $result = $_template->render(true, false, $display); + if (isset($_smarty_old_error_level)) { + error_reporting($_smarty_old_error_level); + } + return $result === null ? ob_get_clean() : $result; + } + catch (Exception $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + throw $e; + } } /** diff --git a/libs/sysplugins/smarty_internal_compile_include.php b/libs/sysplugins/smarty_internal_compile_include.php index 7f45296a..8114a0ff 100644 --- a/libs/sysplugins/smarty_internal_compile_include.php +++ b/libs/sysplugins/smarty_internal_compile_include.php @@ -282,9 +282,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase //$compiler->suppressNocacheProcessing = true; } if (isset($_assign)) { - $_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_Variable(\$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}'));\n"; + $_output .= "ob_start();\n"; + $_output .= "\$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}');\n"; + $_output .= "\$_smarty_tpl->tpl_vars[$_assign] = new Smarty_Variable(ob_get_clean());\n"; } else { - $_output .= "echo \$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}');\n"; + $_output .= "\$_smarty_tpl->getInlineSubTemplate({$include_file}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_parent_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$tpl_name][$uid]['func']}');\n"; } if ($update_compile_id) { $_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"); @@ -303,9 +305,11 @@ class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase } // was there an assign attribute if (isset($_assign)) { - $_output .= "\$_smarty_tpl->tpl_vars[$_assign] = new Smarty_Variable(\$_smarty_tpl->getSubTemplate ($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, {$_cache_tpl}));\n"; + $_output .= "ob_start();\n"; + $_output .= "\$_smarty_tpl->getSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, {$_cache_tpl});\n"; + $_output .= "\$_smarty_tpl->tpl_vars[$_assign] = new Smarty_Variable(ob_get_clean());\n"; } else { - $_output .= "echo \$_smarty_tpl->getSubTemplate ($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, {$_cache_tpl});\n"; + $_output .= "\$_smarty_tpl->getSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, {$_cache_tpl});\n"; } if ($update_compile_id) { $_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"; diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index f7a2d52b..2ff631dd 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -151,14 +151,34 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase * @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 object $parent next higher level of Smarty variables + * @param bool $_display true: display, false: fetch * - * @throws Exception - * @throws SmartyException - * @return string rendered template output + * @return string + * @throws \Exception */ - public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null) + public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $_display = false) { - return isset($template) ? $this->smarty->fetch($template, $cache_id, $compile_id, $parent) : $this->render(true, false, false); + if (isset($template)) { + return $this->smarty->fetch($template, $cache_id, $compile_id, $parent, $_display); + } else { + // fetch template content + $level = ob_get_level(); + try { + $_smarty_old_error_level = isset($this->smarty->error_reporting) ? error_reporting($this->smarty->error_reporting) : null; + ob_start(); + $result = $this->render(true, false, $_display); + if (isset($_smarty_old_error_level)) { + error_reporting($_smarty_old_error_level); + } + return $result === null ? ob_get_clean() : $result; + } + catch (Exception $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + throw $e; + } + } } /** @@ -232,7 +252,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $this->tpl_vars = $tpl_vars; $this->config_vars = $config_vars; } - $_smarty_old_error_level = isset($this->smarty->error_reporting) ? error_reporting($this->smarty->error_reporting) : null; // check URL debugging control if (!$this->smarty->debugging && $this->smarty->debugging_ctrl == 'URL') { $this->smarty->_debug->debugUrl($this); @@ -260,9 +279,9 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if (!isset($this->compiled)) { $this->loadCompiled(); } - $content = $this->compiled->render($this); + $this->compiled->render($this); } else { - $content = $this->source->renderUncompiled($this); + $this->source->renderUncompiled($this); } if ($parentIsTpl && !empty($this->tpl_function)) { $this->parent->tpl_function = array_merge($this->parent->tpl_function, $this->tpl_function); @@ -275,7 +294,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if ($this->smarty->debugging) { $this->smarty->_debug->start_cache($this); } - $this->cached->updateCache($this, $content, $no_output_filter); + $this->cached->updateCache($this, $no_output_filter); $compile_check = $this->smarty->compile_check; $this->smarty->compile_check = false; if ($parentIsTpl) { @@ -285,7 +304,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $this->cached->process($this, true); } $this->smarty->compile_check = $compile_check; - $content = $this->getRenderedTemplateCode($this->cached->unifunc); + $this->getRenderedTemplateCode($this->cached->unifunc); if ($this->smarty->debugging) { $this->smarty->_debug->end_cache($this); } @@ -303,25 +322,23 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if ($this->smarty->debugging) { $this->smarty->_debug->start_cache($this); } - $content = $this->cached->render($this); + $this->cached->render($this); if ($this->smarty->debugging) { $this->smarty->_debug->end_cache($this); } } + $content = null; if ((!$this->caching || $this->cached->has_nocache_code || $this->source->recompiled) && !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) ) { - $content = Smarty_Internal_Filter_Handler::runFilter('output', $content, $this); - } - if (isset($_smarty_old_error_level)) { - error_reporting($_smarty_old_error_level); + $content = Smarty_Internal_Filter_Handler::runFilter('output', ob_get_clean(), $this); } // display or fetch if ($display) { if ($this->caching && $this->smarty->cache_modified_check) { - $this->cached->cacheModifiedCheck($this, $content); + $this->cached->cacheModifiedCheck($this, isset($content) ? $content : ob_get_clean()); } else { - echo $content; + echo isset($content) ? $content : ob_get_clean(); } if ($this->smarty->debugging) { $this->smarty->_debug->end_template($this); @@ -361,7 +378,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } } // return cache content - return $content; + return $content === null ? null: $content; } } @@ -377,7 +394,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase { $level = ob_get_level(); try { - ob_start(); if (empty($unifunc) || !is_callable($unifunc)) { throw new SmartyException("Invalid compiled template for '{$this->template_resource}'"); } @@ -397,12 +413,16 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if (isset($this->smarty->security_policy)) { $this->smarty->security_policy->exitTemplate(); } - return ob_get_clean(); + return null; } catch (Exception $e) { while (ob_get_level() > $level) { ob_end_clean(); } + array_shift($this->_capture_stack); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->exitTemplate(); + } throw $e; } } @@ -470,7 +490,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $cache_tpl_obj) { $tpl = $this->setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $cache_tpl_obj); - return $tpl->render(); + $tpl->render(); } /** @@ -563,7 +583,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $this->smarty->_debug->start_template($tpl); $this->smarty->_debug->start_render($tpl); } - $output = $tpl->getRenderedTemplateCode($content_func); + $tpl->getRenderedTemplateCode($content_func); if ($this->smarty->debugging) { $this->smarty->_debug->end_template($tpl); $this->smarty->_debug->end_render($tpl); diff --git a/libs/sysplugins/smarty_template_cached.php b/libs/sysplugins/smarty_template_cached.php index ee2ea249..b9682715 100644 --- a/libs/sysplugins/smarty_template_cached.php +++ b/libs/sysplugins/smarty_template_cached.php @@ -208,7 +208,7 @@ class Smarty_Template_Cached extends Smarty_Template_Resource_Base if (!$this->processed) { $this->process($_template); } - return $_template->getRenderedTemplateCode($this->unifunc); + $_template->getRenderedTemplateCode($this->unifunc); } /** @@ -269,31 +269,33 @@ class Smarty_Template_Cached extends Smarty_Template_Resource_Base * * @throws SmartyException */ - public function updateCache(Smarty_Internal_Template $_template, $content, $no_output_filter) + public function updateCache(Smarty_Internal_Template $_template, $no_output_filter) { + $content = ob_get_clean(); $_template->cached->has_nocache_code = false; // get text between non-cached items $cache_split = preg_split("!/\*%%SmartyNocache:{$_template->compiled->nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->compiled->nocache_hash}%%\*/!s", $content); // get non-cached items preg_match_all("!/\*%%SmartyNocache:{$_template->compiled->nocache_hash}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->compiled->nocache_hash}%%\*/!s", $content, $cache_parts); - $output = ''; + $content = ''; // loop over items, stitch back together foreach ($cache_split as $curr_idx => $curr_split) { // escape PHP tags in template content - $output .= preg_replace('/(<%|%>|<\?php|<\?|\?>|)/', "\n", $curr_split); + $content .= preg_replace('/(<%|%>|<\?php|<\?|\?>|)/', "\n", $curr_split); if (isset($cache_parts[0][$curr_idx])) { $_template->cached->has_nocache_code = true; - $output .= $cache_parts[1][$curr_idx]; + $content .= $cache_parts[1][$curr_idx]; } } if (!$no_output_filter && !$_template->compiled->has_nocache_code && (isset($_template->smarty->autoload_filters['output']) || isset($_template->smarty->registered_filters['output'])) ) { - $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $_template); + $content = Smarty_Internal_Filter_Handler::runFilter('output', $content, $_template); } // write cache file content - $this->writeCachedContent($_template, $output); + $this->writeCachedContent($_template, $content); + ob_start(); } /** diff --git a/libs/sysplugins/smarty_template_compiled.php b/libs/sysplugins/smarty_template_compiled.php index afe307d4..5aec3a99 100644 --- a/libs/sysplugins/smarty_template_compiled.php +++ b/libs/sysplugins/smarty_template_compiled.php @@ -206,7 +206,7 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base if (isset($_template->cached)) { $_template->cached->file_dependency = array_merge($_template->cached->file_dependency, $this->file_dependency); } - return $_template->getRenderedTemplateCode($this->unifunc); + $_template->getRenderedTemplateCode($this->unifunc); } /** @@ -222,6 +222,7 @@ class Smarty_Template_Compiled extends Smarty_Template_Resource_Base $_template->source->compileds = array(); $this->file_dependency = array(); $this->tpl_function = array(); + $this->includes = array(); $this->nocache_hash = null; $this->unifunc = null; // compile locking diff --git a/libs/sysplugins/smarty_template_source.php b/libs/sysplugins/smarty_template_source.php index e4ea0794..a1c88576 100644 --- a/libs/sysplugins/smarty_template_source.php +++ b/libs/sysplugins/smarty_template_source.php @@ -202,7 +202,9 @@ class Smarty_Template_Source list($name, $type) = Smarty_Resource::parseResourceName($template_resource, $smarty->default_resource_type); $resource = Smarty_Resource::load($smarty, $type); // if resource is not recompiling and resource name is not dotted we can check the source cache - if (($smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON) && !$resource->recompiled && !(isset($name[1]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/'))) { + if (($smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON) && !$resource->recompiled && + !(isset($name[1]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/')) + ) { $unique_resource = $resource->buildUniqueResourceName($smarty, $name); if (isset($smarty->source_objects[$unique_resource])) { return $smarty->source_objects[$unique_resource]; @@ -221,8 +223,11 @@ class Smarty_Template_Source // may by we have already $unique_resource $is_relative = false; if (!isset($unique_resource)) { - $is_relative = isset($name[1]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/') && ($type == 'file' || (isset($_template->parent->source) && $_template->parent->source->type == 'extends')); - $unique_resource = $resource->buildUniqueResourceName($smarty, $is_relative ? $source->filepath . $name : $name); + $is_relative = isset($name[1]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/') && + ($type == 'file' || + (isset($_template->parent->source) && $_template->parent->source->type == 'extends')); + $unique_resource = $resource->buildUniqueResourceName($smarty, $is_relative ? $source->filepath . + $name : $name); } $source->unique_resource = $unique_resource; // save in runtime cache if not relative @@ -243,18 +248,7 @@ class Smarty_Template_Source */ public function renderUncompiled(Smarty_Internal_Template $_template) { - $level = ob_get_level(); - ob_start(); - try { - $this->handler->renderUncompiled($_template->source, $_template); - return ob_get_clean(); - } - catch (Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - throw $e; - } + $this->handler->renderUncompiled($_template->source, $_template); } /**