Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_getconfigvars.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_getconfigvars.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_getconfigvars.php (revision Shelved version) @@ -0,0 +1,58 @@ +config_vars[$varname])) { + return $_ptr->config_vars[$varname]; + } + } else { + $var_array = array_merge($_ptr->config_vars, $var_array); + } + // not found, try at parent + if ($search_parents) { + $_ptr = $_ptr->parent; + } else { + $_ptr = null; + } + } + if (isset($varname)) { + return ''; + } else { + return $var_array; + } + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_createdata.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_createdata.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_createdata.php (revision Shelved version) @@ -0,0 +1,44 @@ +smarty) ? $this->smarty : $obj; + $dataObj = new Smarty_Data($parent, $smarty, $name); + if ($smarty->debugging) { + Smarty_Internal_Debug::register_data($dataObj); + } + return $dataObj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/plugins/outputfilter.trimwhitespace.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/outputfilter.trimwhitespace.php (revision Local version) +++ src/includes/classes/Smarty/plugins/outputfilter.trimwhitespace.php (revision Shelved version) @@ -45,7 +45,7 @@ // capture html elements not to be messed with $_offset = 0; - if (preg_match_all('#<(script|pre|textarea)[^>]*>.*?#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { + if (preg_match_all('#(]*>.*?]*>)|(]*>.*?]*>)|(]*>.*?]*>)#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { foreach ($matches as $match) { $store[] = $match[0][0]; $_length = strlen($match[0][0]); @@ -62,7 +62,7 @@ // can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2', // remove spaces between attributes (but not in attribute values!) - '#(([a-z0-9]\s*=\s*(["\'])[^\3]*?\3)|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \4', + '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5', // note: for some very weird reason trim() seems to remove spaces inside attributes. // maybe a \0 byte or something is interfering? '#^\s+<#Ss' => '<', Index: src/includes/classes/Smarty/sysplugins/smarty_resource_uncompiled.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_resource_uncompiled.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_resource_uncompiled.php (revision Shelved version) @@ -17,6 +17,20 @@ abstract class Smarty_Resource_Uncompiled extends Smarty_Resource { /** + * Flag that it's an uncompiled resource + * + * @var bool + */ + public $uncompiled = true; + + /** + * Resource does implement populateCompiledFilepath() method + * + * @var bool + */ + public $hasCompiledHandler = true; + + /** * Render and output the template (without using the compiler) * * @param Smarty_Template_Source $source source object @@ -37,5 +51,29 @@ $compiled->filepath = false; $compiled->timestamp = false; $compiled->exists = false; + } + + /** + * render compiled template code + * + * @param Smarty_Internal_Template $_template + * + * @return string + * @throws Exception + */ + public function render($_template) + { + $level = ob_get_level(); + ob_start(); + try { + $this->renderUncompiled($_template->source, $_template); + return ob_get_clean(); + } + catch (Exception $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + throw $e; + } } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearassign.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearassign.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearassign.php (revision Shelved version) @@ -0,0 +1,44 @@ +tpl_vars[$curr_var]); + } + } else { + unset($data->tpl_vars[$tpl_var]); + } + + return $data; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_getdefaultmodifiers.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_getdefaultmodifiers.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_getdefaultmodifiers.php (revision Shelved version) @@ -0,0 +1,35 @@ +smarty) ? $obj->smarty : $obj; + return $smarty->default_modifiers; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_security.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_security.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_security.php (revision Shelved version) @@ -34,6 +34,7 @@ * @var integer */ public $php_handling = Smarty::PHP_PASSTHRU; + /** * This is the list of template directories that are considered secure. * $template_dir is in this list implicitly. @@ -41,6 +42,7 @@ * @var array */ public $secure_dir = array(); + /** * This is an array of directories where trusted php scripts reside. * {@link $security} is disabled during their inclusion/execution. @@ -48,13 +50,29 @@ * @var array */ public $trusted_dir = array(); + /** * List of regular expressions (PCRE) that include trusted URIs * * @var array */ public $trusted_uri = array(); + /** + * List of trusted constants names + * + * @var array + */ + public $trusted_constants = array(); + + /** + * List of trusted constants names + * + * @var array + */ + public $trusted_constants = array(); + + /** * This is an array of trusted static classes. * If empty access to all static classes is allowed. * If set to 'none' none is allowed. @@ -62,20 +80,72 @@ * @var array */ public $static_classes = array(); + /** + * This is an nested array of trusted classes and static methods. + * If empty access to all static classes and methods is allowed. + * Format: + * array ( + * 'class_1' => array('method_1', 'method_2'), // allowed methods listed + * 'class_2' => array(), // all methods of class allowed + * ) + * If set to null none is allowed. + * + * @var array + */ + public $trusted_static_methods = array(); + + /** + * This is an array of trusted static properties. + * If empty access to all static classes and properties is allowed. + * Format: + * array ( + * 'class_1' => array('prop_1', 'prop_2'), // allowed properties listed + * 'class_2' => array(), // all properties of class allowed + * ) + * If set to null none is allowed. + * + * @var array + */ + public $trusted_static_properties = array(); + + /** + * This is an nested array of trusted classes and static methods. + * If empty access to all static classes and methods is allowed. + * Format: + * array ( + * 'class_1' => array('method_1', 'method_2'), // allowed methods listed + * 'class_2' => array(), // all methods of class allowed + * ) + * If set to null none is allowed. + * + * @var array + */ + public $trusted_static_methods = array(); + + /** + * This is an array of trusted static properties. + * If empty access to all static classes and properties is allowed. + * Format: + * array ( + * 'class_1' => array('prop_1', 'prop_2'), // allowed properties listed + * 'class_2' => array(), // all properties of class allowed + * ) + * If set to null none is allowed. + * + * @var array + */ + public $trusted_static_properties = array(); + + /** * This is an array of trusted PHP functions. * If empty all functions are allowed. * To disable all PHP functions set $php_functions = null. * * @var array */ - public $php_functions = array( - 'isset', 'empty', - 'count', 'sizeof', - 'in_array', 'is_array', - 'time', - 'nl2br', - ); + public $php_functions = array('isset', 'empty', 'count', 'sizeof', 'in_array', 'is_array', 'time',); + /** * This is an array of trusted PHP modifiers. * If empty all modifiers are allowed. @@ -83,10 +153,8 @@ * * @var array */ - public $php_modifiers = array( - 'escape', - 'count' - ); + public $php_modifiers = array('escape', 'count', 'nl2br',); + /** * This is an array of allowed tags. * If empty no restriction by allowed_tags. @@ -94,6 +162,7 @@ * @var array */ public $allowed_tags = array(); + /** * This is an array of disabled tags. * If empty no restriction by disabled_tags. @@ -101,6 +170,7 @@ * @var array */ public $disabled_tags = array(); + /** * This is an array of allowed modifier plugins. * If empty no restriction by allowed_modifiers. @@ -108,6 +178,7 @@ * @var array */ public $allowed_modifiers = array(); + /** * This is an array of disabled modifier plugins. * If empty no restriction by disabled_modifiers. @@ -115,7 +186,22 @@ * @var array */ public $disabled_modifiers = array(); + /** + * This is an array of disabled special $smarty variables. + * + * @var array + */ + public $disabled_special_smarty_vars = array(); + + /** + * This is an array of disabled special $smarty variables. + * + * @var array + */ + public $disabled_special_smarty_vars = array(); + + /** * This is an array of trusted streams. * If empty all streams are allowed. * To disable all streams set $streams = null. @@ -123,12 +209,14 @@ * @var array */ public $streams = array('file'); + /** * + flag if constants can be accessed from template * * @var boolean */ public $allow_constants = true; + /** * + flag if super globals can be accessed from template * @@ -137,35 +225,54 @@ public $allow_super_globals = true; /** + * max template nesting level + * + * @var int + */ + public $max_template_nesting = 0; + + /** + * current template nesting level + * + * @var int + */ + private $_current_template_nesting = 0; + + /** * Cache for $resource_dir lookup * * @var array */ - protected $_resource_dir = null; + protected $_resource_dir = array(); + /** * Cache for $template_dir lookup * * @var array */ - protected $_template_dir = null; + protected $_template_dir = array(); + /** * Cache for $config_dir lookup * * @var array */ - protected $_config_dir = null; + protected $_config_dir = array(); + /** * Cache for $secure_dir lookup * * @var array */ - protected $_secure_dir = null; + protected $_secure_dir = array(); + /** * Cache for $php_resource_dir lookup * * @var array */ protected $_php_resource_dir = null; + /** * Cache for $trusted_dir lookup * @@ -174,6 +281,20 @@ protected $_trusted_dir = null; /** + * Cache for include path status + * + * @var bool + */ + protected $_include_path_status = false; + + /** + * Cache for $_include_array lookup + * + * @var array + */ + protected $_include_dir = array(); + + /** * @param Smarty $smarty */ public function __construct($smarty) @@ -192,7 +313,9 @@ */ public function isTrustedPhpFunction($function_name, $compiler) { - if (isset($this->php_functions) && (empty($this->php_functions) || in_array($function_name, $this->php_functions))) { + if (isset($this->php_functions) && + (empty($this->php_functions) || in_array($function_name, $this->php_functions)) + ) { return true; } @@ -212,7 +335,9 @@ */ public function isTrustedStaticClass($class_name, $compiler) { - if (isset($this->static_classes) && (empty($this->static_classes) || in_array($class_name, $this->static_classes))) { + if (isset($this->static_classes) && + (empty($this->static_classes) || in_array($class_name, $this->static_classes)) + ) { return true; } @@ -222,6 +347,84 @@ } /** + * Check if static class method/property is trusted. + * + * @param string $class_name + * @param string $params + * @param object $compiler compiler object + * + * @return boolean true if class method is trusted + * @throws SmartyCompilerException if static class method is not trusted + */ + public function isTrustedStaticClassAccess($class_name, $params, $compiler) + { + if (!isset($params[2])) { + // fall back + return $this->isTrustedStaticClass($class_name, $compiler); + } + if ($params[2] == 'method') { + $allowed = $this->trusted_static_methods; + $name = substr($params[0], 0, strpos($params[0], '(')); + } else { + $allowed = $this->trusted_static_properties; + // strip '$' + $name = substr($params[0], 1); + } + if (isset($allowed)) { + if (empty($allowed)) { + // fall back + return $this->isTrustedStaticClass($class_name, $compiler); + } + if (isset($allowed[$class_name]) && + (empty($allowed[$class_name]) || in_array($name, $allowed[$class_name])) + ) { + return true; + } + } + $compiler->trigger_template_error("access to static class '{$class_name}' {$params[2]} '{$name}' not allowed by security setting"); + return false; // should not, but who knows what happens to the compiler in the future? + } + + /** + * Check if static class method/property is trusted. + * + * @param string $class_name + * @param string $params + * @param object $compiler compiler object + * + * @return boolean true if class method is trusted + * @throws SmartyCompilerException if static class method is not trusted + */ + public function isTrustedStaticClassAccess($class_name, $params, $compiler) + { + if (!isset($params[2])) { + // fall back + return $this->isTrustedStaticClass($class_name, $compiler); + } + if ($params[2] == 'method') { + $allowed = $this->trusted_static_methods; + $name = substr($params[0], 0, strpos($params[0], '(')); + } else { + $allowed = $this->trusted_static_properties; + // strip '$' + $name = substr($params[0], 1); + } + if (isset($allowed)) { + if (empty($allowed)) { + // fall back + return $this->isTrustedStaticClass($class_name, $compiler); + } + if (isset($allowed[$class_name]) && + (empty($allowed[$class_name]) || in_array($name, $allowed[$class_name])) + ) { + return true; + } + } + $compiler->trigger_template_error("access to static class '{$class_name}' {$params[2]} '{$name}' not allowed by security setting"); + return false; // should not, but who knows what happens to the compiler in the future? + } + + /** * Check if PHP modifier is trusted. * * @param string $modifier_name @@ -232,7 +435,9 @@ */ public function isTrustedPhpModifier($modifier_name, $compiler) { - if (isset($this->php_modifiers) && (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers))) { + if (isset($this->php_modifiers) && + (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers)) + ) { return true; } @@ -253,9 +458,11 @@ public function isTrustedTag($tag_name, $compiler) { // check for internal always required tags - if (in_array($tag_name, array('assign', 'call', 'private_filter', 'private_block_plugin', 'private_function_plugin', 'private_object_block_function', - 'private_object_function', 'private_registered_function', 'private_registered_block', 'private_special_variable', 'private_print_expression', 'private_modifier')) - ) { + if (in_array($tag_name, array('assign', 'call', 'private_filter', 'private_block_plugin', + 'private_function_plugin', 'private_object_block_function', + 'private_object_function', 'private_registered_function', + 'private_registered_block', 'private_special_variable', + 'private_print_expression', 'private_modifier'))) { return true; } // check security settings @@ -263,18 +470,58 @@ if (empty($this->disabled_tags) || !in_array($tag_name, $this->disabled_tags)) { return true; } else { - $compiler->trigger_template_error("tag '{$tag_name}' disabled by security setting", $compiler->lex->taglineno); + $compiler->trigger_template_error("tag '{$tag_name}' disabled by security setting", null, true); } } elseif (in_array($tag_name, $this->allowed_tags) && !in_array($tag_name, $this->disabled_tags)) { return true; } else { - $compiler->trigger_template_error("tag '{$tag_name}' not allowed by security setting", $compiler->lex->taglineno); + $compiler->trigger_template_error("tag '{$tag_name}' not allowed by security setting", null, true); } return false; // should not, but who knows what happens to the compiler in the future? } /** + * Check if special $smarty variable is trusted. + * + * @param string $var_name + * @param object $compiler compiler object + * + * @return boolean true if tag is trusted + * @throws SmartyCompilerException if modifier is not trusted + */ + public function isTrustedSpecialSmartyVar($var_name, $compiler) + { + if (!in_array($var_name, $this->disabled_special_smarty_vars)) { + return true; + } else { + $compiler->trigger_template_error("special variable '\$smarty.{$var_name}' not allowed by security setting", null, true); + } + + return false; // should not, but who knows what happens to the compiler in the future? + } + + /** + * Check if special $smarty variable is trusted. + * + * @param string $var_name + * @param object $compiler compiler object + * + * @return boolean true if tag is trusted + * @throws SmartyCompilerException if modifier is not trusted + */ + public function isTrustedSpecialSmartyVar($var_name, $compiler) + { + if (!in_array($var_name, $this->disabled_special_smarty_vars)) { + return true; + } else { + $compiler->trigger_template_error("special variable '\$smarty.{$var_name}' not allowed by security setting", null, true); + } + + return false; // should not, but who knows what happens to the compiler in the future? + } + + /** * Check if modifier plugin is trusted. * * @param string $modifier_name @@ -294,18 +541,47 @@ if (empty($this->disabled_modifiers) || !in_array($modifier_name, $this->disabled_modifiers)) { return true; } else { - $compiler->trigger_template_error("modifier '{$modifier_name}' disabled by security setting", $compiler->lex->taglineno); + $compiler->trigger_template_error("modifier '{$modifier_name}' disabled by security setting", null, true); } - } elseif (in_array($modifier_name, $this->allowed_modifiers) && !in_array($modifier_name, $this->disabled_modifiers)) { + } elseif (in_array($modifier_name, $this->allowed_modifiers) && + !in_array($modifier_name, $this->disabled_modifiers) + ) { return true; } else { - $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting", $compiler->lex->taglineno); + $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting", null, true); } return false; // should not, but who knows what happens to the compiler in the future? } /** + * Check if constants are enabled or trusted + * + * @param string $const constant name + * @param object $compiler compiler object + * + * @return bool + */ + public function isTrustedConstant($const, $compiler) + { + if (in_array($const, array('true', 'false', 'null'))) { + return true; + } + if (!empty($this->trusted_constants)) { + if (!in_array($const, $this->trusted_constants)) { + $compiler->trigger_template_error("Security: access to constant '{$const}' not permitted"); + return false; + } + return true; + } + if ($this->allow_constants) { + return true; + } + $compiler->trigger_template_error("Security: access to constants not permitted"); + return false; + } + + /** * Check if stream is trusted. * * @param string $stream_name @@ -325,83 +601,72 @@ /** * Check if directory of file resource is trusted. * - * @param string $filepath + * @param string $filepath + * @param null|bool $isConfig * - * @return boolean true if directory is trusted - * @throws SmartyException if directory is not trusted + * @return bool true if directory is trusted + * @throws \SmartyException if directory is not trusted */ - public function isTrustedResourceDir($filepath) + public function isTrustedResourceDir($filepath, $isConfig = null) { - $_template = false; - $_config = false; - $_secure = false; - - $_template_dir = $this->smarty->getTemplateDir(); - $_config_dir = $this->smarty->getConfigDir(); - - // check if index is outdated - if ((!$this->_template_dir || $this->_template_dir !== $_template_dir) - || (!$this->_config_dir || $this->_config_dir !== $_config_dir) - || (!empty($this->secure_dir) && (!$this->_secure_dir || $this->_secure_dir !== $this->secure_dir)) + if ($this->_include_path_status !== $this->smarty->use_include_path) { + foreach ($this->_include_dir as $directory) { + unset($this->_resource_dir[$directory]); + } + if ($this->smarty->use_include_path) { + $this->_include_dir = array(); + $_dirs = $this->smarty->ext->_getIncludePath->getIncludePathDirs($this->smarty); + foreach ($_dirs as $directory) { + $this->_include_dir[] = $directory; + $this->_resource_dir[$directory] = true; + } + } + $this->_include_path_status = $this->smarty->use_include_path; + } + if ($isConfig !== true && + (!isset($this->smarty->_cache['template_dir_new']) || $this->smarty->_cache['template_dir_new']) ) { - $this->_resource_dir = array(); - $_template = true; - $_config = true; - $_secure = !empty($this->secure_dir); + $_dir = $this->smarty->getTemplateDir(); + if ($this->_template_dir !== $_dir) { + foreach ($this->_template_dir as $directory) { + unset($this->_resource_dir[$directory]); - } + } - - // rebuild template dir index - if ($_template) { - $this->_template_dir = $_template_dir; - foreach ($_template_dir as $directory) { - $directory = realpath($directory); + foreach ($_dir as $directory) { - $this->_resource_dir[$directory] = true; - } + $this->_resource_dir[$directory] = true; + } + $this->_template_dir = $_dir; - } + } - - // rebuild config dir index - if ($_config) { - $this->_config_dir = $_config_dir; - foreach ($_config_dir as $directory) { - $directory = realpath($directory); + $this->smarty->_cache['template_dir_new'] = false; + } + if ($isConfig !== false && + (!isset($this->smarty->_cache['config_dir_new']) || $this->smarty->_cache['config_dir_new']) + ) { + $_dir = $this->smarty->getConfigDir(); + if ($this->_config_dir !== $_dir) { + foreach ($this->_config_dir as $directory) { + unset($this->_resource_dir[$directory]); + } + foreach ($_dir as $directory) { - $this->_resource_dir[$directory] = true; - } + $this->_resource_dir[$directory] = true; + } + $this->_config_dir = $_dir; - } + } - - // rebuild secure dir index - if ($_secure) { - $this->_secure_dir = $this->secure_dir; + $this->smarty->_cache['config_dir_new'] = false; + } + if ($this->_secure_dir !== (array) $this->secure_dir) { + foreach ($this->_secure_dir as $directory) { + unset($this->_resource_dir[$directory]); + } foreach ((array) $this->secure_dir as $directory) { - $directory = realpath($directory); + $directory = $this->smarty->_realpath($directory . DS, true); $this->_resource_dir[$directory] = true; } + $this->_secure_dir = (array) $this->secure_dir; } - - $_filepath = realpath($filepath); - $directory = dirname($_filepath); - $_directory = array(); - while (true) { - // remember the directory to add it to _resource_dir in case we're successful - $_directory[$directory] = true; - // test if the directory is trusted - if (isset($this->_resource_dir[$directory])) { - // merge sub directories of current $directory into _resource_dir to speed up subsequent lookup - $this->_resource_dir = array_merge($this->_resource_dir, $_directory); - + $this->_resource_dir = $this->_checkDir($filepath, $this->_resource_dir); - return true; - } + return true; + } - // abort if we've reached root - if (($pos = strrpos($directory, DS)) === false || !isset($directory[1])) { - break; - } - // bubble up one level - $directory = substr($directory, 0, $pos); - } - // give up - throw new SmartyException("directory '{$_filepath}' not allowed by security setting"); - } - /** * Check if URI (e.g. {fetch} or {html_image}) is trusted * To simplify things, isTrustedUri() resolves all input to "{$PROTOCOL}://{$HOSTNAME}". @@ -432,7 +697,8 @@ /** * Check if directory of file resource is trusted. * - * @param string $filepath + * @param string $filepath + * @param null|bool $isConfig * * @return boolean true if directory is trusted * @throws SmartyException if PHP directory is not trusted @@ -449,32 +715,103 @@ $this->_trusted_dir = $this->trusted_dir; foreach ((array) $this->trusted_dir as $directory) { - $directory = realpath($directory); + $directory = $this->smarty->_realpath($directory . DS, true); $this->_php_resource_dir[$directory] = true; } } - $_filepath = realpath($filepath); - $directory = dirname($_filepath); + $this->_php_resource_dir = $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 + * + * @param string $filepath + * @param array $dirs valid directories + * + * @return array + * @throws \SmartyException + */ + private function _checkDir($filepath, $dirs) + { + $directory = dirname($filepath) . DS; $_directory = array(); while (true) { // remember the directory to add it to _resource_dir in case we're successful - $_directory[] = $directory; + $_directory[$directory] = true; // test if the directory is trusted - if (isset($this->_php_resource_dir[$directory])) { + if (isset($dirs[$directory])) { // merge sub directories of current $directory into _resource_dir to speed up subsequent lookup - $this->_php_resource_dir = array_merge($this->_php_resource_dir, $_directory); + $dirs = array_merge($dirs, $_directory); - return true; + return $dirs; } // abort if we've reached root - if (($pos = strrpos($directory, DS)) === false || !isset($directory[2])) { + if (!preg_match('#[\\\/][^\\\/]+[\\\/]$#', $directory)) { break; } // bubble up one level - $directory = substr($directory, 0, $pos); + $directory = preg_replace('#[\\\/][^\\\/]+[\\\/]$#', DS, $directory); } - throw new SmartyException("directory '{$_filepath}' not allowed by security setting"); + // give up + throw new SmartyException("directory '{$filepath}' not allowed by security setting"); + } + + /** + * Loads security class and enables security + * + * @param \Smarty $smarty + * @param string|Smarty_Security $security_class if a string is used, it must be class-name + * + * @return \Smarty current Smarty instance for chaining + * @throws \SmartyException when an invalid class name is provided + */ + public static function enableSecurity(Smarty $smarty, $security_class) + { + if ($security_class instanceof Smarty_Security) { + $smarty->security_policy = $security_class; + return; + } elseif (is_object($security_class)) { + throw new SmartyException("Class '" . get_class($security_class) . "' must extend Smarty_Security."); + } + if ($security_class == null) { + $security_class = $smarty->security_class; + } + if (!class_exists($security_class)) { + throw new SmartyException("Security class '$security_class' is not defined"); + } elseif ($security_class !== 'Smarty_Security' && !is_subclass_of($security_class, 'Smarty_Security')) { + throw new SmartyException("Class '$security_class' must extend Smarty_Security."); + } else { + $smarty->security_policy = new $security_class($smarty); + } + return; } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_special_variable.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_special_variable.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_special_variable.php (revision Shelved version) @@ -19,96 +19,108 @@ /** * Compiles code for the special $smarty variables * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param $parameter + * @param $parameter * * @return string compiled code + * @throws \SmartyCompilerException */ - public function compile($args, $compiler, $parameter) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { $_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2)); - $compiled_ref = ' '; - $variable = trim($_index[0], "'"); + $variable = strtolower($compiler->getId($_index[ 0 ])); + if ($variable === false) { + $compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true); + } + if (!isset($compiler->smarty->security_policy) || + $compiler->smarty->security_policy->isTrustedSpecialSmartyVar($variable, $compiler) + ) { - switch ($variable) { - case 'foreach': + switch ($variable) { + case 'foreach': - return "\$_smarty_tpl->getVariable('smarty')->value$parameter"; - case 'section': + case 'section': - return "\$_smarty_tpl->getVariable('smarty')->value$parameter"; + if (!isset($compiler->_tag_objects[ $variable ])) { + $class = 'Smarty_Internal_Compile_' . ucfirst($variable); + $compiler->_tag_objects[ $variable ] = new $class; + } + return $compiler->_tag_objects[ $variable ]->compileSpecialVariable(array(), $compiler, $_index); - case 'capture': + case 'capture': - return "Smarty::\$_smarty_vars$parameter"; + if (class_exists('Smarty_Internal_Compile_Capture')) { + return Smarty_Internal_Compile_Capture::compileSpecialVariable(array(), $compiler, $_index); + } + return ''; - case 'now': - return 'time()'; - case 'cookies': + case 'now': + return 'time()'; + case 'cookies': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_super_globals) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_super_globals + ) { - $compiler->trigger_template_error("(secure mode) super globals not permitted"); - break; - } - $compiled_ref = '$_COOKIE'; - break; + $compiler->trigger_template_error("(secure mode) super globals not permitted"); + break; + } + $compiled_ref = '$_COOKIE'; + break; - - case 'get': - case 'post': - case 'env': - case 'server': - case 'session': - case 'request': + case 'get': + case 'post': + case 'env': + case 'server': + case 'session': + case 'request': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_super_globals) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_super_globals + ) { - $compiler->trigger_template_error("(secure mode) super globals not permitted"); - break; - } - $compiled_ref = '$_' . strtoupper($variable); - break; + $compiler->trigger_template_error("(secure mode) super globals not permitted"); + break; + } + $compiled_ref = '$_' . strtoupper($variable); + break; - case 'template': - return 'basename($_smarty_tpl->source->filepath)'; + case 'template': + return 'basename($_smarty_tpl->source->filepath)'; - case 'template_object': - return '$_smarty_tpl'; + case 'template_object': + return '$_smarty_tpl'; - case 'current_dir': - return 'dirname($_smarty_tpl->source->filepath)'; + case 'current_dir': + return 'dirname($_smarty_tpl->source->filepath)'; - case 'version': + case 'version': - $_version = Smarty::SMARTY_VERSION; + return "Smarty::SMARTY_VERSION"; - return "'$_version'"; - - case 'const': + case 'const': - if (isset($compiler->smarty->security_policy) && !$compiler->smarty->security_policy->allow_constants) { + if (isset($compiler->smarty->security_policy) && + !$compiler->smarty->security_policy->allow_constants + ) { - $compiler->trigger_template_error("(secure mode) constants not permitted"); - break; - } + $compiler->trigger_template_error("(secure mode) constants not permitted"); + break; + } - + if (strpos($_index[ 1 ], '$') === false && strpos($_index[ 1 ], '\'') === false) { + return "@constant('{$_index[1]}')"; + } else { - return "@constant({$_index[1]})"; + return "@constant({$_index[1]})"; + } - case 'config': + case 'config': - if (isset($_index[2])) { + if (isset($_index[ 2 ])) { - return "(is_array(\$tmp = \$_smarty_tpl->getConfigVariable($_index[1])) ? \$tmp[$_index[2]] : null)"; + return "(is_array(\$tmp = \$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])) ? \$tmp[$_index[2]] : null)"; - } else { + } else { - return "\$_smarty_tpl->getConfigVariable($_index[1])"; + return "\$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])"; - } - case 'ldelim': + } + case 'ldelim': - $_ldelim = $compiler->smarty->left_delimiter; - - return "'$_ldelim'"; - + return "\$_smarty_tpl->smarty->left_delimiter"; - case 'rdelim': + case 'rdelim': - $_rdelim = $compiler->smarty->right_delimiter; - - return "'$_rdelim'"; - + return "\$_smarty_tpl->smarty->right_delimiter"; - default: + default: - $compiler->trigger_template_error('$smarty.' . trim($_index[0], "'") . ' is invalid'); + $compiler->trigger_template_error('$smarty.' . trim($_index[ 0 ], "'") . ' is not defined'); - break; - } + break; + } - if (isset($_index[1])) { + if (isset($_index[ 1 ])) { - array_shift($_index); - foreach ($_index as $_ind) { - $compiled_ref = $compiled_ref . "[$_ind]"; - } - } + array_shift($_index); + foreach ($_index as $_ind) { + $compiled_ref = $compiled_ref . "[$_ind]"; + } + } - - return $compiled_ref; + return $compiled_ref; + } } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_gettemplatevars.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_gettemplatevars.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_gettemplatevars.php (revision Shelved version) @@ -0,0 +1,114 @@ +_getVariable($data, $varName, $_ptr, $searchParents, false); + if (is_object($_var)) { + return $_var->value; + } else { + return null; + } + } else { + $_result = array(); + if ($_ptr === null) { + $_ptr = $data; + } + while ($_ptr !== null) { + foreach ($_ptr->tpl_vars AS $key => $var) { + if (!array_key_exists($key, $_result)) { + $_result[$key] = $var->value; + } + } + // not found, try at parent + if ($searchParents) { + $_ptr = $_ptr->parent; + } else { + $_ptr = null; + } + } + if ($searchParents && isset(Smarty::$global_tpl_vars)) { + foreach (Smarty::$global_tpl_vars AS $key => $var) { + if (!array_key_exists($key, $_result)) { + $_result[$key] = $var->value; + } + } + } + return $_result; + } + } + + /** + * gets the object of a Smarty variable + * + * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $data + * @param string $varName the name of the Smarty variable + * @param \Smarty_Internal_Data|\Smarty_Internal_Template|\Smarty $_ptr optional pointer to data object + * @param bool $searchParents search also in parent data + * @param bool $errorEnable + * + * @return \Smarty_Variable + */ + public function _getVariable(Smarty_Internal_Data $data, $varName, Smarty_Internal_Data $_ptr = null, $searchParents = true, $errorEnable = true) + { + if ($_ptr === null) { + $_ptr = $data; + } + while ($_ptr !== null) { + if (isset($_ptr->tpl_vars[$varName])) { + // found it, return it + return $_ptr->tpl_vars[$varName]; + } + // not found, try at parent + if ($searchParents) { + $_ptr = $_ptr->parent; + } else { + $_ptr = null; + } + } + if (isset(Smarty::$global_tpl_vars[$varName])) { + // found it, return it + return Smarty::$global_tpl_vars[$varName]; + } + /* @var \Smarty $smarty */ + $smarty = isset($data->smarty) ? $data->smarty : $data; + if ($smarty->error_unassigned && $errorEnable) { + // force a notice + $x = $$varName; + } + + return new Smarty_Undefined_Variable; + } + +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_config_load.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_config_load.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_config_load.php (revision Shelved version) @@ -23,6 +23,7 @@ * @see Smarty_Internal_CompileBase */ public $required_attributes = array('file'); + /** * Attribute definition: Overwrites base class. * @@ -30,30 +31,47 @@ * @see Smarty_Internal_CompileBase */ public $shorttag_order = array('file', 'section'); + /** * Attribute definition: Overwrites base class. * * @var array * @see Smarty_Internal_CompileBase */ - public $optional_attributes = array('section', 'scope'); + public $optional_attributes = array('section', 'scope', 'bubble_up'); /** + * Valid scope names + * + * @var array + */ + public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true, + 'smarty' => true, 'tpl_root' => true); + + /** + * Valid scope names + * + * @var array + */ + public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true, + 'smarty' => true, 'tpl_root' => true); + + /** * Compiles code for the {config_load} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * * @return string compiled code + * @throws \SmartyCompilerException */ - public function compile($args, $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) { - static $_is_legal_scope = array('local' => true, 'parent' => true, 'root' => true, 'global' => true); // check and get attributes $_attr = $this->getAttributes($compiler, $args); if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); + $compiler->trigger_template_error('nocache option not allowed', null, true); } // save possible attributes @@ -63,19 +81,46 @@ } else { $section = 'null'; } - $scope = 'local'; - // scope setup + $_scope = Smarty::SCOPE_LOCAL; if (isset($_attr['scope'])) { $_attr['scope'] = trim($_attr['scope'], "'\""); - if (isset($_is_legal_scope[$_attr['scope']])) { - $scope = $_attr['scope']; - } else { - $compiler->trigger_template_error('illegal value for "scope" attribute', $compiler->lex->taglineno); + if (!isset($this->valid_scopes[$_attr['scope']])) { + $compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, true); } + if ($_attr['scope'] != 'local') { + if ($_attr['scope'] == 'parent') { + $_scope = Smarty::SCOPE_PARENT; + } elseif ($_attr['scope'] == 'root') { + $_scope = Smarty::SCOPE_ROOT; + } elseif ($_attr['scope'] == 'global') { + $_scope = Smarty::SCOPE_GLOBAL; + } elseif ($_attr['scope'] == 'smarty') { + $_scope = Smarty::SCOPE_SMARTY; + } elseif ($_attr['scope'] == 'tpl_root') { + $_scope = Smarty::SCOPE_TPL_ROOT; - } + } + $_scope += (isset($_attr['bubble_up']) && $_attr['bubble_up'] == 'false') ? 0 : Smarty::SCOPE_BUBBLE_UP; + } + if ($_attr['scope'] != 'local') { + if ($_attr['scope'] == 'parent') { + $_scope = Smarty::SCOPE_PARENT; + } elseif ($_attr['scope'] == 'root') { + $_scope = Smarty::SCOPE_ROOT; + } elseif ($_attr['scope'] == 'global') { + $_scope = Smarty::SCOPE_GLOBAL; + } elseif ($_attr['scope'] == 'smarty') { + $_scope = Smarty::SCOPE_SMARTY; + } elseif ($_attr['scope'] == 'tpl_root') { + $_scope = Smarty::SCOPE_TPL_ROOT; + } + $_scope += (isset($_attr['bubble_up']) && $_attr['bubble_up'] == 'false') ? 0 : Smarty::SCOPE_BUBBLE_UP; + } + } + + // create config object - $_output = "smarty, \$_smarty_tpl);"; - $_output .= "\$_config->loadConfigVars($section, '$scope'); ?>"; + $_output = + "smarty->ext->configLoad->_loadConfigFile(\$_smarty_tpl, {$conf_file}, {$section}, {$_scope});\n?>\n"; return $_output; } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_foreach.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_foreach.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_foreach.php (revision Shelved version) @@ -0,0 +1,47 @@ +getIterator()); + } elseif ($value instanceof Iterator) { + if ($value instanceof Generator) { + return 1; + } + return iterator_count($value); + } elseif ($value instanceof PDOStatement) { + return $value->rowCount(); + } elseif ($value instanceof Traversable) { + return iterator_count($value); + } elseif ($value instanceof ArrayAccess) { + if ($value->offsetExists(0)) { + return 1; + } + } elseif (is_object($value)) { + return count($value); + } + return 0; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_data.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_data.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_data.php (revision Shelved version) @@ -0,0 +1,68 @@ +dataObjectName = 'Data_object ' . (isset($name) ? "'{$name}'" : self::$count); + $this->smarty = $smarty; + if (is_object($_parent)) { + // when object set up back pointer + $this->parent = $_parent; + } elseif (is_array($_parent)) { + // set up variable values + foreach ($_parent as $_key => $_val) { + $this->tpl_vars[$_key] = new Smarty_Variable($_val); + } + } elseif ($_parent != null) { + throw new SmartyException("Wrong type for template variables"); + } + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_continue.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_continue.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_continue.php (revision Shelved version) @@ -23,6 +23,7 @@ * @see Smarty_Internal_CompileBase */ public $optional_attributes = array('levels'); + /** * Attribute definition: Overwrites base class. * @@ -34,25 +35,26 @@ /** * Compiles code for the {continue} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter + * @param array $parameter array with compilation parameter * * @return string compiled code + * @throws \SmartyCompilerException */ - public function compile($args, $compiler, $parameter) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true); // check and get attributes $_attr = $this->getAttributes($compiler, $args); if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); + $compiler->trigger_template_error('nocache option not allowed', null, true); } if (isset($_attr['levels'])) { if (!is_numeric($_attr['levels'])) { - $compiler->trigger_template_error('level attribute must be a numeric constant', $compiler->lex->taglineno); + $compiler->trigger_template_error('level attribute must be a numeric constant', null, true); } $_levels = $_attr['levels']; } else { @@ -67,7 +69,7 @@ $stack_count --; } if ($level_count != 0) { - $compiler->trigger_template_error("cannot continue {$_levels} level(s)", $compiler->lex->taglineno); + $compiler->trigger_template_error("cannot continue {$_levels} level(s)", null, true); } return ""; Index: src/includes/classes/Smarty/sysplugins/smartyexception.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smartyexception.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smartyexception.php (revision Shelved version) @@ -0,0 +1,15 @@ + Smarty: ' . (self::$escape ? htmlentities($this->message) : $this->message) . ' <-- '; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_tag.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_tag.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_tag.php (revision Shelved version) @@ -0,0 +1,69 @@ +data = $data; + $this->saved_block_nesting = $parser->block_nesting_level; + } + + /** + * Return buffer content + * + * @param \Smarty_Internal_Templateparser $parser + * + * @return string content + */ + public function to_smarty_php(Smarty_Internal_Templateparser $parser) + { + return $this->data; + } + + /** + * Return complied code that loads the evaluated output of buffer content into a temporary variable + * + * @param \Smarty_Internal_Templateparser $parser + * + * @return string template code + */ + public function assign_to_var(Smarty_Internal_Templateparser $parser) + { + $var = sprintf('$_tmp%d', ++ Smarty_Internal_Templateparser::$prefix_number); + $tmp = $parser->compiler->appendCode('', $this->data); + $tmp = $parser->compiler->appendCode($tmp, ""); + $parser->compiler->prefix_code[] = sprintf("%s", $tmp); + + return $var; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree.php (revision Shelved version) @@ -14,15 +14,10 @@ * @subpackage Compiler * @ignore */ -abstract class _smarty_parsetree +abstract class Smarty_Internal_ParseTree { + /** - * Parser object - * - * @var object - */ - public $parser; - /** * Buffer content * * @var mixed @@ -39,323 +34,21 @@ /** * Return buffer * + * @param \Smarty_Internal_Templateparser $parser + * * @return string buffer content */ - abstract public function to_smarty_php(); -} + abstract public function to_smarty_php(Smarty_Internal_Templateparser $parser); -/** + /** - * A complete smarty tag. - * - * @package Smarty - * @subpackage Compiler - * @ignore + * Template data object destructor - */ + */ -class _smarty_tag extends _smarty_parsetree + public function __destruct() -{ + { - /** - * Saved block nesting level - * - * @var int - */ - public $saved_block_nesting; - - /** - * Create parse tree buffer for Smarty tag - * - * @param object $parser parser object - * @param string $data content - */ - public function __construct($parser, $data) - { - $this->parser = $parser; - $this->data = $data; - $this->saved_block_nesting = $parser->block_nesting_level; + $this->data = null; + $this->subtrees = null; } - /** - * Return buffer content - * - * @return string content - */ - public function to_smarty_php() - { - return $this->data; - } +} - /** - * Return complied code that loads the evaluated output of buffer content into a temporary variable - * - * @return string template code - */ - 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); - return $var; - } -} - -/** - * Code fragment inside a tag. - * - * @package Smarty - * @subpackage Compiler - * @ignore - */ -class _smarty_code extends _smarty_parsetree -{ - /** - * Create parse tree buffer for code fragment - * - * @param object $parser parser object - * @param string $data content - */ - public function __construct($parser, $data) - { - $this->parser = $parser; - $this->data = $data; - } - - /** - * Return buffer content in parentheses - * - * @return string content - */ - public function to_smarty_php() - { - return sprintf("(%s)", $this->data); - } -} - -/** - * Double quoted string inside a tag. - * - * @package Smarty - * @subpackage Compiler - * @ignore - */ -class _smarty_doublequoted extends _smarty_parsetree -{ - /** - * Create parse tree buffer for double quoted string subtrees - * - * @param object $parser parser object - * @param _smarty_parsetree $subtree parsetree buffer - */ - public function __construct($parser, _smarty_parsetree $subtree) - { - $this->parser = $parser; - $this->subtrees[] = $subtree; - if ($subtree instanceof _smarty_tag) { - $this->parser->block_nesting_level = count($this->parser->compiler->_tag_stack); - } - } - - /** - * Append buffer to subtree - * - * @param _smarty_parsetree $subtree parsetree buffer - */ - public function append_subtree(_smarty_parsetree $subtree) - { - $last_subtree = count($this->subtrees) - 1; - if ($last_subtree >= 0 && $this->subtrees[$last_subtree] instanceof _smarty_tag && $this->subtrees[$last_subtree]->saved_block_nesting < $this->parser->block_nesting_level) { - if ($subtree instanceof _smarty_code) { - $this->subtrees[$last_subtree]->data .= 'data . ';?>'; - } elseif ($subtree instanceof _smarty_dq_content) { - $this->subtrees[$last_subtree]->data .= 'data . '";?>'; - } else { - $this->subtrees[$last_subtree]->data .= $subtree->data; - } - } else { - $this->subtrees[] = $subtree; - } - if ($subtree instanceof _smarty_tag) { - $this->parser->block_nesting_level = count($this->parser->compiler->_tag_stack); - } - } - - /** - * Merge subtree buffer content together - * - * @return string compiled template code - */ - public function to_smarty_php() - { - $code = ''; - foreach ($this->subtrees as $subtree) { - if ($code !== "") { - $code .= "."; - } - if ($subtree instanceof _smarty_tag) { - $more_php = $subtree->assign_to_var(); - } else { - $more_php = $subtree->to_smarty_php(); - } - - $code .= $more_php; - - if (!$subtree instanceof _smarty_dq_content) { - $this->parser->compiler->has_variable_string = true; - } - } - - return $code; - } -} - -/** - * Raw chars as part of a double quoted string. - * - * @package Smarty - * @subpackage Compiler - * @ignore - */ -class _smarty_dq_content extends _smarty_parsetree -{ - /** - * Create parse tree buffer with string content - * - * @param object $parser parser object - * @param string $data string section - */ - public function __construct($parser, $data) - { - $this->parser = $parser; - $this->data = $data; - } - - /** - * Return content as double quoted string - * - * @return string doubled quoted string - */ - public function to_smarty_php() - { - return '"' . $this->data . '"'; - } -} - -/** - * Template element - * - * @package Smarty - * @subpackage Compiler - * @ignore - */ -class _smarty_template_buffer extends _smarty_parsetree -{ - /** - * Array of template elements - * - * @var array - */ - public $subtrees = Array(); - - /** - * Create root of parse tree for template elements - * - * @param object $parser parse object - */ - public function __construct($parser) - { - $this->parser = $parser; - } - - /** - * Append buffer to subtree - * - * @param _smarty_parsetree $subtree - */ - public function append_subtree(_smarty_parsetree $subtree) - { - if ($subtree->data !== '') { - $this->subtrees[] = $subtree; - } - } - - /** - * Sanitize and merge subtree buffers together - * - * @return string template code content - */ - public function to_smarty_php() - { - $code = ''; - 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++; - if ($this->subtrees[$key]->data == '') { - continue; - } - $subtree .= $this->subtrees[$key]->to_smarty_php(); - } - if ($subtree == '') { - continue; - } - $code .= preg_replace('/(<%|%>|<\?php|<\?|\?>|<\/?script)/', "\n", $subtree); - continue; - } - 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++; - 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); - $subtree .= preg_replace('/^\s*<\?php\s+/', '', $newCode); - } else { - $subtree .= $newCode; - } - } - if ($subtree == '') { - continue; - } - $code .= $subtree; - continue; - } - $code .= $this->subtrees[$key]->to_smarty_php(); - } - return $code; - } - -} - -/** - * template text - * - * @package Smarty - * @subpackage Compiler - * @ignore - */ -class _smarty_text extends _smarty_parsetree -{ - /** - * Create template text buffer - * - * @param object $parser parser object - * @param string $data text - */ - public function __construct($parser, $data) - { - $this->parser = $parser; - $this->data = $data; - } - - /** - * Return buffer content - * - * @return strint text - */ - public function to_smarty_php() - { - return $this->data; - } -} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_break.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_break.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_break.php (revision Shelved version) @@ -23,6 +23,7 @@ * @see Smarty_Internal_CompileBase */ public $optional_attributes = array('levels'); + /** * Attribute definition: Overwrites base class. * @@ -34,25 +35,26 @@ /** * Compiles code for the {break} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter + * @param array $parameter array with compilation parameter * * @return string compiled code + * @throws \SmartyCompilerException */ - public function compile($args, $compiler, $parameter) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true); // check and get attributes $_attr = $this->getAttributes($compiler, $args); if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); + $compiler->trigger_template_error('nocache option not allowed', null, true); } if (isset($_attr['levels'])) { if (!is_numeric($_attr['levels'])) { - $compiler->trigger_template_error('level attribute must be a numeric constant', $compiler->lex->taglineno); + $compiler->trigger_template_error('level attribute must be a numeric constant', null, true); } $_levels = $_attr['levels']; } else { @@ -67,7 +69,7 @@ $stack_count --; } if ($level_count != 0) { - $compiler->trigger_template_error("cannot break {$_levels} level(s)", $compiler->lex->taglineno); + $compiler->trigger_template_error("cannot break {$_levels} level(s)", null, true); } return ""; Index: src/includes/classes/Smarty/sysplugins/smarty_internal_extension_handler.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_extension_handler.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_extension_handler.php (revision Shelved version) @@ -0,0 +1,157 @@ + 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0, + 'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0, + 'TemplateVars' => 0,);# + + private $resolvedProperties = array(); + + /** + * Call external Method + * + * @param \Smarty_Internal_Data $data + * @param string $name external method names + * @param array $args argument array + * + * @return mixed + * @throws SmartyException + */ + public function _callExternalMethod(Smarty_Internal_Data $data, $name, $args) + { + /* @var Smarty $data ->smarty */ + $smarty = isset($data->smarty) ? $data->smarty : $data; + if (!isset($smarty->ext->$name)) { + $class = 'Smarty_Internal_Method_' . ucfirst($name); + if (preg_match('/^(set|get)([A-Z].*)$/', $name, $match)) { + if (!isset($this->_property_info[$prop = $match[2]])) { + // convert camel case to underscored name + $this->resolvedProperties[$prop] = $pn = strtolower(join('_', + preg_split('/([A-Z][^A-Z]*)/', $prop, - 1, + PREG_SPLIT_NO_EMPTY | + PREG_SPLIT_DELIM_CAPTURE))); + $this->_property_info[$prop] = property_exists($data, $pn) ? 1 : + ($data->_objType == 2 && property_exists($smarty, $pn) ? 2 : 0); + } + if ($this->_property_info[$prop]) { + $pn = $this->resolvedProperties[$prop]; + if ($match[1] == 'get') { + return $this->_property_info[$prop] == 1 ? $data->$pn : $data->smarty->$pn; + } else { + return $this->_property_info[$prop] == 1 ? $data->$pn = $args[0] : + $data->smarty->$pn = $args[0]; + } + } elseif (!class_exists($class)) { + throw new SmartyException("property '$pn' does not exist."); + } + } + if (class_exists($class)) { + $callback = array($smarty->ext->$name = new $class(), $name); + } + } else { + $callback = array($smarty->ext->$name, $name); + } + array_unshift($args, $data); + if (isset($callback) && $callback[0]->objMap | $data->_objType) { + return call_user_func_array($callback, $args); + } + return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args); + } + + /** + * set extension property + * + * @param string $property_name property name + * @param mixed $value value + * + * @throws SmartyException + */ + public function __set($property_name, $value) + { + $this->$property_name = $value; + } + + /** + * get extension object + * + * @param string $property_name property name + * + * @return mixed|Smarty_Template_Cached + * @throws SmartyException + */ + public function __get($property_name) + { + // object properties of runtime template extensions will start with '_' + if ($property_name[0] == '_') { + $class = 'Smarty_Internal_Runtime_' . ucfirst(substr($property_name, 1)); + } else { + $class = 'Smarty_Internal_Method_' . ucfirst($property_name); + } + if (class_exists($class)) { + return $this->$property_name = new $class(); + } + return $this; + } + + /** + * Call error handler for undefined method + * + * @param string $name unknown method-name + * @param array $args argument array + * + * @return mixed + * @throws SmartyException + */ + public function __call($name, $args) + { + return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args); + } + +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_configfilelexer.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_configfilelexer.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_configfilelexer.php (revision Shelved version) @@ -1,6 +1,7 @@ 'START', 2 => 'VALUE', 3 => 'NAKED_STRING_VALUE', 4 => 'COMMENT', 5 => 'SECTION', 6 => 'TRIPPLE'); + + /** + * state names + * + * @var array + */ + public $state_name = array(1 => 'START', 2 => 'VALUE', 3 => 'NAKED_STRING_VALUE', 4 => 'COMMENT', 5 => 'SECTION', + 6 => 'TRIPPLE'); + + /** + * storage for assembled token patterns + * + * @var sring + */ + private $yy_global_pattern1 = null; + + private $yy_global_pattern2 = null; + + private $yy_global_pattern3 = null; + + private $yy_global_pattern4 = null; + + private $yy_global_pattern5 = null; + + private $yy_global_pattern6 = null; + + /** + * token names + * + * @var array + */ - public $smarty_token_names = array( // Text for parser error messages + public $smarty_token_names = array( // Text for parser error messages ); - function __construct($data, $compiler) + /** + * constructor + * + * @param string $data template source + * @param Smarty_Internal_Config_File_Compiler $compiler + */ + function __construct($data, Smarty_Internal_Config_File_Compiler $compiler) { // set instance object self::instance($this); @@ -39,6 +149,7 @@ $this->line = 1; $this->compiler = $compiler; $this->smarty = $compiler->smarty; + $this->configBooleanize = $this->smarty->config_booleanize; } public static function &instance($new_instance = null) @@ -57,6 +168,7 @@ } private $_yy_state = 1; + private $_yy_stack = array(); public function yylex() @@ -97,41 +209,28 @@ public function yylex1() { - $tokenMap = array( - 1 => 0, - 2 => 0, - 3 => 0, - 4 => 0, - 5 => 0, - 6 => 0, - 7 => 0, - 8 => 0, - ); + if (!isset($this->yy_global_pattern1)) { + $this->yy_global_pattern1 = "/\G(#|;)|\G(\\[)|\G(\\])|\G(=)|\G([ \t\r]+)|\G(\n)|\G([0-9]*[a-zA-Z_]\\w*)|\G([\S\s])/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G(#|;)|\G(\\[)|\G(\\])|\G(=)|\G([ \t\r]+)|\G(\n)|\G([0-9]*[a-zA-Z_]\\w*)|\G([\S\s])/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern1, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state START'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state START'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r1_' . $this->token}($yysubmatches); + $r = $this->{'yy_r1_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -151,8 +250,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -160,52 +258,52 @@ const START = 1; - function yy_r1_1($yy_subpatterns) + function yy_r1_1() { $this->token = Smarty_Internal_Configfileparser::TPC_COMMENTSTART; $this->yypushstate(self::COMMENT); } - function yy_r1_2($yy_subpatterns) + function yy_r1_2() { $this->token = Smarty_Internal_Configfileparser::TPC_OPENB; $this->yypushstate(self::SECTION); } - function yy_r1_3($yy_subpatterns) + function yy_r1_3() { $this->token = Smarty_Internal_Configfileparser::TPC_CLOSEB; } - function yy_r1_4($yy_subpatterns) + function yy_r1_4() { $this->token = Smarty_Internal_Configfileparser::TPC_EQUAL; $this->yypushstate(self::VALUE); } - function yy_r1_5($yy_subpatterns) + function yy_r1_5() { return false; } - function yy_r1_6($yy_subpatterns) + function yy_r1_6() { $this->token = Smarty_Internal_Configfileparser::TPC_NEWLINE; } - function yy_r1_7($yy_subpatterns) + function yy_r1_7() { $this->token = Smarty_Internal_Configfileparser::TPC_ID; } - function yy_r1_8($yy_subpatterns) + function yy_r1_8() { $this->token = Smarty_Internal_Configfileparser::TPC_OTHER; @@ -213,42 +311,28 @@ public function yylex2() { - $tokenMap = array( - 1 => 0, - 2 => 0, - 3 => 0, - 4 => 0, - 5 => 0, - 6 => 0, - 7 => 0, - 8 => 0, - 9 => 0, - ); + if (!isset($this->yy_global_pattern2)) { + $this->yy_global_pattern2 = "/\G([ \t\r]+)|\G(\\d+\\.\\d+(?=[ \t\r]*[\n#;]))|\G(\\d+(?=[ \t\r]*[\n#;]))|\G(\"\"\")|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*'(?=[ \t\r]*[\n#;]))|\G(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"(?=[ \t\r]*[\n#;]))|\G([a-zA-Z]+(?=[ \t\r]*[\n#;]))|\G([^\n]+?(?=[ \t\r]*\n))|\G(\n)/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G([ \t\r]+)|\G(\\d+\\.\\d+(?=[ \t\r]*[\n#;]))|\G(\\d+(?=[ \t\r]*[\n#;]))|\G(\"\"\")|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*'(?=[ \t\r]*[\n#;]))|\G(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"(?=[ \t\r]*[\n#;]))|\G([a-zA-Z]+(?=[ \t\r]*[\n#;]))|\G([^\n]+?(?=[ \t\r]*\n))|\G(\n)/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern2, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state VALUE'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state VALUE'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r2_' . $this->token}($yysubmatches); + $r = $this->{'yy_r2_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -268,8 +352,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -277,51 +360,53 @@ const VALUE = 2; - function yy_r2_1($yy_subpatterns) + function yy_r2_1() { return false; } - function yy_r2_2($yy_subpatterns) + function yy_r2_2() { $this->token = Smarty_Internal_Configfileparser::TPC_FLOAT; $this->yypopstate(); } - function yy_r2_3($yy_subpatterns) + function yy_r2_3() { $this->token = Smarty_Internal_Configfileparser::TPC_INT; $this->yypopstate(); } - function yy_r2_4($yy_subpatterns) + function yy_r2_4() { $this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_QUOTES; $this->yypushstate(self::TRIPPLE); } - function yy_r2_5($yy_subpatterns) + function yy_r2_5() { $this->token = Smarty_Internal_Configfileparser::TPC_SINGLE_QUOTED_STRING; $this->yypopstate(); } - function yy_r2_6($yy_subpatterns) + function yy_r2_6() { $this->token = Smarty_Internal_Configfileparser::TPC_DOUBLE_QUOTED_STRING; $this->yypopstate(); } - function yy_r2_7($yy_subpatterns) + function yy_r2_7() { - if (!$this->smarty->config_booleanize || !in_array(strtolower($this->value), Array("true", "false", "on", "off", "yes", "no"))) { + if (!$this->configBooleanize || !in_array(strtolower($this->value), Array("true", "false", "on", "off", "yes", + "no")) + ) { $this->yypopstate(); $this->yypushstate(self::NAKED_STRING_VALUE); return true; //reprocess in new state @@ -331,14 +416,14 @@ } } - function yy_r2_8($yy_subpatterns) + function yy_r2_8() { $this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING; $this->yypopstate(); } - function yy_r2_9($yy_subpatterns) + function yy_r2_9() { $this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING; @@ -348,34 +433,28 @@ public function yylex3() { - $tokenMap = array( - 1 => 0, - ); + if (!isset($this->yy_global_pattern3)) { + $this->yy_global_pattern3 = "/\G([^\n]+?(?=[ \t\r]*\n))/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G([^\n]+?(?=[ \t\r]*\n))/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern3, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state NAKED_STRING_VALUE'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state NAKED_STRING_VALUE'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r3_' . $this->token}($yysubmatches); + $r = $this->{'yy_r3_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -395,8 +474,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -404,7 +482,7 @@ const NAKED_STRING_VALUE = 3; - function yy_r3_1($yy_subpatterns) + function yy_r3_1() { $this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING; @@ -413,36 +491,28 @@ public function yylex4() { - $tokenMap = array( - 1 => 0, - 2 => 0, - 3 => 0, - ); + if (!isset($this->yy_global_pattern4)) { + $this->yy_global_pattern4 = "/\G([ \t\r]+)|\G([^\n]+?(?=[ \t\r]*\n))|\G(\n)/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G([ \t\r]+)|\G([^\n]+?(?=[ \t\r]*\n))|\G(\n)/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern4, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state COMMENT'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state COMMENT'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r4_' . $this->token}($yysubmatches); + $r = $this->{'yy_r4_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -462,8 +532,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -471,19 +540,19 @@ const COMMENT = 4; - function yy_r4_1($yy_subpatterns) + function yy_r4_1() { return false; } - function yy_r4_2($yy_subpatterns) + function yy_r4_2() { $this->token = Smarty_Internal_Configfileparser::TPC_NAKED_STRING; } - function yy_r4_3($yy_subpatterns) + function yy_r4_3() { $this->token = Smarty_Internal_Configfileparser::TPC_NEWLINE; @@ -492,35 +561,28 @@ public function yylex5() { - $tokenMap = array( - 1 => 0, - 2 => 0, - ); + if (!isset($this->yy_global_pattern5)) { + $this->yy_global_pattern5 = "/\G(\\.)|\G(.*?(?=[\.=[\]\r\n]))/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G(\\.)|\G(.*?(?=[\.=[\]\r\n]))/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern5, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state SECTION'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state SECTION'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r5_' . $this->token}($yysubmatches); + $r = $this->{'yy_r5_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -540,8 +602,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -549,13 +610,13 @@ const SECTION = 5; - function yy_r5_1($yy_subpatterns) + function yy_r5_1() { $this->token = Smarty_Internal_Configfileparser::TPC_DOT; } - function yy_r5_2($yy_subpatterns) + function yy_r5_2() { $this->token = Smarty_Internal_Configfileparser::TPC_SECTION; @@ -564,35 +625,28 @@ public function yylex6() { - $tokenMap = array( - 1 => 0, - 2 => 0, - ); + if (!isset($this->yy_global_pattern6)) { + $this->yy_global_pattern6 = "/\G(\"\"\"(?=[ \t\r]*[\n#;]))|\G([\S\s])/isS"; + } if ($this->counter >= strlen($this->data)) { return false; // end of input } - $yy_global_pattern = "/\G(\"\"\"(?=[ \t\r]*[\n#;]))|\G([\S\s])/iS"; do { - if (preg_match($yy_global_pattern, $this->data, $yymatches, null, $this->counter)) { + if (preg_match($this->yy_global_pattern6, $this->data, $yymatches, null, $this->counter)) { $yysubmatches = $yymatches; - $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns - if (!count($yymatches)) { - throw new Exception('Error: lexing failed because a rule matched' . - ' an empty string. Input "' . substr($this->data, - $this->counter, 5) . '... state TRIPPLE'); + if (strlen($yysubmatches[0]) < 200) { + $yymatches = preg_grep("/(.|\s)+/", $yysubmatches); + } else { + $yymatches = array_filter($yymatches, 'strlen'); } + if (empty($yymatches)) { + throw new Exception('Error: lexing failed because a rule matched' . ' an empty string. Input "' . substr($this->data, $this->counter, 5) . '... state TRIPPLE'); + } next($yymatches); // skip global match $this->token = key($yymatches); // token number - if ($tokenMap[$this->token]) { - // extract sub-patterns for passing to lex function - $yysubmatches = array_slice($yysubmatches, $this->token + 1, - $tokenMap[$this->token]); - } else { - $yysubmatches = array(); - } $this->value = current($yymatches); // token value - $r = $this->{'yy_r6_' . $this->token}($yysubmatches); + $r = $this->{'yy_r6_' . $this->token}(); if ($r === null) { $this->counter += strlen($this->value); $this->line += substr_count($this->value, "\n"); @@ -612,8 +666,7 @@ continue; } } else { - throw new Exception('Unexpected input at line' . $this->line . - ': ' . $this->data[$this->counter]); + throw new Exception('Unexpected input at line' . $this->line . ': ' . $this->data[$this->counter]); } break; } while (true); @@ -621,7 +674,7 @@ const TRIPPLE = 6; - function yy_r6_1($yy_subpatterns) + function yy_r6_1() { $this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_QUOTES_END; @@ -629,7 +682,7 @@ $this->yypushstate(self::START); } - function yy_r6_2($yy_subpatterns) + function yy_r6_2() { $to = strlen($this->data); @@ -642,5 +695,5 @@ $this->value = substr($this->data, $this->counter, $to - $this->counter); $this->token = Smarty_Internal_Configfileparser::TPC_TRIPPLE_TEXT; } -} +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_adddefaultmodifiers.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_adddefaultmodifiers.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_adddefaultmodifiers.php (revision Shelved version) @@ -0,0 +1,42 @@ +smarty) ? $obj->smarty : $obj; + if (is_array($modifiers)) { + $this->default_modifiers = array_merge($smarty->default_modifiers, $modifiers); + } else { + $smarty->default_modifiers[] = $modifiers; + } + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_template.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_template.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_template.php (revision Shelved version) @@ -13,120 +13,90 @@ * * @package Smarty * @subpackage Template - * @property Smarty_Template_Source $source + * + * @property Smarty_Template_Source|Smarty_Template_Config $source - * @property Smarty_Template_Compiled $compiled + * @property Smarty_Template_Compiled $compiled - * @property Smarty_Template_Cached $cached + * @property Smarty_Template_Cached $cached + * @method bool mustCompile() */ class Smarty_Internal_Template extends Smarty_Internal_TemplateBase { /** - * cache_id + * This object type (Smarty = 1, template = 2, data = 4) * - * @var string + * @var int */ - public $cache_id = null; + public $_objType = 2; + /** - * $compile_id - * @var string - */ - public $compile_id = null; - /** - * caching enabled + * Global smarty instance * - * @var boolean + * @var Smarty */ - public $caching = null; + public $smarty = null; + /** - * cache lifetime in seconds + * Source instance * - * @var integer + * @var Smarty_Template_Source|Smarty_Template_Config */ - public $cache_lifetime = null; + public $source = null; + /** * Template resource * * @var string */ public $template_resource = null; + /** * flag if compiled template is invalid and must be (re)compiled * * @var bool */ public $mustCompile = null; + /** - * flag if template does contain nocache code sections + * Template Id * - * @var bool + * @var null|string */ - public $has_nocache_code = false; + public $templateId = null; + /** - * special compiled and cached template properties + * Known template functions * * @var array */ - public $properties = array('file_dependency' => array(), - 'nocache_hash' => '', - 'function' => array()); + public $tpl_function = array(); + /** - * required plugins + * Scope in which template is rendered * - * @var array + * @var int */ - public $required_plugins = array('compiled' => array(), 'nocache' => array()); - /** - * Global smarty instance - * - * @var Smarty - */ - public $smarty = null; - /** - * blocks for template inheritance - * - * @var array - */ - public $block_data = array(); - /** - * variable filters - * - * @var array - */ - public $variable_filters = array(); - /** - * optional log of tag/attributes - * - * @var array - */ - public $used_tags = array(); - /** - * internal flag to allow relative path in child template blocks - * - * @var bool - */ - public $allow_relative_path = false; - /** - * internal capture runtime stack - * - * @var array - */ - public $_capture_stack = array(0 => array()); + public $scope = 0; /** * Create template data object * Some of the global Smarty settings copied to template scope - * It load the required template resources and cacher plugins + * It load the required template resources and caching plugins * - * @param string $template_resource template resource string + * @param string $template_resource template resource string - * @param Smarty $smarty Smarty instance + * @param Smarty $smarty Smarty instance - * @param Smarty_Internal_Template $_parent back pointer to parent object with variables or null + * @param \Smarty_Internal_Template|\Smarty|\Smarty_Internal_Data $_parent back pointer to parent object + * with variables or null - * @param mixed $_cache_id cache id or null + * @param mixed $_cache_id cache id or null - * @param mixed $_compile_id compile id or null + * @param mixed $_compile_id compile id or null - * @param bool $_caching use caching? + * @param bool $_caching use caching? - * @param int $_cache_lifetime cache life-time in seconds + * @param int $_cache_lifetime cache life-time in seconds + * + * @throws \SmartyException */ - public function __construct($template_resource, $smarty, $_parent = null, $_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null) + public function __construct($template_resource, Smarty $smarty, Smarty_Internal_Data $_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; @@ -138,502 +108,206 @@ $this->parent = $_parent; // Template resource $this->template_resource = $template_resource; - // copy block data of template inheritance - if ($this->parent instanceof Smarty_Internal_Template) { - $this->block_data = $this->parent->block_data; + $this->source = Smarty_Template_Source::load($this); + parent::__construct(); - } + } - } /** - * 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 + * 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 null: subtemplate + * + * @throws Exception * @throws SmartyException - * @return boolean true if the template must be compiled + * @return string rendered template output */ - public function mustCompile() + public function render($no_output_filter = true, $display = null) { + $parentIsTpl = isset($this->parent) && $this->parent->_objType == 2; + if ($this->smarty->debugging) { + $this->smarty->_debug->start_template($this, $display); + } + // checks if template exists if (!$this->source->exists) { - if ($this->parent instanceof Smarty_Internal_Template) { - $parent_resource = " in '$this->parent->template_resource}'"; + if ($parentIsTpl) { + $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}"); } - if ($this->mustCompile === null) { - $this->mustCompile = (!$this->source->uncompiled && ($this->smarty->force_compile || $this->source->recompiled || $this->compiled->timestamp === false || - ($this->smarty->compile_check && $this->compiled->timestamp < $this->source->timestamp))); + // disable caching for evaluated code + if ($this->source->handler->recompiled) { + $this->caching = false; } - - return $this->mustCompile; + // read from cache or render + $isCacheTpl = + $this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED; + if ($isCacheTpl) { + if (!isset($this->cached)) { + $this->loadCached(); - } + } + $this->cached->render($this, $no_output_filter); + } elseif ($this->source->handler->uncompiled) { + $this->source->render($this); + } else { + if (!isset($this->compiled)) { + $this->loadCompiled(); + } + $this->compiled->render($this); + } - /** - * Compiles the template - * If the template is not evaluated the compiled template is saved on disk - */ - public function compileTemplateSource() - { - if (!$this->source->recompiled) { - $this->properties['file_dependency'] = array(); - if ($this->source->components) { - // for the extends resource the compiler will fill it - // uses real resource for file dependency - // $source = end($this->source->components); - // $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type); + // display or fetch + if ($display) { + if ($this->caching && $this->smarty->cache_modified_check) { + $this->smarty->ext->_cachemodify->cacheModifiedCheck($this->cached, $this, + isset($content) ? $content : ob_get_clean()); } else { - $this->properties['file_dependency'][$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $this->source->type); + if ((!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) && + !$no_output_filter && (isset($this->smarty->autoload_filters['output']) || + isset($this->smarty->registered_filters['output'])) + ) { + echo $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this); + } else { + ob_end_flush(); + flush(); - } - } + } + } - // compile locking - if ($this->smarty->compile_locking && !$this->source->recompiled) { - if ($saved_timestamp = $this->compiled->timestamp) { - touch($this->compiled->filepath); + if ($this->smarty->debugging) { + $this->smarty->_debug->end_template($this); + // debug output + $this->smarty->_debug->display_debug($this, true); } + return ''; + } else { + if ($this->smarty->debugging) { + $this->smarty->_debug->end_template($this); + if ($this->smarty->debugging === 2 && $display === false) { + $this->smarty->_debug->display_debug($this, true); - } + } - // 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); + if ($parentIsTpl) { + if (!empty($this->tpl_function)) { + $this->parent->tpl_function = array_merge($this->parent->tpl_function, $this->tpl_function); - } + } - throw $e; + foreach ($this->compiled->required_plugins as $code => $tmp1) { + foreach ($tmp1 as $name => $tmp) { + foreach ($tmp as $type => $data) { + $this->parent->compiled->required_plugins[$code][$name][$type] = $data; - } + } - // 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); - } + } - - /** - * Writes the cached template output - * - * @param string $content - * - * @return bool - */ - 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; + if (!$no_output_filter && + (!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) && + (isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output'])) + ) { + return $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this); - } + } - $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); - /** @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $this; - eval("?>" . $content); - $this->cached->valid = true; - $this->cached->processed = true; - - return $this->cached->write($this, $content); + // return cache content + return null; - } + } + } /** - * Template code runtime function to get subtemplate content - * - * @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 - * - * @returns string template content + * Compiles the template + * If the template is not evaluated the compiled template is saved on disk */ - public function getSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope) + public function compileTemplateSource() { - // 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; + return $this->compiled->compileTemplateSource($this); - } + } - if (isset($_templateId[150])) { - $_templateId = sha1($_templateId); - } - if (isset($this->smarty->template_objects[$_templateId])) { - // clone cached template object because of possible recursive call - $tpl = clone $this->smarty->template_objects[$_templateId]; - $tpl->parent = $this; - $tpl->caching = $caching; - $tpl->cache_lifetime = $cache_lifetime; - } else { - $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); - } - // 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->fetch(null, null, null, null, false, false, true); - } - /** - * Template code runtime function to set up an inline subtemplate + * Writes the content to cache resource * - * @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 * - * @returns string template content + * @return bool */ - public function setupInlineSubTemplate($template, $cache_id, $compile_id, $caching, $cache_lifetime, $data, $parent_scope, $hash) + public function writeCachedContent($content) { - $tpl = new $this->smarty->template_class($template, $this->smarty, $this, $cache_id, $compile_id, $caching, $cache_lifetime); - $tpl->properties['nocache_hash'] = $hash; - // 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; + return $this->smarty->ext->_updateCache->writeCachedContent($this->cached, $this, $content); - } + } - $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; - } - /** - * Create code frame for compiled and cached templates + * Get unique template id * - * @param string $content optional template content - * @param bool $cache flag for cache file - * * @return string */ - public function createTemplateCodeFrame($content = '', $cache = false) + public function _getTemplateId() { - $plugins_string = ''; - // include code for plugins - if (!$cache) { - if (!empty($this->required_plugins['compiled'])) { - $plugins_string = 'required_plugins['compiled'] as $tmp) { - foreach ($tmp as $data) { - $file = addslashes($data['file']); - if (is_Array($data['function'])) { - $plugins_string .= "if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) include '{$file}';\n"; - } else { - $plugins_string .= "if (!is_callable('{$data['function']}')) include '{$file}';\n"; + return isset($this->templateId) ? $this->templateId : $this->templateId = + $this->smarty->_getTemplateId($this->template_resource, $this->cache_id, $this->compile_id); - } + } - } - } - $plugins_string .= '?>'; - } - if (!empty($this->required_plugins['nocache'])) { - $this->has_nocache_code = true; - $plugins_string .= "properties['nocache_hash']}%%*/smarty; "; - foreach ($this->required_plugins['nocache'] as $tmp) { - foreach ($tmp as $data) { - $file = addslashes($data['file']); - if (is_Array($data['function'])) { - $plugins_string .= addslashes("if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) include '{$file}';\n"); - } else { - $plugins_string .= addslashes("if (!is_callable('{$data['function']}')) include '{$file}';\n"); - } - } - } - $plugins_string .= "?>/*/%%SmartyNocache:{$this->properties['nocache_hash']}%%*/';?>\n"; - } - } - // build property code - $this->properties['has_nocache_code'] = $this->has_nocache_code; - $output = ''; - if (!$this->source->recompiled) { - $output = "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['version'] = Smarty::SMARTY_VERSION; - if (!isset($this->properties['unifunc'])) { - $this->properties['unifunc'] = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); - } - 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 .= $plugins_string; - $output .= $content; - if (!$this->source->recompiled) { - $output .= "\n"; - } - return $output; - } - /** - * This function is executed automatically when a compiled or cached template file is included - * - Decode saved properties from compiled template and cache files - * - Check if compiled or cache file is valid - * - * @param array $properties special template properties - * @param bool $cache flag if called from cache file - * - * @return bool flag if compiled or cache file is valid + * runtime error not matching capture tags */ - public function decodeProperties($properties, $cache = false) + public function capture_error() { - $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']; + throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\""); - } + } - 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 - $is_valid = true; - if ($this->properties['version'] != Smarty::SMARTY_VERSION) { - $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) { - 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 - $mtime = $this->source->timestamp; - } else { - // file and php types can be checked without loading the respective resource handlers - $mtime = @filemtime($_file_to_check[0]); - } - } elseif ($_file_to_check[2] == 'string') { - continue; - } else { - $source = Smarty_Resource::source(null, $this->smarty, $_file_to_check[0]); - $mtime = $source->timestamp; - } - if (!$mtime || $mtime > $_file_to_check[1]) { - $is_valid = false; - break; - } - } - } - 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'])) - ) { - $is_valid = false; - } - $this->cached->valid = $is_valid; - } else { - $this->mustCompile = !$is_valid; - } - // store data in reusable Smarty_Template_Compiled - if (!$cache) { - $this->compiled->_properties = $properties; - } - return $is_valid; - } - /** - * Template code runtime function to create a local Smarty variable for array assignments + * Load compiled object * - * @param string $tpl_var tempate variable name - * @param bool $nocache cache mode of variable - * @param int $scope scope of variable */ - public function createLocalArrayVariable($tpl_var, $nocache = false, $scope = Smarty::SCOPE_LOCAL) + public function loadCompiled() { - if (!isset($this->tpl_vars[$tpl_var])) { - $this->tpl_vars[$tpl_var] = new Smarty_variable(array(), $nocache, $scope); - } else { - $this->tpl_vars[$tpl_var] = clone $this->tpl_vars[$tpl_var]; - if ($scope != Smarty::SCOPE_LOCAL) { - $this->tpl_vars[$tpl_var]->scope = $scope; + if (!isset($this->compiled)) { + $this->compiled = Smarty_Template_Compiled::load($this); - } + } - if (!(is_array($this->tpl_vars[$tpl_var]->value) || $this->tpl_vars[$tpl_var]->value instanceof ArrayAccess)) { - settype($this->tpl_vars[$tpl_var]->value, 'array'); - } + } - } - } /** - * Template code runtime function to get pointer to template variable array of requested scope + * Load cached object * - * @param int $scope requested variable scope - * - * @return array array of template variables */ - public function &getScope($scope) + public function loadCached() { - if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { - return $this->parent->tpl_vars; - } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { - $ptr = $this->parent; - while (!empty($ptr->parent)) { - $ptr = $ptr->parent; + if (!isset($this->cached)) { + $this->cached = Smarty_Template_Cached::load($this); - } + } - - return $ptr->tpl_vars; - } elseif ($scope == Smarty::SCOPE_GLOBAL) { - return Smarty::$global_tpl_vars; - } + } - $null = null; - return $null; - } - /** - * Get parent or root of template parent chain + * Load compiler object * - * @param int $scope pqrent or root scope - * - * @return mixed object + * @throws \SmartyException */ - public function getScopePointer($scope) + public function loadCompiler() { - if ($scope == Smarty::SCOPE_PARENT && !empty($this->parent)) { - return $this->parent; - } elseif ($scope == Smarty::SCOPE_ROOT && !empty($this->parent)) { - $ptr = $this->parent; - while (!empty($ptr->parent)) { - $ptr = $ptr->parent; + if (!class_exists($this->source->handler->compiler_class)) { + $this->smarty->loadPlugin($this->source->handler->compiler_class); - } + } - - return $ptr; + $this->compiler = new $this->source->handler->compiler_class($this->source->handler->template_lexer_class, + $this->source->handler->template_parser_class, + $this->smarty); - } + } - return null; - } - /** - * [util function] counts an array, arrayaccess/traversable or PDOStatement object + * Handle unknown class methods * - * @param mixed $value + * @param string $name unknown method-name + * @param array $args argument array * - * @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0 for empty elements + * @return mixed + * @throws SmartyException */ - public function _count($value) + public function __call($name, $args) { - if (is_array($value) === true || $value instanceof Countable) { - return count($value); - } elseif ($value instanceof IteratorAggregate) { - // Note: getIterator() returns a Traversable, not an Iterator - // thus rewind() and valid() methods may not be present - return iterator_count($value->getIterator()); - } elseif ($value instanceof Iterator) { - return iterator_count($value); - } elseif ($value instanceof PDOStatement) { - return $value->rowCount(); - } elseif ($value instanceof Traversable) { - return iterator_count($value); - } elseif ($value instanceof ArrayAccess) { - if ($value->offsetExists(0)) { - return 1; + // method of Smarty object? + if (method_exists($this->smarty, $name)) { + return call_user_func_array(array($this->smarty, $name), $args); - } + } - } elseif (is_object($value)) { - return count($value); + // parent + return parent::__call($name, $args); - } + } - return 0; - } - /** - * runtime error not matching capture tags - - */ - public function capture_error() - { - throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\""); - } - - /** - * Empty cache for this template - * - * @param integer $exp_time expiration time - * - * @return integer number of cache files deleted - */ - public function clearCache($exp_time = null) - { - Smarty_CacheResource::invalidLoadedCache($this->smarty); - - return $this->cached->handler->clear($this->smarty, $this->template_name, $this->cache_id, $this->compile_id, $exp_time); - } - - /** * set Smarty property in template context * * @param string $property_name property name @@ -644,23 +318,18 @@ public function __set($property_name, $value) { switch ($property_name) { - case 'source': case 'compiled': case 'cached': case 'compiler': $this->$property_name = $value; - return; - - // FIXME: routing of template -> smarty attributes default: + // Smarty property ? if (property_exists($this->smarty, $property_name)) { $this->smarty->$property_name = $value; - return; } } - throw new SmartyException("invalid template property '$property_name'."); } @@ -669,65 +338,34 @@ * * @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_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->loadCompiled(); 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->loadCached(); return $this->cached; case 'compiler': - $this->smarty->loadPlugin($this->source->compiler_class); - $this->compiler = new $this->source->compiler_class($this->source->template_lexer_class, $this->source->template_parser_class, $this->smarty); - + $this->loadCompiler(); return $this->compiler; - - // FIXME: routing of template -> smarty attributes default: + // Smarty property ? if (property_exists($this->smarty, $property_name)) { return $this->smarty->$property_name; } } - throw new SmartyException("template property '$property_name' does not exist."); } /** * Template data object destructor - */ public function __destruct() { Index: src/includes/classes/Smarty/plugins/modifier.date_format.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/modifier.date_format.php (revision Local version) +++ src/includes/classes/Smarty/plugins/modifier.date_format.php (revision Shelved version) @@ -33,7 +33,7 @@ $format = Smarty::$_DATE_FORMAT; } /** - * Include the {@link shared.make_timestamp.php} plugin + * require_once the {@link shared.make_timestamp.php} plugin */ require_once(SMARTY_PLUGINS_DIR . 'shared.make_timestamp.php'); if ($string != '' && $string != '0000-00-00' && $string != '0000-00-00 00:00:00') { Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_include.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_include.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_include.php (revision Shelved version) @@ -20,6 +20,7 @@ * caching mode to create nocache code but no cache file */ const CACHING_NOCACHE_CODE = 9999; + /** * Attribute definition: Overwrites base class. * @@ -27,6 +28,7 @@ * @see Smarty_Internal_CompileBase */ public $required_attributes = array('file'); + /** * Attribute definition: Overwrites base class. * @@ -34,13 +36,15 @@ * @see Smarty_Internal_CompileBase */ public $shorttag_order = array('file'); + /** * Attribute definition: Overwrites base class. * * @var array * @see Smarty_Internal_CompileBase */ - public $option_flags = array('nocache', 'inline', 'caching'); + public $option_flags = array('nocache', 'inline', 'caching', 'bubble_up'); + /** * Attribute definition: Overwrites base class. * @@ -50,216 +54,313 @@ public $optional_attributes = array('_any'); /** + * Valid scope names + * + * @var array + */ + public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true, + 'smarty' => true, 'tpl_root' => true); + + /** * Compiles code for the {include} tag * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param Smarty_Internal_SmartyTemplateCompiler $compiler compiler object - * @param array $parameter array with compilation parameter + * @param array $parameter array with compilation parameter * + * @throws SmartyCompilerException * @return string compiled code */ - public function compile($args, $compiler, $parameter) + public function compile($args, Smarty_Internal_SmartyTemplateCompiler $compiler, $parameter) { // check and get attributes $_attr = $this->getAttributes($compiler, $args); - // save possible attributes - $include_file = $_attr['file']; + $hashResourceName = $fullResourceName = $source_resource = $_attr['file']; + $variable_template = false; + $cache_tpl = false; + // parse resource_name + if (preg_match('/^([\'"])(([A-Za-z0-9_\-]{2,})[:])?(([^$()]+)|(.+))\1$/', $source_resource, $match)) { + $type = !empty($match[3]) ? $match[3] : $compiler->template->smarty->default_resource_type; + $name = !empty($match[5]) ? $match[5] : $match[6]; + $handler = Smarty_Resource::load($compiler->smarty, $type); + if ($handler->recompiled || $handler->uncompiled) { + $variable_template = true; + } + if (!$variable_template) { + if ($type != 'string') { + $fullResourceName = "{$type}:{$name}"; + $compiled = $compiler->parent_compiler->template->compiled; + if (isset($compiled->includes[$fullResourceName])) { + $compiled->includes[$fullResourceName] ++; + $cache_tpl = true; + } else { + $compiled->includes[$fullResourceName] = 1; + } + $fullResourceName = '"' . $fullResourceName . '"'; + } + } + if (empty($match[5])) { + $variable_template = true; + } + } else { + $variable_template = true; + } + if (isset($_attr['assign'])) { // output will be stored in a smarty variable instead of being displayed $_assign = $_attr['assign']; } - $_parent_scope = Smarty::SCOPE_LOCAL; + // scope setup + $_scope = Smarty::SCOPE_LOCAL; if (isset($_attr['scope'])) { $_attr['scope'] = trim($_attr['scope'], "'\""); + if (!isset($this->valid_scopes[$_attr['scope']])) { + $compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, true); + } + if ($_attr['scope'] != 'local') { - if ($_attr['scope'] == 'parent') { + if ($_attr['scope'] == 'parent') { - $_parent_scope = Smarty::SCOPE_PARENT; + $_scope = Smarty::SCOPE_PARENT; - } elseif ($_attr['scope'] == 'root') { + } elseif ($_attr['scope'] == 'root') { - $_parent_scope = Smarty::SCOPE_ROOT; + $_scope = Smarty::SCOPE_ROOT; - } elseif ($_attr['scope'] == 'global') { + } elseif ($_attr['scope'] == 'global') { - $_parent_scope = Smarty::SCOPE_GLOBAL; + $_scope = Smarty::SCOPE_GLOBAL; + } elseif ($_attr['scope'] == 'smarty') { + $_scope = Smarty::SCOPE_SMARTY; + } elseif ($_attr['scope'] == 'tpl_root') { + $_scope = Smarty::SCOPE_TPL_ROOT; - } + } + if ($_attr['bubble_up'] === true) { + $_scope = $_scope + Smarty::SCOPE_BUBBLE_UP; - } + } - - $_caching = Smarty::CACHING_OFF; - - // flag if included template code should be merged into caller - $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || ($compiler->inheritance && $compiler->smarty->inheritance_merge_compiled_includes) || $_attr['inline'] === true) && !$compiler->template->source->recompiled; - - // set default when in nocache mode - // if ($compiler->template->caching && ($compiler->nocache || $compiler->tag_nocache || $compiler->forceNocache == 2)) { - if ($compiler->template->caching && ((!$compiler->inheritance && !$compiler->nocache && !$compiler->tag_nocache) || ($compiler->inheritance && ($compiler->nocache || $compiler->tag_nocache)))) { - $_caching = self::CACHING_NOCACHE_CODE; - } + } - /* - * if the {include} tag provides individual parameter for caching - * it will not be included into the common cache file and treated like - * a nocache section - */ - if (isset($_attr['cache_lifetime'])) { - $_cache_lifetime = $_attr['cache_lifetime']; - $compiler->tag_nocache = true; - $_caching = Smarty::CACHING_LIFETIME_CURRENT; - } else { - $_cache_lifetime = 'null'; } - if (isset($_attr['cache_id'])) { - $_cache_id = $_attr['cache_id']; - $compiler->tag_nocache = true; - $_caching = Smarty::CACHING_LIFETIME_CURRENT; + + // set flag to cache subtemplate object when called within loop or template name is variable. + if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) { + $_cache_tpl = 'true'; } else { - $_cache_id = '$_smarty_tpl->cache_id'; + $_cache_tpl = 'false'; } - if (isset($_attr['compile_id'])) { - $_compile_id = $_attr['compile_id']; - } else { - $_compile_id = '$_smarty_tpl->compile_id'; - } - if ($_attr['caching'] === true) { - $_caching = Smarty::CACHING_LIFETIME_CURRENT; - } + // assume caching is off + $_caching = Smarty::CACHING_OFF; + if ($_attr['nocache'] === true) { $compiler->tag_nocache = true; - if ($merge_compiled_includes) { + } + + $call_nocache = $compiler->tag_nocache || $compiler->nocache; + + // caching was on and {include} is not in nocache mode + if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) { - $_caching = self::CACHING_NOCACHE_CODE; + $_caching = self::CACHING_NOCACHE_CODE; - } else { - $_caching = Smarty::CACHING_OFF; - } + } - } - $has_compiled_template = false; + // flag if included template code should be merged into caller + $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr['inline'] === true) && + !$compiler->template->source->handler->recompiled; + if ($merge_compiled_includes && $_attr['inline'] !== true) { // variable template name ? - if ($compiler->has_variable_string || !((substr_count($include_file, '"') == 2 || substr_count($include_file, "'") == 2)) - || substr_count($include_file, '(') != 0 || substr_count($include_file, '$_smarty_tpl->') != 0 - ) { + if ($variable_template) { $merge_compiled_includes = false; - if ($compiler->inheritance && $compiler->smarty->inheritance_merge_compiled_includes) { - $compiler->trigger_template_error(' variable template file names not allow within {block} tags'); + if ($compiler->template->caching) { + // must use individual cache file + //$_attr['caching'] = 1; } } // variable compile_id? if (isset($_attr['compile_id'])) { - if (!((substr_count($_attr['compile_id'], '"') == 2 || substr_count($_attr['compile_id'], "'") == 2)) - || substr_count($_attr['compile_id'], '(') != 0 || substr_count($_attr['compile_id'], '$_smarty_tpl->') != 0 + if (!((substr_count($_attr['compile_id'], '"') == 2 || substr_count($_attr['compile_id'], "'") == 2 || + is_numeric($_attr['compile_id']))) || substr_count($_attr['compile_id'], '(') != 0 || + substr_count($_attr['compile_id'], '$_smarty_tpl->') != 0 ) { $merge_compiled_includes = false; - if ($compiler->inheritance && $compiler->smarty->inheritance_merge_compiled_includes) { - $compiler->trigger_template_error(' variable compile_id not allow within {block} tags'); + if ($compiler->template->caching) { + // must use individual cache file + //$_attr['caching'] = 1; } } } } - if ($merge_compiled_includes) { - if ($compiler->template->caching && ($compiler->tag_nocache || $compiler->nocache) && $_caching != self::CACHING_NOCACHE_CODE) { - $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 the {include} tag provides individual parameter for caching or compile_id + * the subtemplate must not be included into the common cache file and is treated like + * a call in nocache mode. + * + */ + if ($_attr['nocache'] !== true && $_attr['caching']) { + $_caching = $_new_caching = (int) $_attr['caching']; + $call_nocache = true; + } else { + $_new_caching = Smarty::CACHING_LIFETIME_CURRENT; - } + } + if (isset($_attr['cache_lifetime'])) { + $_cache_lifetime = $_attr['cache_lifetime']; + $call_nocache = true; + $_caching = $_new_caching; + } else { + $_cache_lifetime = '$_smarty_tpl->cache_lifetime'; - } + } + if (isset($_attr['cache_id'])) { + $_cache_id = $_attr['cache_id']; + $call_nocache = true; + $_caching = $_new_caching; + } else { + $_cache_id = '$_smarty_tpl->cache_id'; } - if ($merge_compiled_includes) { - // we must observe different compile_id - $uid = sha1($_compile_id); - $tpl_name = null; - $nocache = false; - /** @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $compiler->template; - eval("\$tpl_name = $include_file;"); - if (!isset($compiler->smarty->merged_templates_func[$tpl_name][$uid])) { - $tpl = new $compiler->smarty->template_class ($tpl_name, $compiler->smarty, $compiler->template, $compiler->template->cache_id, $compiler->template->compile_id); - // 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->template->caching && $_caching == self::CACHING_NOCACHE_CODE) { - // all code must be nocache - $nocache = true; + if (isset($_attr['compile_id'])) { + $_compile_id = $_attr['compile_id']; + } else { + $_compile_id = '$_smarty_tpl->compile_id'; - } + } - if ($compiler->inheritance) { - $tpl->compiler->inheritance = true; - } - // make sure whole chain gets compiled - $tpl->mustCompile = true; - if (!($tpl->source->uncompiled) && $tpl->source->exists) { - // get compiled code - $compiled_code = $tpl->compiler->compileTemplate($tpl, $nocache); - // release compiler object to free memory - unset($tpl->compiler); - // merge compiled code for {function} tags - $compiler->template->properties['function'] = array_merge($compiler->template->properties['function'], $tpl->properties['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']); - // remove header code - $compiled_code = preg_replace("/(<\?php \/\*%%SmartyHeaderCode:{$tpl->properties['nocache_hash']}%%\*\/(.+?)\/\*\/%%SmartyHeaderCode%%\*\/\?>\n)/s", '', $compiled_code); - if ($tpl->has_nocache_code) { - // replace nocache_hash - $compiled_code = str_replace("{$tpl->properties['nocache_hash']}", $compiler->template->properties['nocache_hash'], $compiled_code); - $compiler->template->has_nocache_code = true; + // if subtemplate will be called in nocache mode do not merge + if ($compiler->template->caching && $call_nocache) { + $merge_compiled_includes = false; - } + } - $compiler->merged_templates[$tpl->properties['unifunc']] = $compiled_code; - $has_compiled_template = true; - unset ($tpl); - } + + $has_compiled_template = false; + if ($merge_compiled_includes) { + $c_id = isset($_attr['compile_id']) ? $_attr['compile_id'] : $compiler->template->compile_id; + // we must observe different compile_id and caching + $t_hash = sha1($c_id . ($_caching ? '--caching' : '--nocaching')); + if (!isset($compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash])) { + $has_compiled_template = + $this->compileInlineTemplate($compiler, $fullResourceName, $_caching, $hashResourceName, $t_hash, + $c_id); } else { $has_compiled_template = true; } } // delete {include} standard attributes - unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline']); + unset($_attr['file'], $_attr['assign'], $_attr['cache_id'], $_attr['compile_id'], $_attr['cache_lifetime'], $_attr['nocache'], $_attr['caching'], $_attr['scope'], $_attr['inline'], $_attr['bubble_up']); // remaining attributes must be assigned as smarty variable + $_vars_nc = ''; if (!empty($_attr)) { - if ($_parent_scope == Smarty::SCOPE_LOCAL) { + if ($_scope == Smarty::SCOPE_LOCAL) { + $_pairs = array(); // create variables - $nccode = ''; foreach ($_attr as $key => $value) { $_pairs[] = "'$key'=>$value"; - $nccode .= "\$_smarty_tpl->tpl_vars['$key'] = new Smarty_variable($value);\n"; + $_vars_nc .= "\$_smarty_tpl->tpl_vars['$key'] = new Smarty_Variable($value);\n"; } $_vars = 'array(' . join(',', $_pairs) . ')'; } else { - $compiler->trigger_template_error('variable passing not allowed in parent/global scope', $compiler->lex->taglineno); + $compiler->trigger_template_error('variable passing not allowed in parent/global scope', null, true); } } else { $_vars = 'array()'; } - 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']; - $_output = "caching) { - $compiler->suppressNocacheProcessing = false; - $_output .= substr($compiler->processNocacheCode('\n", true), 6, -3); - $compiler->suppressNocacheProcessing = true; + $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache && + $_compile_id != '$_smarty_tpl->compile_id'; + if ($has_compiled_template && !$call_nocache) { + $_output = "makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n"); } - $_output .= " \$_smarty_tpl = \$_smarty_tpl->setupInlineSubTemplate($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope, '$_hash');\n"; + if (!empty($_vars_nc) && $_caching == 9999 && $compiler->template->caching) { + //$compiler->suppressNocacheProcessing = false; + $_output .= substr($compiler->processNocacheCode('\n", true), 6, - 3); + //$compiler->suppressNocacheProcessing = true; + } if (isset($_assign)) { - $_output .= 'ob_start(); '; + $_output .= "ob_start();\n"; } - $_output .= $compiler->smarty->merged_templates_func[$tpl_name][$uid]['func'] . "(\$_smarty_tpl);\n"; - $_output .= "\$_smarty_tpl = array_pop(\$_tpl_stack); "; + $_output .= "\$_smarty_tpl->smarty->ext->_subtemplate->render(\$_smarty_tpl, {$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['func']}');\n"; if (isset($_assign)) { - $_output .= " \$_smarty_tpl->tpl_vars[$_assign] = new Smarty_variable(ob_get_clean());"; + $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n"; } - $_output .= "\n/* End of included template \"" . $tpl_name . "\" */?>"; + if ($update_compile_id) { + $_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"); + } + $_output .= "?>\n"; return $_output; } + if ($call_nocache) { + $compiler->tag_nocache = true; + } + $_output = "compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n"; + } // was there an assign attribute if (isset($_assign)) { - $_output = "tpl_vars[$_assign] = new Smarty_variable(\$_smarty_tpl->getSubTemplate ($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope));?>\n";; - } else { - $_output = "getSubTemplate ($include_file, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_parent_scope);?>\n"; + $_output .= "ob_start();\n"; } - + $_output .= "\$_smarty_tpl->smarty->ext->_subtemplate->render(\$_smarty_tpl, {$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_scope, {$_cache_tpl});\n"; + if (isset($_assign)) { + $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n"; + } + if ($update_compile_id) { + $_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n"; + } + $_output .= "?>\n"; return $_output; + } + + /** + * Compile inline sub template + * + * @param \Smarty_Internal_SmartyTemplateCompiler $compiler + * @param $fullResourceName + * @param $_caching + * @param $hashResourceName + * @param $t_hash + * @param $c_id + * + * @return bool + */ + public function compileInlineTemplate(Smarty_Internal_SmartyTemplateCompiler $compiler, $fullResourceName, + $_caching, $hashResourceName, $t_hash, $c_id) + { + $compiler->smarty->allow_ambiguous_resources = true; + /* @var Smarty_Internal_Template $tpl */ + $tpl = + new $compiler->smarty->template_class (trim($fullResourceName, '"\''), $compiler->smarty, $compiler->template, + $compiler->template->cache_id, $c_id, $_caching); + if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) { + $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['uid'] = $tpl->source->uid; + if (isset($compiler->template->_inheritance)) { + $tpl->_inheritance = clone $compiler->template->_inheritance; + } + $tpl->compiled = new Smarty_Template_Compiled(); + $tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash; + $tpl->loadCompiler(); + // save unique function name + $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['func'] = + $tpl->compiled->unifunc = 'content_' . str_replace(array('.', ','), '_', uniqid('', true)); + // make sure whole chain gets compiled + $tpl->mustCompile = true; + $compiler->parent_compiler->mergedSubTemplatesData[$hashResourceName][$t_hash]['nocache_hash'] = + $tpl->compiled->nocache_hash; + // get compiled code + $compiled_code = "source->type}:{$tpl->source->name}\" =============================*/\n"; + $compiled_code .= "function {$tpl->compiled->unifunc} (\$_smarty_tpl) {\n"; + $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler); + $compiled_code .= "\n"; + $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode); + $compiled_code .= "source->type}:{$tpl->source->name}\" =============================*/\n"; + $compiled_code .= "?>"; + unset($tpl->compiler); + if ($tpl->compiled->has_nocache_code) { + // replace nocache_hash + $compiled_code = + str_replace("{$tpl->compiled->nocache_hash}", $compiler->template->compiled->nocache_hash, + $compiled_code); + $compiler->template->compiled->has_nocache_code = true; + } + $compiler->parent_compiler->mergedSubTemplatesCode[$tpl->compiled->unifunc] = $compiled_code; + return true; + } else { + return false; + } } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_appendbyref.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_appendbyref.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_appendbyref.php (revision Shelved version) @@ -0,0 +1,50 @@ +tpl_vars[$tpl_var])) { + $data->tpl_vars[$tpl_var] = new Smarty_Variable(); + } + if (!is_array($data->tpl_vars[$tpl_var]->value)) { + settype($data->tpl_vars[$tpl_var]->value, 'array'); + } + if ($merge && is_array($value)) { + foreach ($value as $_key => $_val) { + $data->tpl_vars[$tpl_var]->value[$_key] = &$value[$_key]; + } + } else { + $data->tpl_vars[$tpl_var]->value[] = &$value; + } + if ($data->_objType == 2 && $data->scope) { + $data->ext->_updateScope->updateScope($data, $tpl_var); + } + } + return $data; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/plugins/function.html_options.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/function.html_options.php (revision Local version) +++ src/includes/classes/Smarty/plugins/function.html_options.php (revision Shelved version) @@ -193,4 +193,4 @@ $optgroup_html .= "\n"; return $optgroup_html; -} \ No newline at end of file +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_php.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_php.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_php.php (revision Shelved version) @@ -0,0 +1,209 @@ +getAttributes($compiler, $args); + $compiler->has_code = false; + if ($_attr['type'] == 'xml') { + $compiler->tag_nocache = true; + $save = $compiler->template->compiled->has_nocache_code; + $output = addcslashes($_attr['code'], "'\\"); + $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $compiler->processNocacheCode("", $compiler, true))); + $compiler->template->compiled->has_nocache_code = $save; + return ''; + } + if ($_attr['type'] != 'tag') { + if ($compiler->php_handling == Smarty::PHP_REMOVE) { + return ''; + } elseif ($compiler->php_handling == Smarty::PHP_QUOTE) { + $output = preg_replace_callback('#(<\?(?:php|=)?)|(<%)|()|(\?>)|(%>)|(<\/script>)#i', array($this, + 'quote'), $_attr['code']); + $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Text($output)); + return ''; + } elseif ($compiler->php_handling == Smarty::PHP_PASSTHRU || $_attr['type'] == 'unmatched') { + $compiler->tag_nocache = true; + $save = $compiler->template->compiled->has_nocache_code; + $output = addcslashes($_attr['code'], "'\\"); + $compiler->parser->current_buffer->append_subtree($compiler->parser, new Smarty_Internal_ParseTree_Tag($compiler->parser, $compiler->processNocacheCode("", $compiler, true))); + $compiler->template->compiled->has_nocache_code = $save; + return ''; + } elseif ($compiler->php_handling == Smarty::PHP_ALLOW) { + if (!($compiler->smarty instanceof SmartyBC)) { + $compiler->trigger_template_error('$smarty->php_handling PHP_ALLOW not allowed. Use SmartyBC to enable it', null, true); + } + $compiler->has_code = true; + return $_attr['code']; + } else { + $compiler->trigger_template_error('Illegal $smarty->php_handling value', null, true); + } + } else { + $compiler->has_code = true; + if (!($compiler->smarty instanceof SmartyBC)) { + $compiler->trigger_template_error('{php}{/php} tags not allowed. Use SmartyBC to enable them', null, true); + } + $ldel = preg_quote($compiler->smarty->left_delimiter, '#'); + $rdel = preg_quote($compiler->smarty->right_delimiter, '#'); + preg_match("#^({$ldel}php\\s*)((.)*?)({$rdel})#", $_attr['code'], $match); + if (!empty($match[2])) { + if ('nocache' == trim($match[2])) { + $compiler->tag_nocache = true; + } else { + $compiler->trigger_template_error("illegal value of option flag \"{$match[2]}\"", null, true); + } + } + return preg_replace(array("#^{$ldel}\\s*php\\s*(.)*?{$rdel}#", + "#{$ldel}\\s*/\\s*php\\s*{$rdel}$#"), array(''), $_attr['code']); + } + } + + /** + * Lexer code for PHP tags + * + * This code has been moved from lexer here fo easier debugging and maintenance + * + * @param $lex + */ + public function parsePhp($lex) + { + $lex->token = Smarty_Internal_Templateparser::TP_PHP; + $close = 0; + $lex->taglineno = $lex->line; + $closeTag = '?>'; + if (strpos($lex->value, 'is_xml = true; + $lex->token = Smarty_Internal_Templateparser::TP_NOCACHE; + return; + } elseif (strpos($lex->value, 'phpType = 'php'; + } elseif (strpos($lex->value, '<%') === 0) { + $lex->phpType = 'asp'; + $closeTag = '%>'; + } elseif (strpos($lex->value, '%>') === 0) { + $lex->phpType = 'unmatched'; + } elseif (strpos($lex->value, '?>') === 0) { + if ($lex->is_xml) { + $lex->is_xml = false; + $lex->token = Smarty_Internal_Templateparser::TP_NOCACHE; + return; + } + $lex->phpType = 'unmatched'; + } elseif (strpos($lex->value, 'phpType = 'script'; + $closeTag = ''; + } elseif (strpos($lex->value, $lex->smarty->left_delimiter) === 0) { + if ($lex->isAutoLiteral()) { + $lex->token = Smarty_Internal_Templateparser::TP_TEXT; + return; + } + $closeTag = "{$lex->smarty->left_delimiter}/php{$lex->smarty->right_delimiter}"; + if ($lex->value == $closeTag) { + $lex->compiler->trigger_template_error("unexpected closing tag '{$closeTag}'"); + } + $lex->phpType = 'tag'; + } + if ($lex->phpType == 'unmatched') { + return; + } + if (($lex->phpType == 'php' || $lex->phpType == 'asp') && + ($lex->compiler->php_handling == Smarty::PHP_PASSTHRU || $lex->compiler->php_handling == Smarty::PHP_QUOTE) + ) { + return; + } + $start = $lex->counter + strlen($lex->value); + $body = true; + if (preg_match('~' . preg_quote($closeTag, '~') . '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) { + $close = $match[0][1]; + } else { + $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); + } + while ($body) { + if (preg_match('~([/][*])|([/][/][^\n]*)|(\'[^\'\\\\]*(?:\\.[^\'\\\\]*)*\')|("[^"\\\\]*(?:\\.[^"\\\\]*)*")~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start)) { + $value = $match[0][0]; + $from = $pos = $match[0][1]; + if ($pos > $close) { + $body = false; + } else { + $start = $pos + strlen($value); + $phpCommentStart = $value == '/*'; + if ($phpCommentStart) { + $phpCommentEnd = preg_match('~([*][/])~', $lex->data, $match, PREG_OFFSET_CAPTURE, $start); + if ($phpCommentEnd) { + $pos2 = $match[0][1]; + $start = $pos2 + strlen($match[0][0]); + } + } + while ($close > $pos && $close < $start) { + if (preg_match('~' . preg_quote($closeTag, '~') . + '~i', $lex->data, $match, PREG_OFFSET_CAPTURE, $from)) { + $close = $match[0][1]; + $from = $close + strlen($match[0][0]); + } else { + $lex->compiler->trigger_template_error("missing closing tag '{$closeTag}'"); + } + } + if ($phpCommentStart && (!$phpCommentEnd || $pos2 > $close)) { + $lex->taglineno = $lex->line + substr_count(substr($lex->data, $lex->counter, $start), "\n"); + $lex->compiler->trigger_template_error("missing PHP comment closing tag '*/'"); + } + } + } else { + $body = false; + } + } + $lex->value = substr($lex->data, $lex->counter, $close + strlen($closeTag) - $lex->counter); + } + + /* + * Call back function for $php_handling = PHP_QUOTE + * + */ + /** + * @param $match + * + * @return string + */ + private function quote($match) + { + return htmlspecialchars($match[0], ENT_QUOTES); + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_compilealltemplates.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_compilealltemplates.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_compilealltemplates.php (revision Shelved version) @@ -0,0 +1,111 @@ +compileAll($smarty, $extension, $force_compile, $time_limit, $max_errors); + } + + /** + * Compile all template or config files + * + * @param \Smarty $smarty + * @param string $extension template file name extension + * @param bool $force_compile force all to recompile + * @param int $time_limit set maximum execution time + * @param int $max_errors set maximum allowed errors + * @param bool $isConfig flag true if called for config files + * + * @return int number of template files compiled + */ + protected function compileAll(Smarty $smarty, $extension, $force_compile, $time_limit, $max_errors, $isConfig = false) + { + // switch off time limit + if (function_exists('set_time_limit')) { + @set_time_limit($time_limit); + } + $_count = 0; + $_error_count = 0; + $sourceDir = $isConfig ? $smarty->getConfigDir() : $smarty->getTemplateDir(); + // loop over array of source directories + foreach ($sourceDir as $_dir) { + $_dir_1 = new RecursiveDirectoryIterator($_dir); + $_dir_2 = new RecursiveIteratorIterator($_dir_1); + foreach ($_dir_2 as $_fileinfo) { + $_file = $_fileinfo->getFilename(); + if (substr(basename($_fileinfo->getPathname()), 0, 1) == '.' || strpos($_file, '.svn') !== false) { + continue; + } + if (!substr_compare($_file, $extension, - strlen($extension)) == 0) { + continue; + } + if ($_fileinfo->getPath() == !substr($_dir, 0, - 1)) { + $_file = substr($_fileinfo->getPath(), strlen($_dir)) . DS . $_file; + } + echo "\n
", $_dir, '---', $_file; + flush(); + $_start_time = microtime(true); + $_smarty = clone $smarty; + $_smarty->force_compile = $force_compile; + try { + /* @var Smarty_Internal_Template $_tpl */ + $_tpl = new $smarty->template_class($_file, $_smarty); + $_tpl->caching = Smarty::CACHING_OFF; + $_tpl->source = $isConfig ? Smarty_Template_Config::load($_tpl) : Smarty_Template_Source::load($_tpl); + if ($_tpl->mustCompile()) { + $_tpl->compileTemplateSource(); + $_count ++; + echo ' compiled in ', microtime(true) - $_start_time, ' seconds'; + flush(); + } else { + echo ' is up to date'; + flush(); + } + } + catch (Exception $e) { + echo "\n
------>Error: ", $e->getMessage(), "

