diff --git a/change_log.txt b/change_log.txt index d4a2a90a..930f0801 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,5 +1,8 @@ - ===== 3.1.22-dev ===== (xx.xx.2014) - 31.12.22014 + ===== 3.1.22-dev ===== (xx.xx.2015) + + - optimization restructure template processing by moving code into classes it better belongs to + + 31.12.2014 - bugfix use function_exists('mb_get_info') for setting Smarty::$_MBSTRING. Function mb_split could be overloaded depending on php.ini mbstring.func_overload diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 3c7db90a..b1069532 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -71,22 +71,28 @@ if (!defined('SMARTY_RESOURCE_DATE_FORMAT')) { /** * Try loading the Smmarty_Internal_Data class - * + * * If we fail we must load Smarty's autoloader. * Otherwise we may have a global autoloader like Composer */ -if (!class_exists('Smarty_Internal_Data', true)) { - require 'Autoloader.php'; - Smarty_Autoloader::registerBC(); - require SMARTY_SYSPLUGINS_DIR . 'smarty_internal_data.php'; +if (!class_exists('Smarty_Autoloader', false)) { + if (!class_exists('Smarty_Internal_Data', true)) { + require 'Autoloader.php'; + Smarty_Autoloader::registerBC(); + } } /** * Load always needed external class files */ + +if (!class_exists('Smarty_Internal_Data', false)) { + require SMARTY_SYSPLUGINS_DIR . 'smarty_internal_data.php'; +} require SMARTY_SYSPLUGINS_DIR . 'smarty_internal_templatebase.php'; require SMARTY_SYSPLUGINS_DIR . 'smarty_internal_template.php'; require SMARTY_SYSPLUGINS_DIR . 'smarty_resource.php'; +require SMARTY_SYSPLUGINS_DIR . 'smarty_template_source.php'; require SMARTY_SYSPLUGINS_DIR . 'smarty_internal_resource_file.php'; /** @@ -632,8 +638,6 @@ class Smarty extends Smarty_Internal_TemplateBase */ public $_parserdebug = false; - /**#@-*/ - /** * Cache of is_file results of loadPlugin() * @@ -677,70 +681,49 @@ class Smarty extends Smarty_Internal_TemplateBase } /** - * Class destructor - */ - public function __destruct() - { - // intentionally left blank - } - - /** - * <> set selfpointer on cloned object - */ - public function __clone() - { - $this->smarty = $this; - } - - /** - * <> Generic getter. - * Calls the appropriate getter function. - * Issues an E_USER_NOTICE if no valid getter is found. + * fetches a rendered Smarty template * - * @param string $name property name + * @param string $template the resource handle of the template file or template object + * @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 + * @param bool $merge_tpl_vars not used - left for BC + * @param bool $no_output_filter not used - left for BC * - * @return mixed + * @throws Exception + * @throws SmartyException + * @return string rendered template output */ - public function __get($name) + public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false, $merge_tpl_vars = true, $no_output_filter = false) { - $allowed = array( - 'template_dir' => 'getTemplateDir', - 'config_dir' => 'getConfigDir', - 'plugins_dir' => 'getPluginsDir', - 'compile_dir' => 'getCompileDir', - 'cache_dir' => 'getCacheDir', - ); - - if (isset($allowed[$name])) { - return $this->{$allowed[$name]}(); - } else { - trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); + if ($cache_id !== null && is_object($cache_id)) { + $parent = $cache_id; + $cache_id = null; } + if ($parent === null) { + $parent = $this; + } + // get template object + $_template = is_object($template) ? $template : $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false); + // set caching in template object + $_template->caching = $this->caching; + // fetch template content + return $_template->render(true, false, $display); } /** - * <> Generic setter. - * Calls the appropriate setter function. - * Issues an E_USER_NOTICE if no valid setter is found. + * displays a Smarty template * - * @param string $name property name - * @param mixed $value parameter passed to setter + * @param string $template the resource handle of the template file or template object + * @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 */ - public function __set($name, $value) + public function display($template = null, $cache_id = null, $compile_id = null, $parent = null) { - $allowed = array( - 'template_dir' => 'setTemplateDir', - 'config_dir' => 'setConfigDir', - 'plugins_dir' => 'setPluginsDir', - 'compile_dir' => 'setCompileDir', - 'cache_dir' => 'setCacheDir', - ); - - if (isset($allowed[$name])) { - $this->{$allowed[$name]}($value); - } else { - trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); - } + // display template + $this->fetch($template, $cache_id, $compile_id, $parent, true); } /** @@ -880,9 +863,7 @@ class Smarty extends Smarty_Internal_TemplateBase foreach ((array) $template_dir as $k => $v) { $this->template_dir[$k] = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS; } - $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); - return $this; } @@ -922,7 +903,6 @@ class Smarty extends Smarty_Internal_TemplateBase } } $this->joined_template_dir = join(DIRECTORY_SEPARATOR, $this->template_dir); - return $this; } @@ -938,7 +918,6 @@ class Smarty extends Smarty_Internal_TemplateBase if ($index !== null) { return isset($this->template_dir[$index]) ? $this->template_dir[$index] : null; } - return (array) $this->template_dir; } @@ -955,9 +934,7 @@ class Smarty extends Smarty_Internal_TemplateBase foreach ((array) $config_dir as $k => $v) { $this->config_dir[$k] = preg_replace('#(\w+)(/|\\\\){1,}#', '$1$2', rtrim($v, '/\\')) . DS; } - $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); - return $this; } @@ -997,7 +974,6 @@ class Smarty extends Smarty_Internal_TemplateBase } $this->joined_config_dir = join(DIRECTORY_SEPARATOR, $this->config_dir); - return $this; } @@ -1013,7 +989,6 @@ class Smarty extends Smarty_Internal_TemplateBase if ($index !== null) { return isset($this->config_dir[$index]) ? $this->config_dir[$index] : null; } - return (array) $this->config_dir; } @@ -1089,7 +1064,6 @@ class Smarty extends Smarty_Internal_TemplateBase if (!isset(Smarty::$_muted_directories[$this->compile_dir])) { Smarty::$_muted_directories[$this->compile_dir] = null; } - return $this; } @@ -1601,6 +1575,73 @@ class Smarty extends Smarty_Internal_TemplateBase $this->compile_locking = $compile_locking; } + /** + * Class destructor + */ + public function __destruct() + { + // intentionally left blank + } + + /** + * <> set selfpointer on cloned object + */ + public function __clone() + { + $this->smarty = $this; + } + + /** + * <> Generic getter. + * Calls the appropriate getter function. + * Issues an E_USER_NOTICE if no valid getter is found. + * + * @param string $name property name + * + * @return mixed + */ + public function __get($name) + { + $allowed = array( + 'template_dir' => 'getTemplateDir', + 'config_dir' => 'getConfigDir', + 'plugins_dir' => 'getPluginsDir', + 'compile_dir' => 'getCompileDir', + 'cache_dir' => 'getCacheDir', + ); + + if (isset($allowed[$name])) { + return $this->{$allowed[$name]}(); + } else { + trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); + } + } + + /** + * <> Generic setter. + * Calls the appropriate setter function. + * Issues an E_USER_NOTICE if no valid setter is found. + * + * @param string $name property name + * @param mixed $value parameter passed to setter + */ + public function __set($name, $value) + { + $allowed = array( + 'template_dir' => 'setTemplateDir', + 'config_dir' => 'setConfigDir', + 'plugins_dir' => 'setPluginsDir', + 'compile_dir' => 'setCompileDir', + 'cache_dir' => 'setCacheDir', + ); + + if (isset($allowed[$name])) { + $this->{$allowed[$name]}($value); + } else { + trigger_error('Undefined property: ' . get_class($this) . '::$' . $name, E_USER_NOTICE); + } + } + /** * Error Handler to mute expected messages * diff --git a/libs/sysplugins/smarty_internal_template.php b/libs/sysplugins/smarty_internal_template.php index d7969fb3..66771703 100644 --- a/libs/sysplugins/smarty_internal_template.php +++ b/libs/sysplugins/smarty_internal_template.php @@ -122,6 +122,231 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } } + /** + * fetches rendered template + * + * @throws Exception + * @throws SmartyException + * @return string rendered template output + */ + public function fetch() + { + return $this->render(true, false); + } + + /** + * displays a Smarty template + + */ + public function display() + { + $this->render(true, false, true); + } + + /** + * render template + * + * @param bool $merge_tpl_vars if true parent template variables merged in to local scope + * @param bool $no_output_filter if true do not run output filter + * @param bool $display true: display, false: fetch + * + * @throws Exception + * @throws SmartyException + * @return string rendered template output + */ + public function render($merge_tpl_vars = false, $no_output_filter = true, $display = false) + { + if ($this->smarty->debugging) { + Smarty_Internal_Debug::start_template($this); + } + // merge all variable scopes into template + if ($merge_tpl_vars) { + // save local variables + $save_tpl_vars = $this->tpl_vars; + $save_config_vars = $this->config_vars; + $ptr_array = array($this); + $ptr = $this; + while (isset($ptr->parent)) { + $ptr_array[] = $ptr = $ptr->parent; + } + $ptr_array = array_reverse($ptr_array); + $parent_ptr = reset($ptr_array); + $tpl_vars = $parent_ptr->tpl_vars; + $config_vars = $parent_ptr->config_vars; + while ($parent_ptr = next($ptr_array)) { + if (!empty($parent_ptr->tpl_vars)) { + $tpl_vars = array_merge($tpl_vars, $parent_ptr->tpl_vars); + } + if (!empty($parent_ptr->config_vars)) { + $config_vars = array_merge($config_vars, $parent_ptr->config_vars); + } + } + if (!empty(Smarty::$global_tpl_vars)) { + $tpl_vars = array_merge(Smarty::$global_tpl_vars, $tpl_vars); + } + $this->tpl_vars = $tpl_vars; + $this->config_vars = $config_vars; + } + // dummy local smarty variable + if (!isset($this->tpl_vars['smarty'])) { + $this->tpl_vars['smarty'] = new Smarty_Variable; + } + if (isset($this->smarty->error_reporting)) { + $_smarty_old_error_level = error_reporting($this->smarty->error_reporting); + } + // check URL debugging control + if (!$this->smarty->debugging && $this->smarty->debugging_ctrl == 'URL') { + Smarty_Internal_Debug::debugUrl($this); + } + // checks if template exists + if (!$this->source->exists) { + if ($this->parent instanceof Smarty_Internal_Template) { + $parent_resource = " in '{$this->parent->template_resource}'"; + } else { + $parent_resource = ''; + } + throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}"); + } + // disable caching for evaluated code + if ($this->source->recompiled) { + $this->caching = false; + } + // read from cache or render + if (!($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED) || !$this->cached->valid) { + // render template (not loaded and not in cache) + if ($this->smarty->debugging) { + Smarty_Internal_Debug::start_render($this); + } + if (!$this->source->uncompiled) { + // render compiled code + $content = $this->compiled->render($this); + } else { + $content = $this->source->renderUncompiled($this); + } + if (!$this->source->recompiled && empty($this->properties['file_dependency'][$this->source->uid])) { + $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type); + } + if ($this->parent instanceof Smarty_Internal_Template) { + $this->parent->properties['file_dependency'] = array_merge($this->parent->properties['file_dependency'], $this->properties['file_dependency']); + $this->parent->properties['tpl_function'] = array_merge($this->parent->properties['tpl_function'], $this->properties['tpl_function']); + foreach ($this->required_plugins as $code => $tmp1) { + foreach ($tmp1 as $name => $tmp) { + foreach ($tmp as $type => $data) { + $this->parent->required_plugins[$code][$name][$type] = $data; + } + } + } + } + if ($this->smarty->debugging) { + Smarty_Internal_Debug::end_render($this); + } + // write to cache when necessary + if (!$this->source->recompiled && ($this->caching == Smarty::CACHING_LIFETIME_SAVED || $this->caching == Smarty::CACHING_LIFETIME_CURRENT)) { + if ($this->smarty->debugging) { + Smarty_Internal_Debug::start_cache($this); + } + $this->cached->updateCache($this, $content, $no_output_filter); + $compile_check = $this->smarty->compile_check; + $this->smarty->compile_check = false; + $content = $this->cached->render($this); + $this->smarty->compile_check = $compile_check; + if ($this->smarty->debugging) { + Smarty_Internal_Debug::end_cache($this); + } + } else { + if (!empty($this->properties['nocache_hash']) && !empty($this->parent->properties['nocache_hash'])) { + // replace nocache_hash + $content = str_replace("{$this->properties['nocache_hash']}", $this->parent->properties['nocache_hash'], $content); + $this->parent->has_nocache_code = $this->parent->has_nocache_code || $this->has_nocache_code; + } + } + } else { + if ($this->smarty->debugging) { + Smarty_Internal_Debug::start_cache($this); + } + $content = $this->cached->render($this); + if ($this->smarty->debugging) { + Smarty_Internal_Debug::end_cache($this); + } + } + if ((!$this->caching || $this->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($this->error_reporting)) { + error_reporting($_smarty_old_error_level); + } + // display or fetch + if ($display) { + if ($this->caching && $this->smarty->cache_modified_check) { + $this->cached->cacheModifiedCheck($this, $content); + } else { + echo $content; + } + if ($this->smarty->debugging) { + Smarty_Internal_Debug::end_template($this); + } + // debug output + if ($this->smarty->debugging) { + Smarty_Internal_Debug::display_debug($this, true); + } + if ($merge_tpl_vars) { + // restore local variables + $this->tpl_vars = $save_tpl_vars; + $this->config_vars = $save_config_vars; + } + + return ''; + } else { + if ($merge_tpl_vars) { + // restore local variables + $this->tpl_vars = $save_tpl_vars; + $this->config_vars = $save_config_vars; + } + if ($this->smarty->debugging) { + Smarty_Internal_Debug::end_template($this); + } + // return fetched content + return $content; + } + } + + /** + * get rendered template content by calling compiled or cached template code + * + * @return string + * @throws Exception + */ + public function getRenderedTemplateCode() + { + try { + ob_start(); + if (empty($this->properties['unifunc']) || !is_callable($this->properties['unifunc'])) { + throw new SmartyException("Invalid compiled template for '{$this->template_resource}'"); + } + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->startTemplate($this); + } + array_unshift($this->_capture_stack, array()); + // + // render compiled or saved template code + // + $this->properties['unifunc']($this); + // any unclosed {capture} tags ? + if (isset($this->_capture_stack[0][0])) { + $this->capture_error(); + } + array_shift($this->_capture_stack); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->exitTemplate($this); + } + return ob_get_clean(); + } + catch (Exception $e) { + ob_get_clean(); + throw $e; + } + } + /** * Returns if the current template must be compiled by the Smarty compiler * It does compare the timestamps of template source and the compiled templates and checks the force compile configuration @@ -153,43 +378,11 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public function compileTemplateSource() { - if (!$this->source->recompiled) { - $this->properties['file_dependency'] = array(); - } - // compile locking - if ($this->smarty->compile_locking && !$this->source->recompiled) { - if ($saved_timestamp = $this->compiled->timestamp) { - touch($this->compiled->filepath); - } - } - // call compiler - try { - $code = $this->compiler->compileTemplate($this); - } - catch (Exception $e) { - // restore old timestamp in case of error - if ($this->smarty->compile_locking && !$this->source->recompiled && $saved_timestamp) { - touch($this->compiled->filepath, $saved_timestamp); - } - throw $e; - } - // compiling succeded - if (!$this->source->recompiled && $this->compiler->write_compiled_code) { - // write compiled template - $_filepath = $this->compiled->filepath; - if ($_filepath === false) { - throw new SmartyException('getCompiledFilepath() did not return a destination to save the compiled template to'); - } - Smarty_Internal_Write_File::writeFile($_filepath, $code, $this->smarty); - $this->compiled->exists = true; - $this->compiled->isCompiled = true; - } - // release compiler object to free memory - unset($this->compiler); + return $this->compiled->compileTemplateSource($this); } /** - * Writes the cached template output + * Writes the content to cache resource * * @param string $content * @@ -197,15 +390,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public function writeCachedContent($content) { - if ($this->source->recompiled || !($this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED)) { - // don't write cache file - return false; - } - $this->cached->timestamp = time(); - $this->properties['cache_lifetime'] = $this->cache_lifetime; - $this->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); - $content = $this->createTemplateCodeFrame($content, true); - return $this->cached->write($this, $content); + return $this->cached->writeCachedContent($this, $content); } /** @@ -223,16 +408,27 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) { - // already in template cache? - if ($this->smarty->allow_ambiguous_resources) { - $_templateId = Smarty_Resource::getUniqueTemplateName($this, $template) . $cache_id . $compile_id; - } else { - $_templateId = $this->smarty->joined_template_dir . '#' . $template . $cache_id . $compile_id; - } + $tpl = $this->setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope); + return $tpl->render(); + } - if (isset($_templateId[150])) { - $_templateId = sha1($_templateId); - } + /** + * 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 array $data passed parameter template variables + * @param int $parent_scope scope in which {include} should execute + * + * @returns object template object + */ + public function setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) + { + $_templateId = $this->getTemplateId($template, $cache_id, $compile_id); + // already in template cache? if (isset($this->smarty->template_objects[$_templateId])) { // clone cached template object because of possible recursive call $tpl = clone $this->smarty->template_objects[$_templateId]; @@ -244,6 +440,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $tpl->cache_lifetime = $cache_lifetime; } else { $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); + $tpl->templateId = $_templateId; } // get variables from calling scope if ($parent_scope == Smarty::SCOPE_LOCAL) { @@ -265,49 +462,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase $tpl->tpl_vars[$_key] = new Smarty_variable($_val); } } - return $tpl->fetch(null, null, null, null, false, false, true); - } - - /** - * 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 - * - * @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; - } elseif ($parent_scope == Smarty::SCOPE_GLOBAL) { - $tpl->tpl_vars = &Smarty::$global_tpl_vars; - } elseif (($scope_ptr = $this->getScopePointer($parent_scope)) == null) { - $tpl->tpl_vars = &$this->tpl_vars; - } else { - $tpl->tpl_vars = &$scope_ptr->tpl_vars; - } - $tpl->config_vars = $this->config_vars; - if (!empty($data)) { - // set up variable values - foreach ($data as $_key => $_val) { - $tpl->tpl_vars[$_key] = new Smarty_variable($_val); - } - } - return $tpl; } @@ -319,7 +473,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase * @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 array $data passed parameter template variables * @param int $parent_scope scope in which {include} should execute * @param string $hash nocache hash code * @param string $content_func name of content function @@ -328,17 +482,18 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase */ 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); - if (isset($this->smarty->security_policy)) { - $this->smarty->security_policy->startTemplate($tpl); + $tpl = $this->setupSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope); + $tpl->properties['nocache_hash'] = $hash; + $tpl->properties['tpl_function'] = $this->properties['tpl_function']; + if (!isset($this->smarty->template_objects[$tpl->templateId])) { + $this->smarty->template_objects[$tpl->templateId] = $tpl; } - if ($this->smarty->debugging) { Smarty_Internal_Debug::start_template($tpl); Smarty_Internal_Debug::start_render($tpl); } - ob_start(); - $content_func($tpl); + $tpl->properties['unifunc'] = $content_func; + $output = $tpl->getRenderedTemplateCode(); if ($this->smarty->debugging) { Smarty_Internal_Debug::end_template($tpl); Smarty_Internal_Debug::end_render($tpl); @@ -346,10 +501,8 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase if (!empty($tpl->properties['file_dependency'])) { $this->properties['file_dependency'] = array_merge($this->properties['file_dependency'], $tpl->properties['file_dependency']); } - if (isset($this->smarty->security_policy)) { - $this->smarty->security_policy->exitTemplate($tpl); - } - return str_replace($tpl->properties['nocache_hash'], $this->properties['nocache_hash'], ob_get_clean()); + $this->properties['tpl_function'] = $tpl->properties['tpl_function']; + return str_replace($tpl->properties['nocache_hash'], $this->properties['nocache_hash'], $output); } /** @@ -388,7 +541,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } throw new SmartyException("Unable to find template function '{$name}'"); } - + /** * This function is executed automatically when a compiled or cached template file is included * - Decode saved properties from compiled template and cache files @@ -406,7 +559,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase 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($properties['file_dependency'])) { + } elseif ((!$cache && $this->smarty->compile_check || $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') { @@ -441,10 +594,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } else { $this->mustCompile = !$is_valid; } - // store data in reusable Smarty_Template_Compiled - if (!$cache) { - $this->compiled->_properties = $properties; - } if ($is_valid) { $this->has_nocache_code = $properties['has_nocache_code']; // $this->properties['nocache_hash'] = $properties['nocache_hash']; @@ -460,7 +609,6 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } $this->properties['version'] = $properties['version']; $this->properties['unifunc'] = $properties['unifunc']; - $this->properties['type'] = $properties['type']; } return $is_valid; } @@ -516,7 +664,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase /** * Get parent or root of template parent chain * - * @param int $scope pqrent or root scope + * @param int $scope parent or root scope * * @return mixed object */ @@ -537,7 +685,7 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase } /** - * [util function] counts an array, arrayaccess/traversable or PDOStatement object + * [util function] counts an array, arrayAccess/traversable or PDOStatement object * * @param mixed $value * @@ -627,43 +775,25 @@ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase * * @param string $property_name property name * + * @return mixed|Smarty_Template_Cached * @throws SmartyException */ public function __get($property_name) { switch ($property_name) { case 'source': - if (strlen($this->template_resource) == 0) { - throw new SmartyException('Missing template name'); + $this->source = Smarty_Template_Source::load($this); + if ($this->smarty->template_resource_caching && !$this->source->recompiled && isset($this->templateId)) { + $this->smarty->template_objects[$this->templateId] = $this; } - $this->source = Smarty_Resource::source($this); - // cache template object under a unique ID - // do not cache eval resources - if ($this->source->type != 'eval') { - if ($this->smarty->allow_ambiguous_resources) { - $_templateId = $this->source->unique_resource . $this->cache_id . $this->compile_id; - } else { - $_templateId = $this->smarty->joined_template_dir . '#' . $this->template_resource . $this->cache_id . $this->compile_id; - } - - if (isset($_templateId[150])) { - $_templateId = sha1($_templateId); - } - $this->smarty->template_objects[$_templateId] = $this; - } - return $this->source; case 'compiled': - $this->compiled = $this->source->getCompiled($this); - + $this->compiled = Smarty_Template_Compiled::load($this); return $this->compiled; case 'cached': - if (!class_exists('Smarty_Template_Cached')) { - include SMARTY_SYSPLUGINS_DIR . 'smarty_cacheresource.php'; - } - $this->cached = new Smarty_Template_Cached($this); + $this->cached = Smarty_Template_Cached::load($this); return $this->cached; diff --git a/libs/sysplugins/smarty_internal_templatebase.php b/libs/sysplugins/smarty_internal_templatebase.php index 3598faae..92a3c880 100644 --- a/libs/sysplugins/smarty_internal_templatebase.php +++ b/libs/sysplugins/smarty_internal_templatebase.php @@ -49,383 +49,6 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data */ public $cache_lifetime = 3600; - /** - * fetches a rendered Smarty template - * - * @param string $template the resource handle of the template file or template object - * @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 - * @param bool $merge_tpl_vars if true parent template variables merged in to local scope - * @param bool $no_output_filter if true do not run output filter - * - * @throws Exception - * @throws SmartyException - * @return string rendered template output - */ - public function fetch($template = null, $cache_id = null, $compile_id = null, $parent = null, $display = false, $merge_tpl_vars = true, $no_output_filter = false) - { - if ($template === null && $this instanceof $this->template_class) { - $template = $this; - } - if ($cache_id !== null && is_object($cache_id)) { - $parent = $cache_id; - $cache_id = null; - } - if ($parent === null && ($this instanceof Smarty || is_string($template))) { - $parent = $this; - } - // create template object if necessary - $_template = ($template instanceof $this->template_class) - ? $template - : $this->smarty->createTemplate($template, $cache_id, $compile_id, $parent, false); - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_template($_template); - } - if (isset($_template->smarty->security_policy)) { - $_template->smarty->security_policy->startTemplate($_template); - } - // if called by Smarty object make sure we use current caching status - if ($this instanceof Smarty) { - $_template->caching = $this->caching; - } - // merge all variable scopes into template - if ($merge_tpl_vars) { - // save local variables - $save_tpl_vars = $_template->tpl_vars; - $save_config_vars = $_template->config_vars; - $ptr_array = array($_template); - $ptr = $_template; - while (isset($ptr->parent)) { - $ptr_array[] = $ptr = $ptr->parent; - } - $ptr_array = array_reverse($ptr_array); - $parent_ptr = reset($ptr_array); - $tpl_vars = $parent_ptr->tpl_vars; - $config_vars = $parent_ptr->config_vars; - while ($parent_ptr = next($ptr_array)) { - if (!empty($parent_ptr->tpl_vars)) { - $tpl_vars = array_merge($tpl_vars, $parent_ptr->tpl_vars); - } - if (!empty($parent_ptr->config_vars)) { - $config_vars = array_merge($config_vars, $parent_ptr->config_vars); - } - } - if (!empty(Smarty::$global_tpl_vars)) { - $tpl_vars = array_merge(Smarty::$global_tpl_vars, $tpl_vars); - } - $_template->tpl_vars = $tpl_vars; - $_template->config_vars = $config_vars; - } - // dummy local smarty variable - if (!isset($_template->tpl_vars['smarty'])) { - $_template->tpl_vars['smarty'] = new Smarty_Variable; - } - if (isset($_template->smarty->error_reporting)) { - $_smarty_old_error_level = error_reporting($_template->smarty->error_reporting); - } - // check URL debugging control - if (!$_template->smarty->debugging && $_template->smarty->debugging_ctrl == 'URL') { - Smarty_Internal_Debug::debugUrl($_template); - } - // checks if template exists - if (!$_template->source->exists) { - if ($_template->parent instanceof Smarty_Internal_Template) { - $parent_resource = " in '{$_template->parent->template_resource}'"; - } else { - $parent_resource = ''; - } - throw new SmartyException("Unable to load template {$_template->source->type} '{$_template->source->name}'{$parent_resource}"); - } - // get rendered template - // disable caching for evaluated code - if ($_template->source->recompiled) { - $_template->caching = false; - } - // read from cache or render - if (!($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || $_template->caching == Smarty::CACHING_LIFETIME_SAVED) || !$_template->cached->valid) { - // render template (not loaded and not in cache) - if (!$_template->source->uncompiled) { - /** @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $_template; - if ($_template->source->recompiled) { - $code = $_template->compiler->compileTemplate($_template); - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_render($_template); - } - try { - ob_start(); - eval("?>" . $code); - unset($code); - } - catch (Exception $e) { - ob_get_clean(); - throw $e; - } - } else { - if (!$_template->compiled->exists || ($_template->smarty->force_compile && !$_template->compiled->isCompiled)) { - $_template->compileTemplateSource(); - $code = file_get_contents($_template->compiled->filepath); - eval("?>" . $code); - unset($code); - $_template->compiled->loaded = true; - $_template->compiled->isCompiled = true; - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_render($_template); - } - if (!$_template->compiled->loaded) { - include($_template->compiled->filepath); - if ($_template->mustCompile) { - // recompile and load again - $_template->compileTemplateSource(); - $code = file_get_contents($_template->compiled->filepath); - eval("?>" . $code); - unset($code); - $_template->compiled->isCompiled = true; - } - $_template->compiled->loaded = true; - } else { - $_template->decodeProperties($_template->compiled->_properties, false); - } - try { - ob_start(); - if (empty($_template->properties['unifunc']) || !is_callable($_template->properties['unifunc'])) { - throw new SmartyException("Invalid compiled template for '{$_template->template_resource}'"); - } - array_unshift($_template->_capture_stack, array()); - // - // render compiled template - // - $_template->properties['unifunc']($_template); - // any unclosed {capture} tags ? - if (isset($_template->_capture_stack[0][0])) { - $_template->capture_error(); - } - array_shift($_template->_capture_stack); - } - catch (Exception $e) { - ob_get_clean(); - throw $e; - } - } - } else { - if ($_template->source->uncompiled) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_render($_template); - } - try { - ob_start(); - $_template->source->renderUncompiled($_template); - } - catch (Exception $e) { - ob_get_clean(); - throw $e; - } - } else { - throw new SmartyException("Resource '$_template->source->type' must have 'renderUncompiled' method"); - } - } - $_output = ob_get_clean(); - if (!$_template->source->recompiled && empty($_template->properties['file_dependency'][$_template->source->uid])) { - $_template->properties['file_dependency'][$_template->source->uid] = array($_template->source->filepath, $_template->source->timestamp, $_template->source->type); - } - 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) { - $_template->parent->required_plugins[$code][$name][$type] = $data; - } - } - } - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_render($_template); - } - // write to cache when nessecary - if (!$_template->source->recompiled && ($_template->caching == Smarty::CACHING_LIFETIME_SAVED || $_template->caching == Smarty::CACHING_LIFETIME_CURRENT)) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_cache($_template); - } - $_template->properties['has_nocache_code'] = false; - // get text between non-cached items - $cache_split = preg_split("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output); - // get non-cached items - preg_match_all("!/\*%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*\/(.+?)/\*/%%SmartyNocache:{$_template->properties['nocache_hash']}%%\*/!s", $_output, $cache_parts); - $output = ''; - // 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); - 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 .= $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']))) { - $output = Smarty_Internal_Filter_Handler::runFilter('output', $output, $_template); - } - // 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; - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_cache($_template); - } - } else { - // var_dump('renderTemplate', $_template->has_nocache_code, $_template->template_resource, $_template->properties['nocache_hash'], $_template->parent->properties['nocache_hash'], $_output); - if (!empty($_template->properties['nocache_hash']) && !empty($_template->parent->properties['nocache_hash'])) { - // replace nocache_hash - $_output = str_replace("{$_template->properties['nocache_hash']}", $_template->parent->properties['nocache_hash'], $_output); - $_template->parent->has_nocache_code = $_template->parent->has_nocache_code || $_template->has_nocache_code; - } - } - } else { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_cache($_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; - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_cache($_template); - } - } - if ((!$this->caching || $_template->has_nocache_code || $_template->source->recompiled) && !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))) { - $_output = Smarty_Internal_Filter_Handler::runFilter('output', $_output, $_template); - } - if (isset($this->error_reporting)) { - error_reporting($_smarty_old_error_level); - } - if (isset($_template->smarty->security_policy)) { - $_template->smarty->security_policy->exitTemplate($_template); - } - // display or fetch - if ($display) { - if ($this->caching && $this->cache_modified_check) { - $_isCached = $_template->isCached() && !$_template->has_nocache_code; - $_last_modified_date = @substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); - if ($_isCached && $_template->cached->timestamp <= strtotime($_last_modified_date)) { - switch (PHP_SAPI) { - case 'cgi': // php-cgi < 5.3 - case 'cgi-fcgi': // php-cgi >= 5.3 - case 'fpm-fcgi': // php-fpm >= 5.3.3 - header('Status: 304 Not Modified'); - break; - - case 'cli': - if ( /* ^phpunit */ - !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ - ) { - $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = '304 Not Modified'; - } - break; - - default: - header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); - break; - } - } else { - switch (PHP_SAPI) { - case 'cli': - if ( /* ^phpunit */ - !empty($_SERVER['SMARTY_PHPUNIT_DISABLE_HEADERS']) /* phpunit$ */ - ) { - $_SERVER['SMARTY_PHPUNIT_HEADERS'][] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT'; - } - break; - - default: - header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $_template->cached->timestamp) . ' GMT'); - break; - } - echo $_output; - } - } else { - echo $_output; - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_template($_template); - } - // debug output - if ($this->smarty->debugging) { - Smarty_Internal_Debug::display_debug($_template, true); - } - if ($merge_tpl_vars) { - // restore local variables - $_template->tpl_vars = $save_tpl_vars; - $_template->config_vars = $save_config_vars; - } - - return; - } else { - if ($merge_tpl_vars) { - // restore local variables - $_template->tpl_vars = $save_tpl_vars; - $_template->config_vars = $save_config_vars; - } - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_template($_template); - } - // return fetched content - return $_output; - } - } - - /** - * displays a Smarty template - * - * @param string $template the resource handle of the template file or template object - * @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 - */ - public function display($template = null, $cache_id = null, $compile_id = null, $parent = null) - { - // display template - $this->fetch($template, $cache_id, $compile_id, $parent, true); - } - /** * test if cache is valid *