\n"; + $_error_count ++; + } + // free memory + unset($_tpl); + $_smarty->_cache['template_objects'] = array(); + if ($max_errors !== null && $_error_count == $max_errors) { + echo "\n

too many errors\n"; + exit(); + } + } + } + echo "\n
"; + return $_count; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregistercacheresource.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregistercacheresource.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregistercacheresource.php (revision Shelved version) @@ -0,0 +1,40 @@ +smarty) ? $obj->smarty : $obj; + if (isset($smarty->registered_cache_resources[$name])) { + unset($smarty->registered_cache_resources[$name]); + } + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/plugins/modifier.escape.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/modifier.escape.php (revision Local version) +++ src/includes/classes/Smarty/plugins/modifier.escape.php (revision Shelved version) @@ -195,4 +195,4 @@ default: return $string; } -} \ No newline at end of file +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_template.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_template.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_template.php (revision Shelved version) @@ -0,0 +1,128 @@ +subtrees)) { + $this->subtrees = array_merge($this->subtrees, $subtree->subtrees); + } else { + if ($subtree->data !== '') { + $this->subtrees[] = $subtree; + } + } + } + + /** + * Append array to subtree + * + * @param \Smarty_Internal_Templateparser $parser + * @param \Smarty_Internal_ParseTree[] $array + */ + public function append_array(Smarty_Internal_Templateparser $parser, $array = array()) + { + if (!empty($array)) { + $this->subtrees = array_merge($this->subtrees, (array) $array); + } + } + + /** + * Prepend array to subtree + * + * @param \Smarty_Internal_Templateparser $parser + * @param \Smarty_Internal_ParseTree[] $array + */ + public function prepend_array(Smarty_Internal_Templateparser $parser, $array = array()) + { + if (!empty($array)) { + $this->subtrees = array_merge((array) $array, $this->subtrees); + } + } + + /** + * Sanitize and merge subtree buffers together + * + * @param \Smarty_Internal_Templateparser $parser + * + * @return string template code content + */ + public function to_smarty_php(Smarty_Internal_Templateparser $parser) + { + $code = ''; + for ($key = 0, $cnt = count($this->subtrees); $key < $cnt; $key ++) { + if ($this->subtrees[$key] instanceof Smarty_Internal_ParseTree_Text) { + $subtree = $this->subtrees[$key]->to_smarty_php($parser); + while ($key + 1 < $cnt && ($this->subtrees[$key + 1] instanceof Smarty_Internal_ParseTree_Text || + $this->subtrees[$key + 1]->data == '')) { + $key ++; + if ($this->subtrees[$key]->data == '') { + continue; + } + $subtree .= $this->subtrees[$key]->to_smarty_php($parser); + } + if ($subtree == '') { + continue; + } + $code .= preg_replace('/((<%)|(%>)|(<\?php)|(<\?)|(\?>)|(<\/?script))/', "\n", + $subtree); + continue; + } + if ($this->subtrees[$key] instanceof Smarty_Internal_ParseTree_Tag) { + $subtree = $this->subtrees[$key]->to_smarty_php($parser); + while ($key + 1 < $cnt && ($this->subtrees[$key + 1] instanceof Smarty_Internal_ParseTree_Tag || + $this->subtrees[$key + 1]->data == '')) { + $key ++; + if ($this->subtrees[$key]->data == '') { + continue; + } + $subtree = $parser->compiler->appendCode($subtree, $this->subtrees[$key]->to_smarty_php($parser)); + } + if ($subtree == '') { + continue; + } + $code .= $subtree; + continue; + } + $code .= $this->subtrees[$key]->to_smarty_php($parser); + } + return $code; + } +} Index: src/includes/classes/Smarty/plugins/function.mailto.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/function.mailto.php (revision Local version) +++ src/includes/classes/Smarty/plugins/function.mailto.php (revision Shelved version) @@ -152,4 +152,4 @@ // no encoding return '' . $text . ''; } -} \ No newline at end of file +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_updatecache.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_updatecache.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_runtime_updatecache.php (revision Shelved version) @@ -0,0 +1,170 @@ +hashes[$_template->compiled->nocache_hash]); + if (!empty($cached->hashes)) { + $hash_array = array(); + foreach ($cached->hashes as $hash => $foo) { + $hash_array[] = "/{$hash}/"; + } + $content = preg_replace($hash_array, $_template->compiled->nocache_hash, $content); + } + $_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); + $content = ''; + // loop over items, stitch back together + foreach ($cache_split as $curr_idx => $curr_split) { + // escape PHP tags in template content + $content .= preg_replace('/(<%|%>|<\?php|<\?|\?>|)/', + "\n", $curr_split); + if (isset($cache_parts[0][$curr_idx])) { + $_template->cached->has_nocache_code = true; + $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'])) + ) { + $content = $_template->smarty->ext->_filterHandler->runFilter('output', $content, $_template); + } + // write cache file content + $this->writeCachedContent($cached, $_template, $content); + } + + /** + * Cache was invalid , so render from compiled and write to cache + * + * @param \Smarty_Template_Cached $cached + * @param \Smarty_Internal_Template $_template + * @param $no_output_filter + * + * @throws \Exception + */ + public function updateCache(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $no_output_filter) + { + if ($_template->source->handler->uncompiled) { + ob_start(); + $_template->source->render($_template); + } else { + ob_start(); + if (!isset($_template->compiled)) { + $_template->loadCompiled(); + } + $_template->compiled->render($_template); + } + if ($_template->smarty->debugging) { + $_template->smarty->_debug->start_cache($_template); + } + $this->removeNoCacheHash($cached, $_template, $no_output_filter); + $compile_check = $_template->smarty->compile_check; + $_template->smarty->compile_check = false; + if (isset($_template->parent) && $_template->parent->_objType == 2) { + $_template->compiled->unifunc = $_template->parent->compiled->unifunc; + } + if (!$_template->cached->processed) { + $_template->cached->process($_template, true); + } + $_template->smarty->compile_check = $compile_check; + $cached->getRenderedTemplateCode($_template); + if ($_template->smarty->debugging) { + $_template->smarty->_debug->end_cache($_template); + } + } + + /** + * Writes the content to cache resource + * + * @param \Smarty_Template_Cached $cached + * @param Smarty_Internal_Template $_template + * @param string $content + * + * @return bool + */ + public function writeCachedContent(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $content) + { + if ($_template->source->handler->recompiled || !($_template->caching == Smarty::CACHING_LIFETIME_CURRENT || + $_template->caching == Smarty::CACHING_LIFETIME_SAVED) + ) { + // don't write cache file + return false; + } + $content = $_template->smarty->ext->_codeFrame->create($_template, $content, '', true); + return $this->write($cached, $_template, $content); + } + + /** + * Write this cache object to handler + * + * @param \Smarty_Template_Cached $cached + * @param Smarty_Internal_Template $_template template object + * @param string $content content to cache + * + * @return bool success + */ + public function write(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template, $content) + { + if (!$_template->source->handler->recompiled) { + if ($cached->handler->writeCachedContent($_template, $content)) { + $cached->content = null; + $cached->timestamp = time(); + $cached->exists = true; + $cached->valid = true; + $cached->cache_lifetime = $_template->cache_lifetime; + $cached->processed = false; + if ($_template->smarty->cache_locking) { + $cached->handler->releaseLock($_template->smarty, $cached); + } + + return true; + } + $cached->content = null; + $cached->timestamp = false; + $cached->exists = false; + $cached->valid = false; + $cached->processed = false; + } + + return false; + } + +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_extension_clear.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_extension_clear.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_extension_clear.php (revision Shelved version) @@ -0,0 +1,126 @@ +clear() method file cache file resource + * + * @package Smarty + * @subpackage PluginsInternal + * @author Uwe Tews + */ +class Smarty_Internal_Extension_Clear +{ + /** + * Empty cache for a specific template + * + * @param Smarty $smarty + * @param string $resource_name template name + * @param string $cache_id cache id + * @param string $compile_id compile id + * @param integer $exp_time expiration time (number of seconds, not timestamp) + * + * @return integer number of cache files deleted + */ + public static function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time) + { + $_cache_id = isset($cache_id) ? preg_replace('![^\w\|]+!', '_', $cache_id) : null; + $_compile_id = isset($compile_id) ? preg_replace('![^\w]+!', '_', $compile_id) : null; + $_dir_sep = $smarty->use_sub_dirs ? '/' : '^'; + $_compile_id_offset = $smarty->use_sub_dirs ? 3 : 0; + $_dir = $smarty->getCacheDir(); + if ($_dir == '/') { //We should never want to delete this! + return 0; + } + $_dir_length = strlen($_dir); + if (isset($_cache_id)) { + $_cache_id_parts = explode('|', $_cache_id); + $_cache_id_parts_count = count($_cache_id_parts); + if ($smarty->use_sub_dirs) { + foreach ($_cache_id_parts as $id_part) { + $_dir .= $id_part . DS; + } + } + } + if (isset($resource_name)) { + $_save_stat = $smarty->caching; + $smarty->caching = true; + $tpl = new $smarty->template_class($resource_name, $smarty); + $smarty->caching = $_save_stat; + + // remove from template cache + $tpl->source; // have the template registered before unset() + + if ($tpl->source->exists) { + $_resourcename_parts = basename(str_replace('^', '/', $tpl->cached->filepath)); + } else { + return 0; + } + } + $_count = 0; + $_time = time(); + if (file_exists($_dir)) { + $_cacheDirs = new RecursiveDirectoryIterator($_dir); + $_cache = new RecursiveIteratorIterator($_cacheDirs, RecursiveIteratorIterator::CHILD_FIRST); + foreach ($_cache as $_file) { + if (substr(basename($_file->getPathname()), 0, 1) == '.' || strpos($_file, '.svn') !== false) { + continue; + } + // directory ? + if ($_file->isDir()) { + if (!$_cache->isDot()) { + // delete folder if empty + @rmdir($_file->getPathname()); + } + } else { + $_parts = explode($_dir_sep, str_replace('\\', '/', substr((string) $_file, $_dir_length))); + $_parts_count = count($_parts); + // check name + if (isset($resource_name)) { + if ($_parts[$_parts_count - 1] != $_resourcename_parts) { + continue; + } + } + // check compile id + if (isset($_compile_id) && (!isset($_parts[$_parts_count - 2 - $_compile_id_offset]) || + $_parts[$_parts_count - 2 - $_compile_id_offset] != $_compile_id) + ) { + continue; + } + // check cache id + if (isset($_cache_id)) { + // count of cache id parts + $_parts_count = (isset($_compile_id)) ? $_parts_count - 2 - $_compile_id_offset : + $_parts_count - 1 - $_compile_id_offset; + if ($_parts_count < $_cache_id_parts_count) { + continue; + } + for ($i = 0; $i < $_cache_id_parts_count; $i ++) { + if ($_parts[$i] != $_cache_id_parts[$i]) { + continue 2; + } + } + } + // expired ? + if (isset($exp_time)) { + if ($exp_time < 0) { + preg_match('#\'cache_lifetime\' =>\s*(\d*)#', file_get_contents($_file), $match); + if ($_time < (@filemtime($_file) + $match[1])) { + continue; + } + } else { + if ($_time - @filemtime($_file) < $exp_time) { + continue; + } + } + } + $_count += @unlink((string) $_file) ? 1 : 0; + if (function_exists('opcache_invalidate')) { + opcache_invalidate((string) $_file); + } + } + } + } + return $_count; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_text.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_text.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_text.php (revision Shelved version) @@ -0,0 +1,40 @@ +data = $data; + } + + /** + * Return buffer content + * + * @param \Smarty_Internal_Templateparser $parser + * + * @return string text + */ + public function to_smarty_php(Smarty_Internal_Templateparser $parser) + { + return $this->data; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_addautoloadfilters.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_addautoloadfilters.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_addautoloadfilters.php (revision Shelved version) @@ -0,0 +1,51 @@ +smarty) ? $obj->smarty : $obj; + if ($type !== null) { + $this->_checkFilterType($type); + if (!empty($smarty->autoload_filters[$type])) { + $smarty->autoload_filters[$type] = array_merge($smarty->autoload_filters[$type], (array) $filters); + } else { + $smarty->autoload_filters[$type] = (array) $filters; + } + } else { + foreach ((array) $filters as $type => $value) { + $this->_checkFilterType($type); + if (!empty($smarty->autoload_filters[$type])) { + $smarty->autoload_filters[$type] = array_merge($smarty->autoload_filters[$type], (array) $value); + } else { + $smarty->autoload_filters[$type] = (array) $value; + } + } + } + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_compileallconfig.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_compileallconfig.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_compileallconfig.php (revision Shelved version) @@ -0,0 +1,32 @@ +compileAll($smarty, $extension, $force_compile, $time_limit, $max_errors, true); + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_registerresource.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_registerresource.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_registerresource.php (revision Shelved version) @@ -0,0 +1,44 @@ +smarty) ? $obj->smarty : $obj; + $smarty->registered_resources[$name] = $resource_handler instanceof + Smarty_Resource ? $resource_handler : array($resource_handler, false); + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearallassign.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearallassign.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_clearallassign.php (revision Shelved version) @@ -0,0 +1,37 @@ +tpl_vars = array(); + + return $data; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_getregisteredobject.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_getregisteredobject.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_getregisteredobject.php (revision Shelved version) @@ -0,0 +1,44 @@ +smarty) ? $obj->smarty : $obj; + if (!isset($smarty->registered_objects[$object_name])) { + throw new SmartyException("'$object_name' is not a registered object"); + } + if (!is_object($smarty->registered_objects[$object_name][0])) { + throw new SmartyException("registered '$object_name' is not an object"); + } + return $smarty->registered_objects[$object_name][0]; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/Autoloader.php =================================================================== --- src/includes/classes/Smarty/Autoloader.php (revision Shelved version) +++ src/includes/classes/Smarty/Autoloader.php (revision Shelved version) @@ -0,0 +1,124 @@ + 'Smarty.class.php', 'smartybc' => 'SmartyBC.class.php',); + + /** + * Registers Smarty_Autoloader backward compatible to older installations. + * + * @param bool $prepend Whether to prepend the autoloader or not. + */ + public static function registerBC($prepend = false) + { + /** + * register the class autoloader + */ + if (!defined('SMARTY_SPL_AUTOLOAD')) { + define('SMARTY_SPL_AUTOLOAD', 0); + } + if (SMARTY_SPL_AUTOLOAD && + set_include_path(get_include_path() . PATH_SEPARATOR . SMARTY_SYSPLUGINS_DIR) !== false + ) { + $registeredAutoLoadFunctions = spl_autoload_functions(); + if (!isset($registeredAutoLoadFunctions['spl_autoload'])) { + spl_autoload_register(); + } + } else { + self::register($prepend); + } + } + + /** + * Registers Smarty_Autoloader as an SPL autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not. + */ + public static function register($prepend = false) + { + self::$SMARTY_DIR = defined('SMARTY_DIR') ? SMARTY_DIR : dirname(__FILE__) . DIRECTORY_SEPARATOR; + self::$SMARTY_SYSPLUGINS_DIR = defined('SMARTY_SYSPLUGINS_DIR') ? SMARTY_SYSPLUGINS_DIR : + self::$SMARTY_DIR . 'sysplugins' . DIRECTORY_SEPARATOR; + if (version_compare(phpversion(), '5.3.0', '>=')) { + spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend); + } else { + spl_autoload_register(array(__CLASS__, 'autoload')); + } + } + + /** + * Handles auto loading of classes. + * + * @param string $class A class name. + */ + public static function autoload($class) + { + $_class = strtolower($class); + $file = self::$SMARTY_SYSPLUGINS_DIR . $_class . '.php'; + if (strpos($_class, 'smarty_internal_') === 0) { + if (strpos($_class, 'smarty_internal_compile_') === 0) { + if (is_file($file)) { + require $file; + } + return; + } + @include $file; + return; + } + if (preg_match('/^(smarty_(((template_(source|config|cache|compiled|resource_base))|((cached|compiled)?resource)|(variable|security)))|(smarty(bc)?)$)/', + $_class, $match)) { + if (!empty($match[3])) { + @include $file; + return; + } elseif (!empty($match[9]) && isset(self::$rootClasses[$_class])) { + $file = self::$rootClasses[$_class]; + require $file; + return; + } + } + if (0 !== strpos($_class, 'smarty')) { + return; + } + if (is_file($file)) { + require $file; + return; + } + return; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_object_block_function.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_object_block_function.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_object_block_function.php (revision Shelved version) @@ -27,15 +27,15 @@ /** * Compiles code for the execution of block plugin * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter + * @param array $parameter array with compilation parameter - * @param string $tag name of block object + * @param string $tag name of block object - * @param string $method name of method to call + * @param string $method name of method to call * * @return string compiled code */ - public function compile($args, $compiler, $parameter, $tag, $method) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $method) { if (!isset($tag[5]) || substr($tag, - 5) != 'close') { // opening tag of block plugin @@ -60,7 +60,8 @@ // maybe nocache because of nocache variables or nocache plugin $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; // compile code - $output = "smarty->_tag_stack[] = array('{$tag}->{$method}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>"; + $output = + "smarty->_cache['tag_stack'][] = array('{$tag}->{$method}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>"; } else { $base_tag = substr($tag, 0, - 5); // must endblock be nocache? @@ -76,9 +77,13 @@ $mod_pre = $mod_post = ''; } else { $mod_pre = ' ob_start(); '; - $mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'], 'value' => 'ob_get_clean()')) . ';'; + $mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(), + array('modifierlist' => $parameter['modifier_list'], + 'value' => 'ob_get_clean()')) . ';'; } - $output = "smarty->registered_objects['{$base_tag}'][0]->{$method}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " . $mod_post . " } array_pop(\$_smarty_tpl->smarty->_tag_stack);?>"; + $output = "smarty->registered_objects['{$base_tag}'][0]->{$method}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " . + $mod_post . " } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>"; } return $output . "\n"; Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregisterobject.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregisterobject.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_unregisterobject.php (revision Shelved version) @@ -0,0 +1,40 @@ +smarty) ? $obj->smarty : $obj; + if (isset($smarty->registered_objects[$object_name])) { + unset($smarty->registered_objects[$object_name]); + } + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/plugins/modifier.debug_print_var.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/plugins/modifier.debug_print_var.php (revision Local version) +++ src/includes/classes/Smarty/plugins/modifier.debug_print_var.php (revision Shelved version) @@ -14,26 +14,30 @@ * * @author Monte Ohrt * - * @param array|object $var variable to be formatted + * @param array|object $var variable to be formatted - * @param integer $depth maximum recursion depth if $var is an array - * @param integer $length maximum string length if $var is a string + * @param int $max maximum recursion depth if $var is an array or object + * @param int $length maximum string length if $var is a string + * @param int $depth actual recursion depth + * @param array $objects processed objects in actual depth to prevent recursive object processing * * @return string */ -function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) +function smarty_modifier_debug_print_var($var, $max = 10, $length = 40, $depth = 0, $objects = array()) { - $_replace = array("\n" => '\n', - "\r" => '\r', - "\t" => '\t' + $_replace = array("\n" => '\n', + "\r" => '\r', + "\t" => '\t' ); - switch (gettype($var)) { case 'array' : $results = 'Array (' . count($var) . ')'; + if ($depth == $max) { + break; + } foreach ($var as $curr_key => $curr_val) { $results .= '
' . str_repeat(' ', $depth * 2) . '' . strtr($curr_key, $_replace) . ' => ' - . smarty_modifier_debug_print_var($curr_val, ++$depth, $length); + . smarty_modifier_debug_print_var($curr_val, $max, $length, ++ $depth, $objects); $depth --; } break; @@ -41,10 +45,18 @@ case 'object' : $object_vars = get_object_vars($var); $results = '' . get_class($var) . ' Object (' . count($object_vars) . ')'; + if (in_array($var, $objects)) { + $results .= ' called recursive'; + break; + } + if ($depth == $max) { + break; + } + $objects[] = $var; foreach ($object_vars as $curr_key => $curr_val) { $results .= '
' . str_repeat(' ', $depth * 2) . ' ->' . strtr($curr_key, $_replace) . ' = ' - . smarty_modifier_debug_print_var($curr_val, ++$depth, $length); + . smarty_modifier_debug_print_var($curr_val, $max, $length, ++ $depth, $objects); $depth --; } break; Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_nocache.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_nocache.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_nocache.php (revision Shelved version) @@ -17,20 +17,25 @@ class Smarty_Internal_Compile_Nocache extends Smarty_Internal_CompileBase { /** + * Array of names of valid option flags + * + * @var array + */ + public $option_flags = array(); + + /** * Compiles code for the {nocache} tag * This tag does not generate compiled output. It only sets a compiler flag. * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * * @return bool */ - public function compile($args, $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) { $_attr = $this->getAttributes($compiler, $args); - if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); - } + $this->openTag($compiler, 'nocache', array($compiler->nocache)); // enter nocache mode $compiler->nocache = true; // this tag does not return compiled code @@ -52,16 +57,16 @@ * Compiles code for the {/nocache} tag * This tag does not generate compiled output. It only sets a compiler flag. * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * * @return bool */ - public function compile($args, $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) { $_attr = $this->getAttributes($compiler, $args); // leave nocache mode - $compiler->nocache = false; + list($compiler->nocache) = $this->closeTag($compiler, array('nocache')); // this tag does not return compiled code $compiler->has_code = false; Index: src/includes/classes/Smarty/sysplugins/smarty_internal_templatecompilerbase.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_templatecompilerbase.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_templatecompilerbase.php (revision Shelved version) @@ -14,87 +14,100 @@ * * @package Smarty * @subpackage Compiler + * + * @property Smarty_Internal_SmartyTemplateCompiler $prefixCompiledCode = '' + * @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = '' + * @method Smarty_Internal_SmartyTemplateCompiler registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false) + * @method Smarty_Internal_SmartyTemplateCompiler unregisterPostCompileCallback($key) */ abstract class Smarty_Internal_TemplateCompilerBase { + /** - * hash for nocache sections + * Smarty object * - * @var mixed + * @var Smarty */ - private $nocache_hash = null; + public $smarty = null; /** - * suppress generation of nocache code + * Parser object * - * @var bool + * @var Smarty_Internal_Templateparser */ - public $suppressNocacheProcessing = false; + public $parser = null; /** - * suppress generation of merged template code + * Smarty object * - * @var bool + * @var Smarty */ - public $suppressMergedTemplates = false; + public $smarty = null; /** - * compile tag objects + * Parser object * - * @var array + * @var Smarty_Internal_Templateparser */ - public static $_tag_objects = array(); + public $parser = null; /** - * tag stack + * hash for nocache sections * - * @var array + * @var mixed */ - public $_tag_stack = array(); + public $nocache_hash = null; /** - * current template + * suppress generation of nocache code * - * @var Smarty_Internal_Template + * @var bool */ - public $template = null; + public $suppressNocacheProcessing = false; /** - * merged templates + * compile tag objects cache * * @var array */ - public $merged_templates = array(); + public $_tag_objects = array(); /** - * sources which must be compiled + * tag stack * * @var array */ - public $sources = array(); + public $_tag_stack = array(); /** - * flag that we are inside {block} + * current template * - * @var bool + * @var Smarty_Internal_Template */ - public $inheritance = false; + public $template = null; /** - * flag when compiling inheritance child template + * merged included sub template data * - * @var bool + * @var array */ - public $inheritance_child = false; + public $mergedSubTemplatesData = array(); /** - * uid of templates called by {extends} for recursion check + * merged sub template code * * @var array */ - public $extends_uid = array(); + public $mergedSubTemplatesCode = array(); /** + * collected template properties during compilation + * + * @var array + */ + public $templateProperties = array(); + + /** * source line offset for error messages * * @var int @@ -114,6 +127,7 @@ * @var string */ public $trace_filepath = ''; + /** * stack for tracing file and line of nested {block} tags * @@ -143,184 +157,371 @@ public $forceNocache = false; /** - * suppress Smarty header code in compiled template + * flag if compiled template file shall we written * * @var bool */ - public $suppressHeader = false; + public $has_code = false; /** - * suppress template property header code in compiled template + * Template functions * + * @var array + */ + public $tpl_function = array(); + + /** + * called sub functions from template function + * + * @var array + */ + public $variable_filter_stack = array(); + + /** + * compiled template or block function code + * + * @var string + */ + public $blockOrFunctionCode = ''; + + /** + * php_handling setting either from Smarty or security + * + * @var int + */ + public $php_handling = 0; + + /** + * flags for used modifier plugins + * * @var bool */ - public $suppressTemplatePropertyHeader = false; + public $has_output = false; /** - * suppress pre and post filter + * Stack for {setfilter} {/setfilter} * + * @var array + */ + public $modifier_plugins = array(); + + /** + * Nesting count of looping tags like {foreach}, {for}, {section}, {while} + * + * @var array + */ + public $plugin_search_order = array('function', 'block', 'compiler', 'class'); + + /** + * parent compiler object for merged subtemplates and template functions + * + * @var Smarty_Internal_TemplateCompilerBase + */ + public $parent_compiler = null; + + /** + * Flag true when compiling nocache section + * + * @var array + */ + public $prefix_code = array(); + + /** + * Prefix code stack + * + * @var array + */ + public $prefixCodeStack = array(); + + /** + * Tag has compiled code + * * @var bool */ - public $suppressFilter = false; + public $nocache = false; /** - * flag if compiled template file shall we written + * Flag true when tag is compiled as nocache * * @var bool */ - public $write_compiled_code = true; + public $tag_nocache = false; /** - * flag if currently a template function is compiled + * Compiled tag prefix code * + * @var int + */ + public $loopNesting = 0; + + /** + * Strip preg pattern + * + * @var string + */ + public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!'; + + /** + * plugin search order + * + * @var array + */ + public $prefix_code = array(); + + /** + * Prefix code stack + * + * @var array + */ + public $prefixCodeStack = array(); + + /** + * Tag has compiled code + * * @var bool */ - public $compiles_template_function = false; + public $has_code = false; /** - * called subfuntions from template function + * A variable string was compiled * + * @var bool + */ + public $has_variable_string = false; + + /** + * Tag creates output + * + * @var bool + */ + public $has_output = false; + + /** + * Stack for {setfilter} {/setfilter} + * * @var array */ - public $called_functions = array(); + public $variable_filter_stack = array(); /** - * flags for used modifier plugins + * variable filters for {setfilter} {/setfilter} * * @var array */ - public $modifier_plugins = array(); + public $variable_filters = array(); /** - * type of already compiled modifier + * Nesting count of looping tags like {foreach}, {for}, {section}, {while} * + * @var int + */ + public $loopNesting = 0; + + /** + * Strip preg pattern + * + * @var string + */ + public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!'; + + /** + * plugin search order + * * @var array */ - public $known_modifier_type = array(); + public $plugin_search_order = array('function', 'block', 'compiler', 'class'); /** + * General storage area for tag compiler plugins + * + * @var array + */ + public $_cache = array(); + + /** + * General storage area for tag compiler plugins + * + * @var array + */ + public $_cache = array(); + + /** * method to compile a Smarty template * - * @param mixed $_content template source + * @param mixed $_content template source + * @param bool $isTemplateSource * - * @return bool true if compiling succeeded, false if it failed + * @return bool true if compiling succeeded, false if it failed */ - abstract protected function doCompile($_content); + abstract protected function doCompile($_content, $isTemplateSource = false); /** * Initialize compiler + * + * @param Smarty $smarty global instance */ - public function __construct() + public function __construct(Smarty $smarty) { - $this->nocache_hash = str_replace(array('.', ','), '-', uniqid(rand(), true)); + $this->smarty = $smarty; + $this->nocache_hash = str_replace(array('.', ','), '_', uniqid(rand(), true)); } /** * Method to compile a Smarty template * - * @param Smarty_Internal_Template $template template object to compile + * @param Smarty_Internal_Template $template template object to compile - * @param bool $nocache true is shall be compiled in nocache mode + * @param bool $nocache true is shall be compiled in nocache mode + * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler * - * @return bool true if compiling succeeded, false if it failed + * @return bool true if compiling succeeded, false if it failed + * @throws \Exception */ - public function compileTemplate(Smarty_Internal_Template $template, $nocache = false) + public function compileTemplate(Smarty_Internal_Template $template, $nocache = null, + Smarty_Internal_TemplateCompilerBase $parent_compiler = null) { - if (empty($template->properties['nocache_hash'])) { - $template->properties['nocache_hash'] = $this->nocache_hash; - } else { - $this->nocache_hash = $template->properties['nocache_hash']; + // get code frame of compiled template + $_compiled_code = $template->smarty->ext->_codeFrame->create($template, + $this->compileTemplateSource($template, $nocache, + $parent_compiler), + $this->postFilter($this->blockOrFunctionCode) . + join('', $this->mergedSubTemplatesCode), false, + $this); + return $_compiled_code; - } + } - // flag for nochache sections - $this->nocache = $nocache; - $this->tag_nocache = false; + + /** + * Compile template source and run optional post filter + * + * @param \Smarty_Internal_Template $template + * @param null|bool $nocache flag if template must be compiled in nocache mode + * @param \Smarty_Internal_TemplateCompilerBase $parent_compiler + * + * @return string + * @throws \Exception + */ + public function compileTemplateSource(Smarty_Internal_Template $template, $nocache = null, + Smarty_Internal_TemplateCompilerBase $parent_compiler = null) + { + try { - // save template object in compiler class - $this->template = $template; + // save template object in compiler class + $this->template = $template; - // reset has nocache code flag - $this->template->has_nocache_code = false; - $save_source = $this->template->source; - // template header code - $template_header = ''; - if (!$this->suppressHeader) { - $template_header .= "template->source->filepath . "\" */ ?>\n"; + if (property_exists($this->template->smarty, 'plugin_search_order')) { + $this->plugin_search_order = $this->template->smarty->plugin_search_order; - } + } - - if (empty($this->template->source->components)) { - $this->sources = array($template->source); - } else { - // we have array of inheritance templates by extends: resource - $this->sources = array_reverse($template->source->components); - } - $loop = 0; - // the $this->sources array can get additional elements while compiling by the {extends} tag - while ($this->template->source = array_shift($this->sources)) { - $this->smarty->_current_file = $this->template->source->filepath; if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_compile($this->template); + $this->smarty->_debug->start_compile($this->template); } - $no_sources = count($this->sources); - if ($loop || $no_sources) { - $this->template->properties['file_dependency'][$this->template->source->uid] = array($this->template->source->filepath, $this->template->source->timestamp, $this->template->source->type); + if (isset($this->template->smarty->security_policy)) { + $this->php_handling = $this->template->smarty->security_policy->php_handling; + } else { + $this->php_handling = $this->template->smarty->php_handling; } - $loop ++; - if ($no_sources) { - $this->inheritance_child = true; + $this->parent_compiler = $parent_compiler ? $parent_compiler : $this; + $nocache = isset($nocache) ? $nocache : false; + if (empty($template->compiled->nocache_hash)) { + $template->compiled->nocache_hash = $this->nocache_hash; } else { - $this->inheritance_child = false; + $this->nocache_hash = $template->compiled->nocache_hash; } - do { - $_compiled_code = ''; - // flag for aborting current and start recompile - $this->abort_and_recompile = false; + // flag for nocache sections + $this->nocache = $nocache; + $this->tag_nocache = false; + // reset has nocache code flag + $this->template->compiled->has_nocache_code = false; + $this->has_variable_string = false; + $this->prefix_code = array(); + // add file dependency + $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] = + array($this->template->source->filepath, $this->template->source->getTimeStamp(), + $this->template->source->type); + $this->smarty->_current_file = $this->template->source->filepath; - // get template source + // get template source - $_content = $this->template->source->content; - if ($_content != '') { - // run prefilter if required - if ((isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) && !$this->suppressFilter) { - $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template); + if (!empty($this->template->source->components)) { + // we have array of inheritance templates by extends: resource + // generate corresponding source code sequence + $_content = + Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template->source->components); + } else { + // get template source + $_content = $this->template->source->getContent(); - } + } - // call compiler - $_compiled_code = $this->doCompile($_content); + $_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true)); - } + } - } while ($this->abort_and_recompile); + catch (Exception $e) { if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_compile($this->template); + $this->smarty->_debug->end_compile($this->template); } - } - // restore source - $this->template->source = $save_source; - unset($save_source); - $this->smarty->_current_file = $this->template->source->filepath; + $this->_tag_stack = array(); + $this->_tag_objects = array(); - // free memory + // free memory - unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex, $this->template); - 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) { - $merged_code .= $code; + $this->parent_compiler = null; + $this->template = null; + $this->parser = null; + throw $e; - } + } + if ($this->smarty->debugging) { + $this->smarty->_debug->end_compile($this->template); } - // 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 != '') { - $_compiled_code = Smarty_Internal_Filter_Handler::runFilter('post', $_compiled_code, $template); + $this->parent_compiler = null; + $this->template = null; + $this->parser = null; + return $_compiled_code; - } + } - if ($this->suppressTemplatePropertyHeader) { - $code = $_compiled_code . $merged_code; + + /** + * Optionally process compiled code by post filter + * + * @param string $code compiled code + * + * @return string + * @throws \SmartyException + */ + public function postFilter($code) + { + // run post filter if on code + if (!empty($code) && + (isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ])) + ) { + return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template); } else { - $code = $template_header . $template->createTemplateCodeFrame($_compiled_code) . $merged_code; + return $code; } - // unset content because template inheritance could have replace source with parent code - unset ($template->source->content); + } - return $code; + /** + * Run optional prefilter + * + * @param string $_content template source + * + * @return string + * @throws \SmartyException + */ + public function preFilter($_content) + { + // run pre filter if required + if ($_content != '' && + ((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ]))) + ) { + return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template); + } else { + return $_content; - } + } + } /** * Compile Tag * This is a call back from the lexer/parser - * It executes the required compile plugin for the Smarty tag * + * Save current prefix code + * Compile tag + * Merge tag prefix code with saved one + * (required nested tags in attributes) + * + * Save current prefix code + * Compile tag + * Merge tag prefix code with saved one + * (required nested tags in attributes) + * * @param string $tag tag name * @param array $args array with tag attributes * @param array $parameter array with compilation parameter @@ -331,25 +532,46 @@ */ public function compileTag($tag, $args, $parameter = array()) { + $this->prefixCodeStack[] = $this->prefix_code; + $this->prefix_code = array(); + $result = $this->compileTag2($tag, $args, $parameter); + $this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack)); + return $result; + } + + /** + * Compile Tag + * + * @param string $tag tag name + * @param array $args array with tag attributes + * @param array $parameter array with compilation parameter + * + * @throws SmartyCompilerException + * @throws SmartyException + * @return string compiled code + */ + private function compileTag2($tag, $args, $parameter) + { + $plugin_type = ''; // $args contains the attributes parsed and compiled by the lexer/parser // assume that tag does compile into code, but creates no HTML output $this->has_code = true; $this->has_output = false; // log tag/attributes - if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) { - $this->template->used_tags[] = array($tag, $args); + if (isset($this->smarty->_cache[ 'get_used_tags' ])) { + $this->template->_cache[ 'used_tags' ][] = array($tag, $args); } // check nocache option flag - if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args) - || in_array(array('nocache' => '"true"'), $args) || in_array(array('nocache' => "'true'"), $args) + if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args) || + in_array(array('nocache' => '"true"'), $args) || in_array(array('nocache' => "'true'"), $args) ) { $this->tag_nocache = true; } - // compile the smarty tag (required compile classes to compile the tag are autoloaded) + // compile the smarty tag (required compile classes to compile the tag are auto loaded) if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) { - if (isset($this->smarty->template_functions[$tag])) { + if (isset($this->parent_compiler->template->tpl_function[ $tag ])) { // template defined by {template} tag - $args['_attr']['name'] = "'" . $tag . "'"; + $args[ '_attr' ][ 'name' ] = "'" . $tag . "'"; $_output = $this->callTagCompiler('call', $args, $parameter); } } @@ -369,8 +591,8 @@ return null; } else { // map_named attributes - if (isset($args['_attr'])) { + if (isset($args[ '_attr' ])) { - foreach ($args['_attr'] as $key => $attribute) { + foreach ($args[ '_attr' ] as $key => $attribute) { if (is_array($attribute)) { $args = array_merge($args, $attribute); } @@ -379,22 +601,26 @@ // not an internal compiler tag if (strlen($tag) < 6 || substr($tag, - 5) != 'close') { // check if tag is a registered object - if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_method'])) { + if (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) { - $method = $parameter['object_method']; + $method = $parameter[ 'object_method' ]; - if (!in_array($method, $this->smarty->registered_objects[$tag][3]) && + if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ]) && - (empty($this->smarty->registered_objects[$tag][1]) || in_array($method, $this->smarty->registered_objects[$tag][1])) + (empty($this->smarty->registered_objects[ $tag ][ 1 ]) || + in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ])) ) { return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method); - } elseif (in_array($method, $this->smarty->registered_objects[$tag][3])) { + } elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) { - return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method); + return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, + $method); } else { // throw exception - $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' . $tag . '"', $this->lex->taglineno); + $this->trigger_template_error('not allowed method "' . $method . '" in registered object "' . + $tag . '"', null, true); } } // check if tag is registered - foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) { + foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) + { - if (isset($this->smarty->registered_plugins[$plugin_type][$tag])) { + if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) { // if compiler function plugin call it now if ($plugin_type == Smarty::PLUGIN_COMPILER) { $new_args = array(); @@ -402,30 +628,36 @@ if (is_array($mixed)) { $new_args = array_merge($new_args, $mixed); } else { - $new_args[$key] = $mixed; + $new_args[ $key ] = $mixed; } } - if (!$this->smarty->registered_plugins[$plugin_type][$tag][1]) { + if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) { $this->tag_nocache = true; } - $function = $this->smarty->registered_plugins[$plugin_type][$tag][0]; + $function = $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ]; if (!is_array($function)) { return $function($new_args, $this); - } elseif (is_object($function[0])) { + } elseif (is_object($function[ 0 ])) { - return $this->smarty->registered_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this); + return $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ][ 0 ]->{$function[ 1 ]}($new_args, + $this); } else { return call_user_func_array($function, array($new_args, $this)); } } // compile registered function or block function if ($plugin_type == Smarty::PLUGIN_FUNCTION || $plugin_type == Smarty::PLUGIN_BLOCK) { - return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag); + return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, + $tag); } } } // check plugins from plugins folder - foreach ($this->smarty->plugin_search_order as $plugin_type) { - if ($plugin_type == Smarty::PLUGIN_COMPILER && $this->smarty->loadPlugin('smarty_compiler_' . $tag) && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) { + foreach ($this->plugin_search_order as $plugin_type) { + if ($plugin_type == Smarty::PLUGIN_COMPILER && + $this->smarty->loadPlugin('smarty_compiler_' . $tag) && + (!isset($this->smarty->security_policy) || + $this->smarty->security_policy->isTrustedTag($tag, $this)) + ) { $plugin = 'smarty_compiler_' . $tag; if (is_callable($plugin)) { // convert arguments format for old compiler plugins @@ -434,7 +666,7 @@ if (is_array($mixed)) { $new_args = array_merge($new_args, $mixed); } else { - $new_args[$key] = $mixed; + $new_args[ $key ] = $mixed; } } @@ -449,8 +681,11 @@ throw new SmartyException("Plugin \"{$tag}\" not callable"); } else { if ($function = $this->getPlugin($tag, $plugin_type)) { - if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { - return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function); + if (!isset($this->smarty->security_policy) || + $this->smarty->security_policy->isTrustedTag($tag, $this) + ) { + return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, + $tag, $function); } } } @@ -458,15 +693,15 @@ if (is_callable($this->smarty->default_plugin_handler_func)) { $found = false; // look for already resolved tags - foreach ($this->smarty->plugin_search_order as $plugin_type) { + foreach ($this->plugin_search_order as $plugin_type) { - if (isset($this->default_handler_plugins[$plugin_type][$tag])) { + if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) { $found = true; break; } } if (!$found) { // call default handler - foreach ($this->smarty->plugin_search_order as $plugin_type) { + foreach ($this->plugin_search_order as $plugin_type) { if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) { $found = true; break; @@ -480,16 +715,18 @@ foreach ($args as $mixed) { $new_args = array_merge($new_args, $mixed); } - $function = $this->default_handler_plugins[$plugin_type][$tag][0]; + $function = $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ]; if (!is_array($function)) { return $function($new_args, $this); - } elseif (is_object($function[0])) { + } elseif (is_object($function[ 0 ])) { - return $this->default_handler_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this); + return $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ][ 0 ]->$function[ 1 ]($new_args, + $this); } else { return call_user_func_array($function, array($new_args, $this)); } } else { - return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag); + return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, + $tag); } } } @@ -497,35 +734,52 @@ // compile closing tag of block function $base_tag = substr($tag, 0, - 5); // check if closing tag is a registered object - if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_method'])) { + if (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) { - $method = $parameter['object_method']; + $method = $parameter[ 'object_method' ]; - if (in_array($method, $this->smarty->registered_objects[$base_tag][3])) { + if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) { - return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $method); + return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, + $method); } else { // throw exception - $this->trigger_template_error('not allowed closing tag method "' . $method . '" in registered object "' . $base_tag . '"', $this->lex->taglineno); + $this->trigger_template_error('not allowed closing tag method "' . $method . + '" in registered object "' . $base_tag . '"', null, true); } } // registered block tag ? - if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) || isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) { + if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ]) || + isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ]) + ) { return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag); } + // registered function tag ? + if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) { + return $this->callTagCompiler('private_registered_function', $args, $parameter, $tag); + } // block plugin? if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) { return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function); } + // function plugin? + if ($function = $this->getPlugin($tag, Smarty::PLUGIN_FUNCTION)) { + if (!isset($this->smarty->security_policy) || + $this->smarty->security_policy->isTrustedTag($tag, $this) + ) { + return $this->callTagCompiler('private_function_plugin', $args, $parameter, $tag, $function); + } + } // registered compiler plugin ? - if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) { + if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) { // if compiler function plugin call it now $args = array(); - if (!$this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][1]) { + if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) { $this->tag_nocache = true; } - $function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0]; + $function = $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ]; if (!is_array($function)) { return $function($args, $this); - } elseif (is_object($function[0])) { + } elseif (is_object($function[ 0 ])) { - return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($args, $this); + return $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ][ 0 ]->$function[ 1 ]($args, + $this); } else { return call_user_func_array($function, array($args, $this)); } @@ -544,15 +798,110 @@ throw new SmartyException("Plugin \"{$tag}\" not callable"); } } - $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex->taglineno); + $this->trigger_template_error("unknown tag \"" . $tag . "\"", null, true); } } /** + * compile variable + * + * @param string $variable + * + * @return string + */ + public function compileVariable($variable) + { + if (strpos($variable, '(') == 0) { + // not a variable variable + $var = trim($variable, '\''); + $this->tag_nocache = $this->tag_nocache | + $this->template->ext->getTemplateVars->_getVariable($this->template, $var, null, true, false)->nocache; + // todo $this->template->compiled->properties['variables'][$var] = $this->tag_nocache | $this->nocache; + } + return '$_smarty_tpl->tpl_vars[' . $variable . ']->value'; + } + + /** + * compile config variable + * + * @param string $variable + * + * @return string + */ + public function compileConfigVariable($variable) + { + // return '$_smarty_tpl->config_vars[' . $variable . ']'; + return '$_smarty_tpl->smarty->ext->configLoad->_getConfigVariable($_smarty_tpl, ' . $variable . ')'; + } + + /** + * This method is called from parser to process a text content section + * - remove text from inheritance child templates as they may generate output + * - strip text if strip is enabled + * + * @param string $text + * + * @return null|\Smarty_Internal_ParseTree_Text + */ + public function processText($text) + { + if ((string) $text != '') { + $store = array(); + $_store = 0; + $_offset = 0; + if ($this->parser->strip) { + if (strpos($text, '<') !== false) { + // capture html elements not to be messed with + $_offset = 0; + if (preg_match_all('#(]*>.*?]*>)|(]*>.*?]*>)|(]*>.*?]*>)#is', + $text, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { + foreach ($matches as $match) { + $store[] = $match[ 0 ][ 0 ]; + $_length = strlen($match[ 0 ][ 0 ]); + $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@'; + $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length); + + $_offset += $_length - strlen($replace); + $_store ++; + } + } + + $expressions = array(// replace multiple spaces between tags by a single space + // can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements + '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2', + // remove spaces between attributes (but not in attribute values!) + '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5', + '#^\s+<#Ss' => '<', + '#>\s+$#Ss' => '>', + $this->stripRegEx => ''); + + $text = preg_replace(array_keys($expressions), array_values($expressions), $text); + $_offset = 0; + if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $text, $matches, + PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { + foreach ($matches as $match) { + $_length = strlen($match[ 0 ][ 0 ]); + $replace = $store[ $match[ 1 ][ 0 ] ]; + $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length); + + $_offset += strlen($replace) - $_length; + $_store ++; + } + } + } else { + $text = preg_replace($this->stripRegEx, '', $text); + } + } + return new Smarty_Internal_ParseTree_Text($text); + } + return null; + } + + /** * lazy loads internal compile plugin for tag and calls the compile method * compile objects cached for reuse. * class name format: Smarty_Internal_Compile_TagName - * plugin filename format: Smarty_Internal_Tagname.php + * plugin filename format: Smarty_Internal_TagName.php * * @param string $tag tag name * @param array $args list of tag attributes @@ -565,23 +914,23 @@ public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null) { // re-use object if already exists - if (isset(self::$_tag_objects[$tag])) { - // compile this tag - return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); - } + if (!isset($this->_tag_objects[ $tag ])) { - // lazy load internal compiler plugin + // lazy load internal compiler plugin - $class_name = 'Smarty_Internal_Compile_' . $tag; - if ($this->smarty->loadPlugin($class_name)) { - // check if tag allowed by security - if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { - // use plugin if found - self::$_tag_objects[$tag] = new $class_name; - // compile this tag - return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); + $_tag = explode('_', $tag); + $_tag = array_map('ucfirst', $_tag); + $class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag); + if (class_exists($class_name) && + (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) + ) { + $this->_tag_objects[ $tag ] = new $class_name; + } else { + $this->_tag_objects[ $tag ] = false; + return false; } } - // no internal compile plugin for this tag - return false; + // compile this tag + return $this->_tag_objects[ $tag ] === false ? false : + $this->_tag_objects[ $tag ]->compile($args, $this, $param1, $param2, $param3); } /** @@ -596,23 +945,29 @@ { $function = null; if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { - if (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) { - $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function']; - } elseif (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) { - $this->template->required_plugins['nocache'][$plugin_name][$plugin_type] = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]; - $function = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function']; + if (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) { + $function = + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ]; + } elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) { + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] = + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ]; + $function = + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ]; } } else { - if (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) { - $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function']; - } elseif (isset($this->template->required_plugins['nocache'][$plugin_name][$plugin_type])) { - $this->template->required_plugins['compiled'][$plugin_name][$plugin_type] = $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]; - $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function']; + if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) { + $function = + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ]; + } elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) { + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] = + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ]; + $function = + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ]; } } if (isset($function)) { if ($plugin_type == 'modifier') { - $this->modifier_plugins[$plugin_name] = true; + $this->modifier_plugins[ $plugin_name ] = true; } return $function; @@ -623,14 +978,18 @@ if (is_string($file)) { if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { - $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['file'] = $file; - $this->template->required_plugins['nocache'][$plugin_name][$plugin_type]['function'] = $function; + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] = + $file; + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] = + $function; } else { - $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] = $file; - $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] = $function; + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] = + $file; + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] = + $function; } if ($plugin_type == 'modifier') { - $this->modifier_plugins[$plugin_name] = true; + $this->modifier_plugins[ $plugin_name ] = true; } return $function; @@ -656,30 +1015,35 @@ $callback = null; $script = null; $cacheable = true; - $result = call_user_func_array( - $this->smarty->default_plugin_handler_func, array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable) - ); + $result = call_user_func_array($this->smarty->default_plugin_handler_func, + array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable)); if ($result) { $this->tag_nocache = $this->tag_nocache || !$cacheable; if ($script !== null) { if (is_file($script)) { if ($this->template->caching && ($this->nocache || $this->tag_nocache)) { - $this->template->required_plugins['nocache'][$tag][$plugin_type]['file'] = $script; - $this->template->required_plugins['nocache'][$tag][$plugin_type]['function'] = $callback; + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] = + $script; + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] = + $callback; } else { - $this->template->required_plugins['compiled'][$tag][$plugin_type]['file'] = $script; - $this->template->required_plugins['compiled'][$tag][$plugin_type]['function'] = $callback; + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] = + $script; + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] = + $callback; } - include_once $script; + require_once $script; } else { $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found"); } } - if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) { + if (!is_string($callback) && + !(is_array($callback) && is_string($callback[ 0 ]) && is_string($callback[ 1 ])) + ) { $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name"); } if (is_callable($callback)) { - $this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array()); + $this->default_handler_plugins[ $plugin_type ][ $tag ] = array($callback, true, array()); return true; } else { @@ -691,6 +1055,44 @@ } /** + * Append code segments and remove unneeded ?> \s*$/', $left) && preg_match('/^\s*<\?php\s+/', $right)) { + $left = preg_replace('/\s*\?>\s*$/', "\n", $left); + $left .= preg_replace('/^\s*<\?php\s+/', '', $right); + } else { + $left .= $right; + } + return $left; + } + + /** + * Append code segments and remove unneeded ?> \s*$/', $left) && preg_match('/^\s*<\?php\s+/', $right)) { + $left = preg_replace('/\s*\?>\s*$/', "\n", $left); + $left .= preg_replace('/^\s*<\?php\s+/', '', $right); + } else { + $left .= $right; + } + return $left; + } + + /** * Inject inline code for nocache template sections * This method gets the content of each template element from the parser. * If the content is compiled code and it should be not cached the code is injected @@ -706,17 +1108,19 @@ // If the template is not evaluated and we have a nocache section and or a nocache tag if ($is_code && !empty($content)) { // generate replacement code - if ((!($this->template->source->recompiled) || $this->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing && - ($this->nocache || $this->tag_nocache) + if ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->template->caching && + !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache) ) { - $this->template->has_nocache_code = true; + $this->template->compiled->has_nocache_code = true; $_output = addcslashes($content, '\'\\'); $_output = str_replace("^#^", "'", $_output); - $_output = "nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n"; + $_output = "nocache_hash}%%*/" . $_output . + "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n"; // make sure we include modifier plugins for nocache code foreach ($this->modifier_plugins as $plugin_name => $dummy) { - if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) { - $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier']; + if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) { + $this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] = + $this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ]; } } } else { @@ -733,44 +1137,46 @@ } /** - * push current file and line offset on stack for tracing {block} source lines + * Get Id * - * @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 $input + * + * @return bool|string */ - public function pushTrace($file, $uid, $line, $debug = true) + public function getId($input) { - if ($this->smarty->debugging && $debug) { - Smarty_Internal_Debug::end_compile($this->template); + if (preg_match('~^[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*$~', $input, $match)) { + return $match[ 1 ]; } - array_push($this->trace_stack, array($this->smarty->_current_file, $this->trace_filepath, $this->trace_uid, $this->trace_line_offset)); - $this->trace_filepath = $this->smarty->_current_file = $file; - $this->trace_uid = $uid; - $this->trace_line_offset = $line; - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_compile($this->template); + return false; - } + } - } /** - * restore file and line offset - + * Get variable name from string + * + * @param string $input + * + * @return bool|string */ - public function popTrace() + public function getVariableName($input) { - if ($this->smarty->debugging) { - Smarty_Internal_Debug::end_compile($this->template); + if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) { + return $match[ 1 ]; } - $r = array_pop($this->trace_stack); - $this->smarty->_current_file = $r[0]; - $this->trace_filepath = $r[1]; - $this->trace_uid = $r[2]; - $this->trace_line_offset = $r[3]; - if ($this->smarty->debugging) { - Smarty_Internal_Debug::start_compile($this->template); + return false; - } + } + + /** + * Generate nocache code string + * + * @param string $code PHP code + * + * @return string + */ + public function makeNocacheCode($code) + { + return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*//*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n"; } /** @@ -779,35 +1185,59 @@ * In this case the parser is called to obtain information about expected tokens. * If parameter $args contains a string this is used as error message * - * @param string $args individual error message or null + * @param string $args individual error message or null - * @param string $line line-number + * @param string $line line-number + * @param null|bool $tagline if true the line number of last tag * - * @throws SmartyCompilerException when an unexpected token is found + * @throws \SmartyCompilerException when an unexpected token is found */ - public function trigger_template_error($args = null, $line = null) + public function trigger_template_error($args = null, $line = null, $tagline = null) { + $lex = $this->parser->lex; + if ($tagline === true) { + // get line number of Tag + $line = $lex->taglineno; + } elseif (!isset($line)) { - // get template source line which has error + // get template source line which has error - if (!isset($line)) { - $line = $this->lex->line; + $line = $lex->line; + } else { + $line = (int) $line; + $line = $lex->line; + } else { + $line = (int) $line; } + + if (in_array($this->template->source->type, array('eval', 'string'))) { + $templateName = $this->template->source->type . ':' . trim(preg_replace('![\t\r\n]+!', ' ', + strlen($lex->data) > 40 ? + substr($lex->data, 0, 40) . + '...' : $lex->data)); + } else { + $templateName = $this->template->source->type . ':' . $this->template->source->filepath; + } + // $line += $this->trace_line_offset; - $match = preg_split("/\n/", $this->lex->data); - $error_text = 'Syntax error in template "' . (empty($this->trace_filepath) ? $this->template->source->filepath : $this->trace_filepath) . '" on line ' . ($line + $this->trace_line_offset) . ' "' . trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])) . '" '; + $match = preg_split("/\n/", $lex->data); + $error_text = + 'Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) . + '" on line ' . ($line + $this->trace_line_offset) . ' "' . + trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" '; if (isset($args)) { // individual error message $error_text .= $args; } else { + $expect = array(); // expected token from parser - $error_text .= ' - Unexpected "' . $this->lex->value . '"'; + $error_text .= ' - Unexpected "' . $lex->value . '"'; if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) { foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) { - $exp_token = $this->parser->yyTokenName[$token]; + $exp_token = $this->parser->yyTokenName[ $token ]; - if (isset($this->lex->smarty_token_names[$exp_token])) { + if (isset($lex->smarty_token_names[ $exp_token ])) { // token type from lexer - $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"'; + $expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"'; } else { // otherwise internal token name - $expect[] = $this->parser->yyTokenName[$token]; + $expect[] = $this->parser->yyTokenName[ $token ]; } } $error_text .= ', expected one of: ' . implode(' , ', $expect); @@ -815,7 +1245,7 @@ } $e = new SmartyCompilerException($error_text); $e->line = $line; - $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])); + $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])); $e->desc = $args; $e->template = $this->template->source->filepath; throw $e; Index: src/includes/classes/Smarty/sysplugins/smarty_resource.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_resource.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_resource.php (revision Shelved version) @@ -17,36 +17,37 @@ abstract class Smarty_Resource { /** - * cache for Smarty_Template_Source instances + * Source is bypassing compiler * - * @var array + * @var boolean */ - public static $sources = array(); + public $uncompiled = false; + /** - * cache for Smarty_Template_Compiled instances + * Source must be recompiled on every occasion * - * @var array + * @var boolean */ - public static $compileds = array(); + public $recompiled = false; + /** - * cache for Smarty_Resource instances + * resource types provided by the core * * @var array */ - public static $resources = array(); + public static $sysplugins = array('file' => 'smarty_internal_resource_file.php', + 'string' => 'smarty_internal_resource_string.php', + 'extends' => 'smarty_internal_resource_extends.php', + 'stream' => 'smarty_internal_resource_stream.php', + 'eval' => 'smarty_internal_resource_eval.php', + 'php' => 'smarty_internal_resource_php.php'); + /** - * resource types provided by the core + * Flag if resource does implement populateCompiledFilepath() method * - * @var array + * @var bool */ - protected static $sysplugins = array( - 'file' => true, - 'string' => true, - 'extends' => true, - 'stream' => true, - 'eval' => true, - 'php' => true - ); + public $hasCompiledHandler = false; /** * Name of the Class to compile this resource's contents with @@ -71,7 +72,6 @@ /** * Load template's source into current template object - * {@internal The loaded source is assigned to $_template->source->content directly.}} * * @param Smarty_Template_Source $source source object * @@ -103,278 +103,33 @@ * * @param Smarty $smarty Smarty instance * @param string $resource_name resource_name to make unique - * @param boolean $is_config flag for config resource + * @param boolean $isConfig flag for config resource * * @return string unique resource name */ - protected function buildUniqueResourceName(Smarty $smarty, $resource_name, $is_config = false) + public function buildUniqueResourceName(Smarty $smarty, $resource_name, $isConfig = false) { - if ($is_config) { - return get_class($this) . '#' . $smarty->joined_config_dir . '#' . $resource_name; - } else { - return get_class($this) . '#' . $smarty->joined_template_dir . '#' . $resource_name; + if ($isConfig) { + if (!isset($smarty->_joined_config_dir)) { + $smarty->getTemplateDir(null, true); - } + } - } - - /** - * populate Compiled Object with compiled filepath - * - * @param Smarty_Template_Compiled $compiled compiled object - * @param Smarty_Internal_Template $_template template object - */ - public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template) - { - $_compile_id = isset($_template->compile_id) ? preg_replace('![^\w\|]+!', '_', $_template->compile_id) : null; - $_filepath = $compiled->source->uid; - // if use_sub_dirs, break file into directories - if ($_template->smarty->use_sub_dirs) { - $_filepath = substr($_filepath, 0, 2) . DS - . substr($_filepath, 2, 2) . DS - . substr($_filepath, 4, 2) . DS - . $_filepath; - } - $_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^'; - if (isset($_compile_id)) { - $_filepath = $_compile_id . $_compile_dir_sep . $_filepath; - } - // caching token - if ($_template->caching) { - $_cache = '.cache'; + return get_class($this) . '#' . $smarty->_joined_config_dir . '#' . $resource_name; } else { - $_cache = ''; + if (!isset($smarty->_joined_template_dir)) { + $smarty->getTemplateDir(); - } + } - $_compile_dir = $_template->smarty->getCompileDir(); - // set basename if not specified - $_basename = $this->getBasename($compiled->source); - if ($_basename === null) { - $_basename = basename(preg_replace('![^\w\/]+!', '_', $compiled->source->name)); + return get_class($this) . '#' . $smarty->_joined_template_dir . '#' . $resource_name; } - // separate (optional) basename by dot - if ($_basename) { - $_basename = '.' . $_basename; - } + } - $compiled->filepath = $_compile_dir . $_filepath . '.' . $compiled->source->type . $_basename . $_cache . '.php'; - } - /** - * Normalize Paths "foo/../bar" to "bar" - * - * @param string $_path path to normalize - * @param boolean $ds respect windows directory separator - * - * @return string normalized path - */ - protected function normalizePath($_path, $ds = true) - { - if ($ds) { - // don't we all just love windows? - $_path = str_replace('\\', '/', $_path); - } - - $offset = 0; - - // resolve simples - $_path = preg_replace('#/\./(\./)*#', '/', $_path); - // resolve parents - while (true) { - $_parent = strpos($_path, '/../', $offset); - if (!$_parent) { - break; - } elseif ($_path[$_parent - 1] === '.') { - $offset = $_parent + 3; - continue; - } - - $_pos = strrpos($_path, '/', $_parent - strlen($_path) - 1); - if ($_pos === false) { - // don't we all just love windows? - $_pos = $_parent; - } - - $_path = substr_replace($_path, '', $_pos, $_parent + 3 - $_pos); - } - - if ($ds && DS != '/') { - // don't we all just love windows? - $_path = str_replace('/', '\\', $_path); - } - - return $_path; - } - - /** - * build template filepath by traversing the template_dir array - * - * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object - * - * @return string fully qualified filepath - * @throws SmartyException if default template handler is registered but not callable - */ - protected function buildFilepath(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null) - { - $file = $source->name; - if ($source instanceof Smarty_Config_Source) { - $_directories = $source->smarty->getConfigDir(); - $_default_handler = $source->smarty->default_config_handler_func; - } else { - $_directories = $source->smarty->getTemplateDir(); - $_default_handler = $source->smarty->default_template_handler_func; - } - - // go relative to a given template? - $_file_is_dotted = $file[0] == '.' && ($file[1] == '.' || $file[1] == '/' || $file[1] == "\\"); - if ($_template && $_template->parent instanceof Smarty_Internal_Template && $_file_is_dotted) { - if ($_template->parent->source->type != 'file' && $_template->parent->source->type != 'extends' && !$_template->parent->allow_relative_path) { - throw new SmartyException("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->source->type}'"); - } - $file = dirname($_template->parent->source->filepath) . DS . $file; - $_file_exact_match = true; - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) { - // the path gained from the parent template is relative to the current working directory - // as expansions (like include_path) have already been done - $file = getcwd() . DS . $file; - } - } - - // resolve relative path - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) { - // don't we all just love windows? - $_path = DS . trim($file, '/'); - $_was_relative = true; - } else { - // don't we all just love windows? - $_path = str_replace('\\', '/', $file); - } - $_path = $this->normalizePath($_path, false); - if (DS != '/') { - // don't we all just love windows? - $_path = str_replace('/', '\\', $_path); - } - // revert to relative - if (isset($_was_relative)) { - $_path = substr($_path, 1); - } - - // this is only required for directories - $file = rtrim($_path, '/\\'); - - // files relative to a template only get one shot - if (isset($_file_exact_match)) { - return $this->fileExists($source, $file) ? $file : false; - } - - // template_dir index? - if (preg_match('#^\[(?P[^\]]+)\](?P.+)$#', $file, $match)) { - $_directory = null; - // try string indexes - if (isset($_directories[$match['key']])) { - $_directory = $_directories[$match['key']]; - } elseif (is_numeric($match['key'])) { - // try numeric index - $match['key'] = (int) $match['key']; - if (isset($_directories[$match['key']])) { - $_directory = $_directories[$match['key']]; - } else { - // try at location index - $keys = array_keys($_directories); - $_directory = $_directories[$keys[$match['key']]]; - } - } - - if ($_directory) { - $_file = substr($file, strpos($file, ']') + 1); - $_filepath = $_directory . $_file; - if ($this->fileExists($source, $_filepath)) { - return $_filepath; - } - } - } - - $_stream_resolve_include_path = function_exists('stream_resolve_include_path'); - - // relative file name? - if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $file)) { - foreach ($_directories as $_directory) { - $_filepath = $_directory . $file; - if ($this->fileExists($source, $_filepath)) { - return $this->normalizePath($_filepath); - } - if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) { - // try PHP include_path - if ($_stream_resolve_include_path) { - $_filepath = stream_resolve_include_path($_filepath); - } else { - $_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath); - } - - if ($_filepath !== false) { - if ($this->fileExists($source, $_filepath)) { - return $this->normalizePath($_filepath); - } - } - } - } - } - - // try absolute filepath - if ($this->fileExists($source, $file)) { - return $file; - } - - // no tpl file found - if ($_default_handler) { - if (!is_callable($_default_handler)) { - if ($source instanceof Smarty_Config_Source) { - throw new SmartyException("Default config handler not callable"); - } else { - throw new SmartyException("Default template handler not callable"); - } - } - $_return = call_user_func_array($_default_handler, - array($source->type, $source->name, &$_content, &$_timestamp, $source->smarty)); - if (is_string($_return)) { - $source->timestamp = @filemtime($_return); - $source->exists = !!$source->timestamp; - - return $_return; - } elseif ($_return === true) { - $source->content = $_content; - $source->timestamp = $_timestamp; - $source->exists = true; - - return $_filepath; - } - } - - // give up - return false; - } - - /** - * test is file exists and save timestamp - * - * @param Smarty_Template_Source $source source object - * @param string $file file name - * - * @return bool true if file exists - */ - protected function fileExists(Smarty_Template_Source $source, $file) - { - $source->timestamp = is_file($file) ? @filemtime($file) : false; - - return $source->exists = !!$source->timestamp; - } - - /** * Determine basename for compiled filename * * @param Smarty_Template_Source $source source object * * @return string resource's basename */ - protected function getBasename(Smarty_Template_Source $source) + public function getBasename(Smarty_Template_Source $source) { return null; } @@ -391,57 +146,32 @@ public static function load(Smarty $smarty, $type) { // try smarty's cache - if (isset($smarty->_resource_handlers[$type])) { - return $smarty->_resource_handlers[$type]; + if (isset($smarty->_cache['resource_handlers'][$type])) { + return $smarty->_cache['resource_handlers'][$type]; } // try registered resource if (isset($smarty->registered_resources[$type])) { - if ($smarty->registered_resources[$type] instanceof Smarty_Resource) { - $smarty->_resource_handlers[$type] = $smarty->registered_resources[$type]; - // note registered to smarty is not kept unique! - return $smarty->_resource_handlers[$type]; + return $smarty->_cache['resource_handlers'][$type] = + $smarty->registered_resources[$type] instanceof Smarty_Resource ? $smarty->registered_resources[$type] : + new Smarty_Internal_Resource_Registered(); - } + } - if (!isset(self::$resources['registered'])) { - self::$resources['registered'] = new Smarty_Internal_Resource_Registered(); - } - if (!isset($smarty->_resource_handlers[$type])) { - $smarty->_resource_handlers[$type] = self::$resources['registered']; - } - - return $smarty->_resource_handlers[$type]; - } - // try sysplugins dir if (isset(self::$sysplugins[$type])) { - if (!isset(self::$resources[$type])) { - $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type); + $_resource_class = 'Smarty_Internal_Resource_' . ucfirst($type); - self::$resources[$type] = new $_resource_class(); + return $smarty->_cache['resource_handlers'][$type] = new $_resource_class(); - } + } - return $smarty->_resource_handlers[$type] = self::$resources[$type]; - } - // try plugins dir $_resource_class = 'Smarty_Resource_' . ucfirst($type); if ($smarty->loadPlugin($_resource_class)) { - if (isset(self::$resources[$type])) { - return $smarty->_resource_handlers[$type] = self::$resources[$type]; - } - if (class_exists($_resource_class, false)) { - self::$resources[$type] = new $_resource_class(); - - return $smarty->_resource_handlers[$type] = self::$resources[$type]; + return $smarty->_cache['resource_handlers'][$type] = new $_resource_class(); } else { - $smarty->registerResource($type, array( - "smarty_resource_{$type}_source", - "smarty_resource_{$type}_timestamp", - "smarty_resource_{$type}_secure", - "smarty_resource_{$type}_trusted" - )); - + $smarty->registerResource($type, + array("smarty_resource_{$type}_source", "smarty_resource_{$type}_timestamp", + "smarty_resource_{$type}_secure", "smarty_resource_{$type}_trusted")); // give it another try, now that the resource is registered properly return self::load($smarty, $type); } @@ -454,13 +184,9 @@ if (is_object($smarty->security_policy)) { $smarty->security_policy->isTrustedStream($type); } - if (!isset(self::$resources['stream'])) { - self::$resources['stream'] = new Smarty_Internal_Resource_Stream(); + return $smarty->_cache['resource_handlers'][$type] = new Smarty_Internal_Resource_Stream(); - } + } - return $smarty->_resource_handlers[$type] = self::$resources['stream']; - } - // TODO: try default_(template|config)_handler // give up @@ -473,57 +199,60 @@ * * @param string $resource_name template_resource or config_resource to parse * @param string $default_resource the default resource_type defined in $smarty - * @param string &$name the parsed resource name - * @param string &$type the parsed resource type * - * @return void + * @return array with parsed resource name and type */ - protected static function parseResourceName($resource_name, $default_resource, &$name, &$type) + public static function parseResourceName($resource_name, $default_resource) { - $parts = explode(':', $resource_name, 2); - if (!isset($parts[1]) || !isset($parts[0][1])) { + if (preg_match('/^([A-Za-z0-9_\-]{2,})[:]/', $resource_name, $match)) { + $type = $match[1]; + $name = substr($resource_name, strlen($match[0])); + } else { // no resource given, use default // or single character before the colon is not a resource type, but part of the filepath $type = $default_resource; $name = $resource_name; - } else { - $type = $parts[0]; - $name = $parts[1]; } + return array($name, $type); } /** - * modify resource_name according to resource handlers specifications - * - * @param Smarty $smarty Smarty instance - * @param string $resource_name resource_name to make unique - * - * @return string unique resource name - */ - - /** * modify template_resource according to resource handlers specifications * - * @param Smarty_Internal_template $template Smarty instance + * @param \Smarty_Internal_Template|\Smarty $obj Smarty instance - * @param string $template_resource template_resource to extract resource handler and name of + * @param string $template_resource template_resource to extract resource handler and name of * * @return string unique resource name */ - public static function getUniqueTemplateName($template, $template_resource) + public static function getUniqueTemplateName($obj, $template_resource) { - self::parseResourceName($template_resource, $template->smarty->default_resource_type, $name, $type); + $smarty = $obj->_objType == 2 ? $obj->smarty : $obj; + list($name, $type) = self::parseResourceName($template_resource, $smarty->default_resource_type); // TODO: optimize for Smarty's internal resource types - $resource = Smarty_Resource::load($template->smarty, $type); + $resource = Smarty_Resource::load($smarty, $type); // go relative to a given template? - $_file_is_dotted = $name[0] == '.' && ($name[1] == '.' || $name[1] == '/' || $name[1] == "\\"); - if ($template instanceof Smarty_Internal_Template && $_file_is_dotted && ($template->source->type == 'file' || $template->parent->source->type == 'extends')) { - $name = dirname($template->source->filepath) . DS . $name; + $_file_is_dotted = $name[0] == '.' && ($name[1] == '.' || $name[1] == '/'); + if ($obj->_objType == 2 && $_file_is_dotted && + ($obj->source->type == 'file' || $obj->parent->source->type == 'extends') + ) { + $name = dirname($obj->source->filepath) . DS . $name; } - return $resource->buildUniqueResourceName($template->smarty, $name); + return $resource->buildUniqueResourceName($smarty, $name); } + /* + * Check if resource must check time stamps when when loading complied or cached templates. + * Resources like 'extends' which use source components my disable timestamp checks on own resource. + * + * @return bool + */ + public function checkTimestamps() { + return true; + } + /** * initialize Source Object for given resource + * wrapper for backward compatibility to versions < 3.1.22 * Either [$_template] or [$smarty, $template_resource] must be specified * * @param Smarty_Internal_Template $_template template object @@ -532,381 +261,10 @@ * * @return Smarty_Template_Source Source Object */ - public static function source(Smarty_Internal_Template $_template = null, Smarty $smarty = null, $template_resource = null) + public static function source(Smarty_Internal_Template $_template = null, Smarty $smarty = null, + $template_resource = null) { - if ($_template) { - $smarty = $_template->smarty; - $template_resource = $_template->template_resource; + return Smarty_Template_Source::load($_template, $smarty, $template_resource); - } + } - - // parse resource_name, load resource handler, identify unique resource name - self::parseResourceName($template_resource, $smarty->default_resource_type, $name, $type); - $resource = Smarty_Resource::load($smarty, $type); - // go relative to a given template? - $_file_is_dotted = isset($name[0]) && $name[0] == '.' && ($name[1] == '.' || $name[1] == '/' || $name[1] == "\\"); - if ($_file_is_dotted && isset($_template) && $_template->parent instanceof Smarty_Internal_Template && ($_template->parent->source->type == 'file' || $_template->parent->source->type == 'extends')) { - $name2 = dirname($_template->parent->source->filepath) . DS . $name; - } else { - $name2 = $name; - } +} - $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name2); - // check runtime cache - $_cache_key = 'template|' . $unique_resource_name; - if ($smarty->compile_id) { - $_cache_key .= '|' . $smarty->compile_id; - } - if (isset(self::$sources[$_cache_key])) { - return self::$sources[$_cache_key]; - } - - // create source - $source = new Smarty_Template_Source($resource, $smarty, $template_resource, $type, $name, $unique_resource_name); - $resource->populate($source, $_template); - - // runtime cache - self::$sources[$_cache_key] = $source; - - return $source; - } - - /** - * initialize Config Source Object for given resource - * - * @param Smarty_Internal_Config $_config config object - * - * @throws SmartyException - * @return Smarty_Config_Source Source Object - */ - public static function config(Smarty_Internal_Config $_config) - { - static $_incompatible_resources = array('eval' => true, 'string' => true, 'extends' => true, 'php' => true); - $config_resource = $_config->config_resource; - $smarty = $_config->smarty; - - // parse resource_name - self::parseResourceName($config_resource, $smarty->default_config_type, $name, $type); - - // make sure configs are not loaded via anything smarty can't handle - if (isset($_incompatible_resources[$type])) { - throw new SmartyException ("Unable to use resource '{$type}' for config"); - } - - // load resource handler, identify unique resource name - $resource = Smarty_Resource::load($smarty, $type); - $unique_resource_name = $resource->buildUniqueResourceName($smarty, $name, true); - - // check runtime cache - $_cache_key = 'config|' . $unique_resource_name; - if (isset(self::$sources[$_cache_key])) { - return self::$sources[$_cache_key]; - } - - // create source - $source = new Smarty_Config_Source($resource, $smarty, $config_resource, $type, $name, $unique_resource_name); - $resource->populate($source, null); - - // runtime cache - self::$sources[$_cache_key] = $source; - - return $source; - } -} - -/** - * Smarty Resource Data Object - * Meta Data Container for Template Files - * - * @package Smarty - * @subpackage TemplateResources - * @author Rodney Rehm - * @property integer $timestamp Source Timestamp - * @property boolean $exists Source Existence - * @property boolean $template Extended Template reference - * @property string $content Source Content - */ -class Smarty_Template_Source -{ - /** - * Name of the Class to compile this resource's contents with - * - * @var string - */ - public $compiler_class = null; - - /** - * Name of the Class to tokenize this resource's contents with - * - * @var string - */ - public $template_lexer_class = null; - - /** - * Name of the Class to parse this resource's contents with - * - * @var string - */ - public $template_parser_class = null; - - /** - * Unique Template ID - * - * @var string - */ - public $uid = null; - - /** - * Template Resource (Smarty_Internal_Template::$template_resource) - * - * @var string - */ - public $resource = null; - - /** - * Resource Type - * - * @var string - */ - public $type = null; - - /** - * Resource Name - * - * @var string - */ - public $name = null; - - /** - * Unique Resource Name - * - * @var string - */ - public $unique_resource = null; - - /** - * Source Filepath - * - * @var string - */ - public $filepath = null; - - /** - * Source is bypassing compiler - * - * @var boolean - */ - public $uncompiled = null; - - /** - * Source must be recompiled on every occasion - * - * @var boolean - */ - public $recompiled = null; - - /** - * The Components an extended template is made of - * - * @var array - */ - public $components = null; - - /** - * Resource Handler - * - * @var Smarty_Resource - */ - public $handler = null; - - /** - * Smarty instance - * - * @var Smarty - */ - public $smarty = null; - - /** - * create Source Object container - * - * @param Smarty_Resource $handler Resource Handler this source object communicates with - * @param Smarty $smarty Smarty instance this source object belongs to - * @param string $resource full template_resource - * @param string $type type of resource - * @param string $name resource name - * @param string $unique_resource unique resource name - */ - public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name, $unique_resource) - { - $this->handler = $handler; // Note: prone to circular references - - $this->compiler_class = $handler->compiler_class; - $this->template_lexer_class = $handler->template_lexer_class; - $this->template_parser_class = $handler->template_parser_class; - $this->uncompiled = $this->handler instanceof Smarty_Resource_Uncompiled; - $this->recompiled = $this->handler instanceof Smarty_Resource_Recompiled; - - $this->smarty = $smarty; - $this->resource = $resource; - $this->type = $type; - $this->name = $name; - $this->unique_resource = $unique_resource; - } - - /** - * get a Compiled Object of this source - * - * @param Smarty_Internal_Template|Smarty_Internal_Config $_template template object - * - * @return Smarty_Template_Compiled compiled object - */ - public function getCompiled($_template) - { - // check runtime cache - $_cache_key = $this->unique_resource . '#' . $_template->compile_id; - if (isset(Smarty_Resource::$compileds[$_cache_key])) { - return Smarty_Resource::$compileds[$_cache_key]; - } - - $compiled = new Smarty_Template_Compiled($this); - $this->handler->populateCompiledFilepath($compiled, $_template); - $compiled->timestamp = @filemtime($compiled->filepath); - $compiled->exists = !!$compiled->timestamp; - - // runtime cache - Smarty_Resource::$compileds[$_cache_key] = $compiled; - - return $compiled; - } - - /** - * render the uncompiled source - * - * @param Smarty_Internal_Template $_template template object - */ - public function renderUncompiled(Smarty_Internal_Template $_template) - { - return $this->handler->renderUncompiled($this, $_template); - } - - /** - * <> Generic Setter. - * - * @param string $property_name valid: timestamp, exists, content, template - * @param mixed $value new value (is not checked) - * - * @throws SmartyException if $property_name is not valid - */ - public function __set($property_name, $value) - { - switch ($property_name) { - // regular attributes - case 'timestamp': - case 'exists': - case 'content': - // required for extends: only - case 'template': - $this->$property_name = $value; - break; - - default: - throw new SmartyException("invalid source property '$property_name'."); - } - } - - /** - * <> Generic getter. - * - * @param string $property_name valid: timestamp, exists, content - * - * @return mixed - * @throws SmartyException if $property_name is not valid - */ - public function __get($property_name) - { - switch ($property_name) { - case 'timestamp': - case 'exists': - $this->handler->populateTimestamp($this); - - return $this->$property_name; - - case 'content': - return $this->content = $this->handler->getContent($this); - - default: - throw new SmartyException("source property '$property_name' does not exist."); - } - } -} - -/** - * Smarty Resource Data Object - * Meta Data Container for Template Files - * - * @package Smarty - * @subpackage TemplateResources - * @author Rodney Rehm - * @property string $content compiled content - */ -class Smarty_Template_Compiled -{ - /** - * Compiled Filepath - * - * @var string - */ - public $filepath = null; - - /** - * Compiled Timestamp - * - * @var integer - */ - public $timestamp = null; - - /** - * Compiled Existence - * - * @var boolean - */ - public $exists = false; - - /** - * Compiled Content Loaded - * - * @var boolean - */ - public $loaded = false; - - /** - * Template was compiled - * - * @var boolean - */ - public $isCompiled = false; - - /** - * Source Object - * - * @var Smarty_Template_Source - */ - public $source = null; - - /** - * Metadata properties - * populated by Smarty_Internal_Template::decodeProperties() - * - * @var array - */ - public $_properties = null; - - /** - * create Compiled Object container - * - * @param Smarty_Template_Source $source source object this compiled object belongs to - */ - public function __construct(Smarty_Template_Source $source) - { - $this->source = $source; - } -} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_extends.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_extends.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_extends.php (revision Shelved version) @@ -15,7 +15,7 @@ * @package Smarty * @subpackage Compiler */ -class Smarty_Internal_Compile_Extends extends Smarty_Internal_CompileBase +class Smarty_Internal_Compile_Extends extends Smarty_Internal_Compile_Shared_Inheritance { /** * Attribute definition: Overwrites base class. @@ -24,7 +24,24 @@ * @see Smarty_Internal_CompileBase */ public $required_attributes = array('file'); + /** + * Array of names of optional attribute required by tag + * use array('_any') if there is no restriction of attributes names + * + * @var array + */ + public $optional_attributes = array('extends_resource'); + + /** + * Array of names of optional attribute required by tag + * use array('_any') if there is no restriction of attributes names + * + * @var array + */ + public $optional_attributes = array('extends_resource'); + + /** * Attribute definition: Overwrites base class. * * @var array @@ -33,53 +50,93 @@ public $shorttag_order = array('file'); /** - * Compiles code for the {extends} tag + * Compiles code for the {extends} tag extends: resource * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object * * @return string compiled code + * @throws \SmartyCompilerException + * @throws \SmartyException */ - public function compile($args, $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) { // check and get attributes $_attr = $this->getAttributes($compiler, $args); if ($_attr['nocache'] === true) { - $compiler->trigger_template_error('nocache option not allowed', $compiler->lex->taglineno); + $compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->line - 1); } if (strpos($_attr['file'], '$_tmp') !== false) { - $compiler->trigger_template_error('illegal value for file attribute', $compiler->lex->taglineno); + $compiler->trigger_template_error('illegal value for file attribute', $compiler->parser->lex->line - 1); } - - $name = $_attr['file']; - /** @var Smarty_Internal_Template $_smarty_tpl - * used in evaluated code - */ - $_smarty_tpl = $compiler->template; - eval("\$tpl_name = $name;"); - // create template object - $_template = new $compiler->smarty->template_class($tpl_name, $compiler->smarty, $compiler->template); - // check for recursion - $uid = $_template->source->uid; - if (isset($compiler->extends_uid[$uid])) { - $compiler->trigger_template_error("illegal recursive call of \"$include_file\"", $compiler->lex->line - 1); - } - $compiler->extends_uid[$uid] = true; - if (empty($_template->source->components)) { - array_unshift($compiler->sources, $_template->source); + // add code to initialize inheritance + $this->registerInit($compiler, true); + $file = trim($_attr['file'], '\'"'); + if (strlen($file) > 8 && substr($file, 0, 8) == 'extends:') { + // generate code for each template + $files = array_reverse(explode('|', substr($file, 8))); + $i = 0; + foreach ($files as $file) { + if ($file[0] == '"') { + $file = trim($file, '".'); - } else { + } else { - foreach ($_template->source->components as $source) { - array_unshift($compiler->sources, $source); - $uid = $source->uid; - if (isset($compiler->extends_uid[$uid])) { - $compiler->trigger_template_error("illegal recursive call of \"{$source->filepath}\"", $compiler->lex->line - 1); + $file = "'{$file}'"; } - $compiler->extends_uid[$uid] = true; + $i ++; + if ($i == count($files) && isset($_attr['extends_resource'])) { + $this->compileEndChild($compiler); - } + } + $this->compileInclude($compiler, $file); - } + } - unset ($_template); - $compiler->inheritance_child = true; - $compiler->lex->yypushstate(Smarty_Internal_Templatelexer::CHILDBODY); + if (!isset($_attr['extends_resource'])) { + $this->compileEndChild($compiler); + } + } else { + $this->compileEndChild($compiler); + $this->compileInclude($compiler, $_attr['file']); + } + $compiler->has_code = false; return ''; + } + + /** + * Add code for inheritance endChild() method to end of template + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + */ + private function compileEndChild(Smarty_Internal_TemplateCompilerBase $compiler) + { + $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser, + "ext->_inheritance->endChild(\$_smarty_tpl);\n?>\n"); + } + + /** + * Add code for including subtemplate to end of template + * + * @param \Smarty_Internal_TemplateCompilerBase $compiler + * @param string $file subtemplate name + */ + private function compileInclude(Smarty_Internal_TemplateCompilerBase $compiler, $file) + { + $compiler->parser->template_postfix[] = new Smarty_Internal_ParseTree_Tag($compiler->parser, + $compiler->compileTag('include', + array($file, + array('scope' => 'parent')))); + } + + /** + * Create source code for {extends} from source components array + * + * @param []\Smarty_Internal_Template_Source $components + * + * @return string + */ + public static function extendsSourceArrayCode($components) + { + $resources = array(); + foreach ($components as $source) { + $resources[] = $source->resource; + } + return '{extends file=\'extends:' . join('|', $resources) . '\' extends_resource=true}'; } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_debug.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_debug.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_debug.php (revision Shelved version) @@ -1,7 +1,7 @@ source->uid == '') { - $template->source->filepath; + if (isset($mode)) { + $this->index ++; + $this->offset ++; + $this->template_data[$this->index] = null; } - self::$ignore_uid[$template->source->uid] = true; + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['start_template_time'] = microtime(true); } /** + * End logging of cache time + * + * @param \Smarty_Internal_Template $template cached template + */ + public function end_template(Smarty_Internal_Template $template) + { + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['total_time'] += + microtime(true) - $this->template_data[$this->index][$key]['start_template_time']; + //$this->template_data[$this->index][$key]['properties'] = $template->properties; + } + + /** + * End logging of cache time + * + * @param \Smarty_Internal_Template $template cached template + */ + public function end_template(Smarty_Internal_Template $template) + { + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['total_time'] += + microtime(true) - $this->template_data[$this->index][$key]['start_template_time']; + //$this->template_data[$this->index][$key]['properties'] = $template->properties; + } + + /** * Start logging of compile time * - * @param object $template + * @param \Smarty_Internal_Template $template */ - public static function start_compile($template) + public function start_compile(Smarty_Internal_Template $template) { static $_is_stringy = array('string' => true, 'eval' => true); if (!empty($template->compiler->trace_uid)) { $key = $template->compiler->trace_uid; - if (!isset(self::$template_data[$key])) { + if (!isset($this->template_data[$this->index][$key])) { if (isset($_is_stringy[$template->source->type])) { - self::$template_data[$key]['name'] = '\'' . substr($template->source->name, 0, 25) . '...\''; + $this->template_data[$this->index][$key]['name'] = + '\'' . substr($template->source->name, 0, 25) . '...\''; } else { - self::$template_data[$key]['name'] = $template->source->filepath; + $this->template_data[$this->index][$key]['name'] = $template->source->filepath; } - self::$template_data[$key]['compile_time'] = 0; - self::$template_data[$key]['render_time'] = 0; - self::$template_data[$key]['cache_time'] = 0; + $this->template_data[$this->index][$key]['compile_time'] = 0; + $this->template_data[$this->index][$key]['render_time'] = 0; + $this->template_data[$this->index][$key]['cache_time'] = 0; } } else { - if (isset(self::$ignore_uid[$template->source->uid])) { + if (isset($this->ignore_uid[$template->source->uid])) { return; } - $key = self::get_key($template); + $key = $this->get_key($template); } - self::$template_data[$key]['start_time'] = microtime(true); + $this->template_data[$this->index][$key]['start_time'] = microtime(true); } /** * End logging of compile time * - * @param object $template + * @param \Smarty_Internal_Template $template */ - public static function end_compile($template) + public function end_compile(Smarty_Internal_Template $template) { if (!empty($template->compiler->trace_uid)) { $key = $template->compiler->trace_uid; } else { - if (isset(self::$ignore_uid[$template->source->uid])) { + if (isset($this->ignore_uid[$template->source->uid])) { return; } - $key = self::get_key($template); + $key = $this->get_key($template); } - self::$template_data[$key]['compile_time'] += microtime(true) - self::$template_data[$key]['start_time']; + $this->template_data[$this->index][$key]['compile_time'] += + microtime(true) - $this->template_data[$this->index][$key]['start_time']; } /** * Start logging of render time * - * @param object $template + * @param \Smarty_Internal_Template $template */ - public static function start_render($template) + public function start_render(Smarty_Internal_Template $template) { - $key = self::get_key($template); - self::$template_data[$key]['start_time'] = microtime(true); + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['start_time'] = microtime(true); } /** * End logging of compile time * - * @param object $template + * @param \Smarty_Internal_Template $template */ - public static function end_render($template) + public function end_render(Smarty_Internal_Template $template) { - $key = self::get_key($template); - self::$template_data[$key]['render_time'] += microtime(true) - self::$template_data[$key]['start_time']; + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['render_time'] += + microtime(true) - $this->template_data[$this->index][$key]['start_time']; } /** * Start logging of cache time * - * @param object $template cached template + * @param \Smarty_Internal_Template $template cached template */ - public static function start_cache($template) + public function start_cache(Smarty_Internal_Template $template) { - $key = self::get_key($template); - self::$template_data[$key]['start_time'] = microtime(true); + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['start_time'] = microtime(true); } /** * End logging of cache time * - * @param object $template cached template + * @param \Smarty_Internal_Template $template cached template */ - public static function end_cache($template) + public function end_cache(Smarty_Internal_Template $template) { - $key = self::get_key($template); - self::$template_data[$key]['cache_time'] += microtime(true) - self::$template_data[$key]['start_time']; + $key = $this->get_key($template); + $this->template_data[$this->index][$key]['cache_time'] += + microtime(true) - $this->template_data[$this->index][$key]['start_time']; } /** - * Opens a window for the Smarty Debugging Consol and display the data + * Register template object * + * @param \Smarty_Internal_Template $template cached template + */ + public function register_template(Smarty_Internal_Template $template) + { + } + + /** + * Register data object + * + * @param \Smarty_Data $data data object + */ + public static function register_data(Smarty_Data $data) + { + } + + /** + * Opens a window for the Smarty Debugging Console and display the data + * + * @param \Smarty_Internal_Template $template cached template + */ + public function register_template(Smarty_Internal_Template $template) + { + } + + /** + * Register data object + * + * @param \Smarty_Data $data data object + */ + public static function register_data(Smarty_Data $data) + { + } + + /** + * Opens a window for the Smarty Debugging Console and display the data + * * @param Smarty_Internal_Template|Smarty $obj object to debug + * @param bool $full */ - public static function display_debug($obj) + public function display_debug($obj, $full = false) { - // prepare information of assigned variables - $ptr = self::get_debug_vars($obj); - if ($obj instanceof Smarty) { - $smarty = clone $obj; + if (!$full) { + $this->offset ++; + $savedIndex = $this->index; + $this->index = 9999; + } + if ($obj->_objType == 1) { + $smarty = $obj; } else { - $smarty = clone $obj->smarty; + $smarty = $obj->smarty; } + // create fresh instance of smarty for displaying the debug console + // to avoid problems if the application did overload the Smarty class + $debObj = new Smarty(); + // copy the working dirs from application + $debObj->setCompileDir($smarty->getCompileDir()); + // init properties by hand as user may have edited the original Smarty class + $debObj->setPluginsDir(is_dir(__DIR__ . '/../plugins') ? __DIR__ . '/../plugins' : $smarty->getPluginsDir()); + $debObj->force_compile = false; + $debObj->compile_check = true; + $debObj->left_delimiter = '{'; + $debObj->right_delimiter = '}'; + $debObj->security_policy = null; + $debObj->debugging = false; + $debObj->debugging_ctrl = 'NONE'; + $debObj->error_reporting = E_ALL & ~E_NOTICE; + $debObj->debug_tpl = isset($smarty->debug_tpl) ? $smarty->debug_tpl : 'file:' . __DIR__ . '/../debug.tpl'; + $debObj->registered_plugins = array(); + $debObj->registered_resources = array(); + $debObj->registered_filters = array(); + $debObj->autoload_filters = array(); + $debObj->default_modifiers = array(); + $debObj->escape_html = true; + $debObj->caching = false; + $debObj->compile_id = null; + $debObj->cache_id = null; + // prepare information of assigned variables + $ptr = $this->get_debug_vars($obj); $_assigned_vars = $ptr->tpl_vars; ksort($_assigned_vars); $_config_vars = $ptr->config_vars; ksort($_config_vars); - $smarty->registered_filters = array(); - $smarty->autoload_filters = array(); - $smarty->default_modifiers = array(); - $smarty->force_compile = false; - $smarty->left_delimiter = '{'; - $smarty->right_delimiter = '}'; - $smarty->debugging = false; - $smarty->debugging_ctrl = 'NONE'; - $smarty->force_compile = false; - $_template = new Smarty_Internal_Template($smarty->debug_tpl, $smarty); - $_template->caching = false; - $_template->disableSecurity(); - $_template->cache_id = null; - $_template->compile_id = null; - if ($obj instanceof Smarty_Internal_Template) { + $debugging = $smarty->debugging; + + $_template = new Smarty_Internal_Template($debObj->debug_tpl, $debObj); + if ($obj->_objType == 2) { $_template->assign('template_name', $obj->source->type . ':' . $obj->source->name); } - if ($obj instanceof Smarty) { - $_template->assign('template_data', self::$template_data); + if ($obj->_objType == 1 || $full) { + $_template->assign('template_data', $this->template_data[$this->index]); } else { $_template->assign('template_data', null); } $_template->assign('assigned_vars', $_assigned_vars); $_template->assign('config_vars', $_config_vars); $_template->assign('execution_time', microtime(true) - $smarty->start_time); + $_template->assign('display_mode', $debugging == 2 || !$full); + $_template->assign('offset', $this->offset * 50); echo $_template->fetch(); + if (isset($full)) { + $this->index --; - } + } + if (!$full) { + $this->index = $savedIndex; + } + } + } + if (!$full) { + $this->index = $savedIndex; + } + } /** * Recursively gets variables from all template/data scopes @@ -189,34 +305,82 @@ * * @return StdClass */ - public static function get_debug_vars($obj) + public function get_debug_vars($obj) { - $config_vars = $obj->config_vars; + $config_vars = array(); + foreach ($obj->config_vars as $key => $var) { + $config_vars[$key]['value'] = $var; + if ($obj->_objType == 2) { + $config_vars[$key]['scope'] = $obj->source->type . ':' . $obj->source->name; + } elseif ($obj->_objType == 4) { + $tpl_vars[$key]['scope'] = $obj->dataObjectName; + } else { + $config_vars[$key]['scope'] = 'Smarty object'; + } + } $tpl_vars = array(); foreach ($obj->tpl_vars as $key => $var) { - $tpl_vars[$key] = clone $var; - if ($obj instanceof Smarty_Internal_Template) { - $tpl_vars[$key]->scope = $obj->source->type . ':' . $obj->source->name; - } elseif ($obj instanceof Smarty_Data) { - $tpl_vars[$key]->scope = 'Data object'; + foreach ($var as $varkey => $varvalue) { + if ($varkey == 'value') { + $tpl_vars[$key][$varkey] = $varvalue; - } else { + } else { - $tpl_vars[$key]->scope = 'Smarty root'; + if ($varkey == 'nocache') { + if ($varvalue == true) { + $tpl_vars[$key][$varkey] = $varvalue; - } + } + } else { + if ($varkey != 'scope' || $varvalue !== 0) { + $tpl_vars[$key]['attributes'][$varkey] = $varvalue; - } + } + } + } + } + if ($obj->_objType == 2) { + $tpl_vars[$key]['scope'] = $obj->source->type . ':' . $obj->source->name; + } elseif ($obj->_objType == 4) { + $tpl_vars[$key]['scope'] = $obj->dataObjectName; + } else { + $tpl_vars[$key]['scope'] = 'Smarty object'; + } + } if (isset($obj->parent)) { - $parent = self::get_debug_vars($obj->parent); + $parent = $this->get_debug_vars($obj->parent); + foreach ($parent->tpl_vars as $name => $pvar) { + if (isset($tpl_vars[$name]) && $tpl_vars[$name]['value'] === $pvar['value']) { + $tpl_vars[$name]['scope'] = $pvar['scope']; + } + } $tpl_vars = array_merge($parent->tpl_vars, $tpl_vars); + + foreach ($parent->config_vars as $name => $pvar) { + if (isset($config_vars[$name]) && $config_vars[$name]['value'] === $pvar['value']) { + $config_vars[$name]['scope'] = $pvar['scope']; + } + } $config_vars = array_merge($parent->config_vars, $config_vars); } else { - foreach (Smarty::$global_tpl_vars as $name => $var) { - if (!array_key_exists($name, $tpl_vars)) { - $clone = clone $var; - $clone->scope = 'Global'; - $tpl_vars[$name] = $clone; + foreach (Smarty::$global_tpl_vars as $key => $var) { + if (!array_key_exists($key, $tpl_vars)) { + foreach ($var as $varkey => $varvalue) { + if ($varkey == 'value') { + $tpl_vars[$key][$varkey] = $varvalue; + } else { + if ($varkey == 'nocache') { + if ($varvalue == true) { + $tpl_vars[$key][$varkey] = $varvalue; - } + } + } else { + if ($varkey != 'scope' || $varvalue !== 0) { + $tpl_vars[$key]['attributes'][$varkey] = $varvalue; - } - } + } + } + } + } + $tpl_vars[$key]['scope'] = 'Global'; + } + } + } return (object) array('tpl_vars' => $tpl_vars, 'config_vars' => $config_vars); } @@ -224,11 +388,11 @@ /** * Return key into $template_data for template * - * @param object $template template object + * @param \Smarty_Internal_Template $template template object * * @return string key into $template_data */ - private static function get_key($template) + private function get_key(Smarty_Internal_Template $template) { static $_is_stringy = array('string' => true, 'eval' => true); // calculate Uid if not already done @@ -236,19 +400,114 @@ $template->source->filepath; } $key = $template->source->uid; - if (isset(self::$template_data[$key])) { + if (isset($this->template_data[$this->index][$key])) { return $key; } else { if (isset($_is_stringy[$template->source->type])) { - self::$template_data[$key]['name'] = '\'' . substr($template->source->name, 0, 25) . '...\''; + $this->template_data[$this->index][$key]['name'] = + '\'' . substr($template->source->name, 0, 25) . '...\''; } else { - self::$template_data[$key]['name'] = $template->source->filepath; + $this->template_data[$this->index][$key]['name'] = $template->source->filepath; } - self::$template_data[$key]['compile_time'] = 0; - self::$template_data[$key]['render_time'] = 0; - self::$template_data[$key]['cache_time'] = 0; + $this->template_data[$this->index][$key]['compile_time'] = 0; + $this->template_data[$this->index][$key]['render_time'] = 0; + $this->template_data[$this->index][$key]['cache_time'] = 0; + $this->template_data[$this->index][$key]['total_time'] = 0; return $key; + } + } + + /** + * Ignore template + * + * @param \Smarty_Internal_Template $template + */ + public function ignore(Smarty_Internal_Template $template) + { + // calculate Uid if not already done + if ($template->source->uid == '') { + $template->source->filepath; + } + $this->ignore_uid[$template->source->uid] = true; + } + + /** + * handle 'URL' debugging mode + * + * @param Smarty $smarty + */ + public function debugUrl(Smarty $smarty) + { + if (isset($_SERVER['QUERY_STRING'])) { + $_query_string = $_SERVER['QUERY_STRING']; + } else { + $_query_string = ''; + } + if (false !== strpos($_query_string, $smarty->smarty_debug_id)) { + if (false !== strpos($_query_string, $smarty->smarty_debug_id . '=on')) { + // enable debugging for this browser session + setcookie('SMARTY_DEBUG', true); + $smarty->debugging = true; + } elseif (false !== strpos($_query_string, $smarty->smarty_debug_id . '=off')) { + // disable debugging for this browser session + setcookie('SMARTY_DEBUG', false); + $smarty->debugging = false; + } else { + // enable debugging for this page + $smarty->debugging = true; + } + } else { + if (isset($_COOKIE['SMARTY_DEBUG'])) { + $smarty->debugging = true; + } + } + } + + /** + * Ignore template + * + * @param \Smarty_Internal_Template $template + */ + public function ignore(Smarty_Internal_Template $template) + { + if (isset($mode)) { + $this->index ++; + $this->offset ++; + $this->template_data[$this->index] = null; + } + $this->ignore_uid[$template->source->uid] = true; + } + + /** + * handle 'URL' debugging mode + * + * @param Smarty $smarty + */ + public function debugUrl(Smarty $smarty) + { + if (isset($_SERVER['QUERY_STRING'])) { + $_query_string = $_SERVER['QUERY_STRING']; + } else { + $_query_string = ''; + } + if (false !== strpos($_query_string, $smarty->smarty_debug_id)) { + if (false !== strpos($_query_string, $smarty->smarty_debug_id . '=on')) { + // enable debugging for this browser session + setcookie('SMARTY_DEBUG', true); + $smarty->debugging = true; + } elseif (false !== strpos($_query_string, $smarty->smarty_debug_id . '=off')) { + // disable debugging for this browser session + setcookie('SMARTY_DEBUG', false); + $smarty->debugging = false; + } else { + // enable debugging for this page + $smarty->debugging = true; + } + } else { + if (isset($_COOKIE['SMARTY_DEBUG'])) { + $smarty->debugging = true; + } } } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_for.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_for.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_for.php (revision Shelved version) @@ -34,6 +34,7 @@ */ public function compile($args, $compiler, $parameter) { + $compiler->loopNesting++; if ($parameter == 0) { $this->required_attributes = array('start', 'to'); $this->optional_attributes = array('max', 'step'); @@ -44,30 +45,51 @@ // check and get attributes $_attr = $this->getAttributes($compiler, $args); - $output = "tpl_vars[$_statement[var]] = new Smarty_Variable;"; - $output .= " \$_smarty_tpl->tpl_vars[$_statement[var]]->value = $_statement[value];\n"; + if (is_array($_statement['var'])) { + $var = $_statement['var']['var']; + $index = $_statement['var']['smarty_internal_index']; + } else { + $var = $_statement['var']; + $index = ''; - } + } - $output .= " if ($_attr[ifexp]) { for (\$_foo=true;$_attr[ifexp]; \$_smarty_tpl->tpl_vars[$_attr[var]]->value$_attr[step]) {\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var] = new Smarty_Variable;\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->value{$index} = {$_statement['value']};\n"; + } + if (is_array($_attr['var'])) { + $var = $_attr['var']['var']; + $index = $_attr['var']['smarty_internal_index']; - } else { + } else { + $var = $_attr['var']; + $index = ''; + } + $output .= "if ($_attr[ifexp]) {\nfor (\$_foo=true;$_attr[ifexp]; \$_smarty_tpl->tpl_vars[$var]->value{$index}$_attr[step]) {\n"; + } else { $_statement = $_attr['start']; - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]] = new Smarty_Variable;"; + if (is_array($_statement['var'])) { + $var = $_statement['var']['var']; + $index = $_statement['var']['smarty_internal_index']; + } else { + $var = $_statement['var']; + $index = ''; + } + $output .= "\$_smarty_tpl->tpl_vars[$var] = new Smarty_Variable;"; if (isset($_attr['step'])) { - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->step = $_attr[step];"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->step = $_attr[step];"; } else { - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->step = 1;"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->step = 1;"; } if (isset($_attr['max'])) { - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->total = (int) min(ceil((\$_smarty_tpl->tpl_vars[$_statement[var]]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$_statement[var]]->step)),$_attr[max]);\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) min(ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step)),$_attr[max]);\n"; } else { - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->total = (int) ceil((\$_smarty_tpl->tpl_vars[$_statement[var]]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$_statement[var]]->step));\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->total = (int) ceil((\$_smarty_tpl->tpl_vars[$var]->step > 0 ? $_attr[to]+1 - ($_statement[value]) : $_statement[value]-($_attr[to])+1)/abs(\$_smarty_tpl->tpl_vars[$var]->step));\n"; } - $output .= "if (\$_smarty_tpl->tpl_vars[$_statement[var]]->total > 0) {\n"; - $output .= "for (\$_smarty_tpl->tpl_vars[$_statement[var]]->value = $_statement[value], \$_smarty_tpl->tpl_vars[$_statement[var]]->iteration = 1;\$_smarty_tpl->tpl_vars[$_statement[var]]->iteration <= \$_smarty_tpl->tpl_vars[$_statement[var]]->total;\$_smarty_tpl->tpl_vars[$_statement[var]]->value += \$_smarty_tpl->tpl_vars[$_statement[var]]->step, \$_smarty_tpl->tpl_vars[$_statement[var]]->iteration++) {\n"; - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->first = \$_smarty_tpl->tpl_vars[$_statement[var]]->iteration == 1;"; - $output .= "\$_smarty_tpl->tpl_vars[$_statement[var]]->last = \$_smarty_tpl->tpl_vars[$_statement[var]]->iteration == \$_smarty_tpl->tpl_vars[$_statement[var]]->total;"; + $output .= "if (\$_smarty_tpl->tpl_vars[$var]->total > 0) {\n"; + $output .= "for (\$_smarty_tpl->tpl_vars[$var]->value{$index} = $_statement[value], \$_smarty_tpl->tpl_vars[$var]->iteration = 1;\$_smarty_tpl->tpl_vars[$var]->iteration <= \$_smarty_tpl->tpl_vars[$var]->total;\$_smarty_tpl->tpl_vars[$var]->value{$index} += \$_smarty_tpl->tpl_vars[$var]->step, \$_smarty_tpl->tpl_vars[$var]->iteration++) {\n"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->first = \$_smarty_tpl->tpl_vars[$var]->iteration == 1;"; + $output .= "\$_smarty_tpl->tpl_vars[$var]->last = \$_smarty_tpl->tpl_vars[$var]->iteration == \$_smarty_tpl->tpl_vars[$var]->total;"; } $output .= "?>"; @@ -127,6 +149,7 @@ */ public function compile($args, $compiler, $parameter) { + $compiler->loopNesting--; // check and get attributes $_attr = $this->getAttributes($compiler, $args); // must endblock be nocache? @@ -136,10 +159,11 @@ list($openTag, $compiler->nocache) = $this->closeTag($compiler, array('for', 'forelse')); - if ($openTag == 'forelse') { - return ""; - } else { - return ""; + $output = "\n"; + return $output; } } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_resource_string.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_resource_string.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_resource_string.php (revision Shelved version) @@ -73,11 +73,11 @@ * * @param Smarty $smarty Smarty instance * @param string $resource_name resource_name to make unique - * @param boolean $is_config flag for config resource + * @param boolean $isConfig flag for config resource * * @return string unique resource name */ - protected function buildUniqueResourceName(Smarty $smarty, $resource_name, $is_config = false) + public function buildUniqueResourceName(Smarty $smarty, $resource_name, $isConfig = false) { return get_class($this) . '#' . $this->decode($resource_name); } @@ -90,7 +90,7 @@ * * @return string resource's basename */ - protected function getBasename(Smarty_Template_Source $source) + public function getBasename(Smarty_Template_Source $source) { return ''; } Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_append.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_append.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_append.php (revision Shelved version) @@ -0,0 +1,74 @@ + $_val) { + if ($_key != '') { + $this->append($data, $_key, $_val, $merge, $nocache); + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if (!isset($data->tpl_vars[$tpl_var])) { + $tpl_var_inst = $data->ext->getTemplateVars->_getVariable($data, $tpl_var, null, true, false); + if ($tpl_var_inst instanceof Smarty_Undefined_Variable) { + $data->tpl_vars[$tpl_var] = new Smarty_Variable(null, $nocache); + } else { + $data->tpl_vars[$tpl_var] = clone $tpl_var_inst; + } + } + if (!(is_array($data->tpl_vars[$tpl_var]->value) || + $data->tpl_vars[$tpl_var]->value instanceof ArrayAccess) + ) { + settype($data->tpl_vars[$tpl_var]->value, 'array'); + } + if ($merge && is_array($value)) { + foreach ($value as $_mkey => $_mval) { + $data->tpl_vars[$tpl_var]->value[$_mkey] = $_mval; + } + } else { + $data->tpl_vars[$tpl_var]->value[] = $value; + } + } + if ($data->_objType == 2 && $data->scope) { + $data->ext->_updateScope->updateScope($data, $tpl_var); + } + } + return $data; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_dqcontent.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_dqcontent.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_parsetree_dqcontent.php (revision Shelved version) @@ -0,0 +1,42 @@ +data = $data; + } + + /** + * Return content as double quoted string + * + * @param \Smarty_Internal_Templateparser $parser + * + * @return string doubled quoted string + */ + public function to_smarty_php(Smarty_Internal_Templateparser $parser) + { + return '"' . $this->data . '"'; + } +} Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_block_plugin.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_block_plugin.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_private_block_plugin.php (revision Shelved version) @@ -27,15 +27,15 @@ /** * Compiles code for the execution of block plugin * - * @param array $args array with attributes from parser + * @param array $args array with attributes from parser - * @param object $compiler compiler object + * @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object - * @param array $parameter array with compilation parameter + * @param array $parameter array with compilation parameter - * @param string $tag name of block plugin + * @param string $tag name of block plugin - * @param string $function PHP function name + * @param string $function PHP function name * * @return string compiled code */ - public function compile($args, $compiler, $parameter, $tag, $function) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $function) { if (!isset($tag[5]) || substr($tag, - 5) != 'close') { // opening tag of block plugin @@ -60,7 +60,7 @@ // maybe nocache because of nocache variables or nocache plugin $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; // compile code - $output = "smarty->_tag_stack[] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>"; + $output = "smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>"; } else { // must endblock be nocache? if ($compiler->nocache) { @@ -75,9 +75,13 @@ $mod_pre = $mod_post = ''; } else { $mod_pre = ' ob_start(); '; - $mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'], 'value' => 'ob_get_clean()')) . ';'; + $mod_post = 'echo ' . + $compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'], + 'value' => 'ob_get_clean()')) . ';'; } - $output = "smarty->_tag_stack);?>"; + $output = "smarty->_cache['tag_stack']);?>"; } return $output . "\n"; Index: src/includes/classes/Smarty/sysplugins/smarty_internal_method_setdefaultmodifiers.php =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_method_setdefaultmodifiers.php (revision Shelved version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_method_setdefaultmodifiers.php (revision Shelved version) @@ -0,0 +1,38 @@ +smarty) ? $obj->smarty : $obj; + $smarty->default_modifiers = (array) $modifiers; + return $obj; + } +} \ No newline at end of file Index: src/includes/classes/Smarty/sysplugins/smarty_internal_compile_setfilter.php IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/sysplugins/smarty_internal_compile_setfilter.php (revision Local version) +++ src/includes/classes/Smarty/sysplugins/smarty_internal_compile_setfilter.php (revision Shelved version) @@ -25,10 +25,10 @@ * * @return string compiled code */ - public function compile($args, $compiler, $parameter) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter) { - $compiler->variable_filter_stack[] = $compiler->template->variable_filters; - $compiler->template->variable_filters = $parameter['modifier_list']; + $compiler->variable_filter_stack[] = $compiler->variable_filters; + $compiler->variable_filters = $parameter['modifier_list']; // this tag does not return compiled code $compiler->has_code = false; @@ -53,14 +53,14 @@ * * @return string compiled code */ - public function compile($args, $compiler) + public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler) { $_attr = $this->getAttributes($compiler, $args); // reset variable filter to previous state if (count($compiler->variable_filter_stack)) { - $compiler->template->variable_filters = array_pop($compiler->variable_filter_stack); + $compiler->variable_filters = array_pop($compiler->variable_filter_stack); } else { - $compiler->template->variable_filters = array(); + $compiler->variable_filters = array(); } // this tag does not return compiled code $compiler->has_code = false; Index: src/includes/classes/Smarty/debug.tpl IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- src/includes/classes/Smarty/debug.tpl (revision Local version) +++ src/includes/classes/Smarty/debug.tpl (revision Shelved version) @@ -5,7 +5,7 @@ Smarty Debug Console