From 6d66c568bd100af32927fd8f7d634eef28fcae5d Mon Sep 17 00:00:00 2001 From: andrey Date: Fri, 15 Jun 2001 14:52:48 +0000 Subject: [PATCH] Finishing up secure mode. --- Smarty.addons.php | 43 +++---- Smarty.class.php | 108 +++++++++-------- Smarty_Compiler.class.php | 214 ++++++++++++++++----------------- libs/Smarty.class.php | 108 +++++++++-------- libs/Smarty_Compiler.class.php | 214 ++++++++++++++++----------------- 5 files changed, 346 insertions(+), 341 deletions(-) diff --git a/Smarty.addons.php b/Smarty.addons.php index 25e7c4c6..575c1d5c 100644 --- a/Smarty.addons.php +++ b/Smarty.addons.php @@ -210,12 +210,12 @@ function smarty_func_assign($args, &$smarty_obj) extract($args); if (empty($var)) { - trigger_error("assign: missing 'var' parameter"); + $smarty_obj->_trigger_error_msg("assign: missing 'var' parameter"); return; } if (empty($value)) { - trigger_error("assign: missing 'value' parameter"); + $smarty_obj->_trigger_error_msg("assign: missing 'value' parameter"); return; } @@ -423,12 +423,10 @@ function smarty_func_html_select_time() Function: smarty_func_math Purpose: allow math computations in template \*======================================================================*/ -function smarty_func_math() { - $args=func_get_arg(0); - +function smarty_func_math($args, $smarty_obj) { // be sure equation parameter is present if(empty($args["equation"])) { - trigger_error("math: missing equation parameter"); + $smarty_obj->_trigger_error_msg("math: missing equation parameter"); return; } @@ -436,7 +434,7 @@ function smarty_func_math() { // make sure parenthesis are balanced if(substr_count($equation,"(") != substr_count($equation,")")) { - trigger_error("math: unbalanced parenthesis"); + $smarty_obj->_trigger_error_msg("math: unbalanced parenthesis"); return; } @@ -445,9 +443,10 @@ function smarty_func_math() { foreach($match[0] as $curr_var) { if(!in_array($curr_var,array_keys($args)) && - !in_array($curr_var,array('int','abs','ceil','cos','exp','floor','log','log10', - 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan')) ) { - trigger_error("math: parameter $curr_var not passed as argument"); + !in_array($curr_var, + array('int','abs','ceil','cos','exp','floor','log','log10', + 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'))) { + $smarty_obj->_trigger_error_msg("math: parameter $curr_var not passed as argument"); return; } } @@ -456,11 +455,11 @@ function smarty_func_math() { if($key != "equation" && $key != "format") { // make sure value is not empty if(strlen($val)==0) { - trigger_error("math: parameter $key is empty"); + $smarty_obj->_trigger_error_msg("math: parameter $key is empty"); return; } if(!is_numeric($val)) { - trigger_error("math: parameter $key: is not numeric"); + $smarty_obj->_trigger_error_msg("math: parameter $key: is not numeric"); return; } $equation = preg_replace("/\b$key\b/",$val,$equation); @@ -479,26 +478,28 @@ function smarty_func_math() { Function: smarty_func_fetch Purpose: fetch file, web or ftp data and display results \*======================================================================*/ -function smarty_func_fetch($args,&$smarty_obj) { +function smarty_func_fetch($args, &$smarty_obj) { extract($args); - if(empty($file)) { - trigger_error("parameter 'file' cannot be empty"); + if (empty($file)) { + $smarty_obj->_trigger_error_msg("parameter 'file' cannot be empty"); return; } - if($smarty_obj->security && !preg_match("/^(http|ftp):\/\//",$file)) { + + if ($smarty_obj->security && !preg_match('!^(http|ftp)://!', $file)) { // make sure fetched file comes from secure directory - foreach($smarty_obj->secure_dir as $curr_dir) { - if(substr(realpath($file),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) { + foreach ($smarty_obj->secure_dir as $curr_dir) { + if (substr(realpath($file), 0, strlen(realpath($curr_dir))) == realpath($curr_dir)) { $resource_is_secure = true; break; } } - if(!$resource_is_secure) { - trigger_error("(secure mode) fetching '$file' is not allowed"); + if (!$resource_is_secure) { + $smarty_obj->_trigger_error_msg("(secure mode) fetching '$file' is not allowed"); return; } - } + } + readfile($file); } diff --git a/Smarty.class.php b/Smarty.class.php index 126a3584..029b524d 100644 --- a/Smarty.class.php +++ b/Smarty.class.php @@ -98,17 +98,19 @@ class Smarty // SMARTY_PHP_REMOVE -> remove php tags // SMARTY_PHP_ALLOW -> execute php tags // default: SMARTY_PHP_PASSTHRU - - - var $security = false; // enable template security (default false) - var $secure_dir = array("./templates"); // array of directories considered secure - var $security_settings = array( - "ALLOW_PHP_HANDLING" => false, - "ALLOW_IF_FUNCS" => array('count','is_array'), - "ALLOW_INCLUDE_ANY" => false, - "ALLOW_PHP_TAGS" => false, - "ALLOW_MODIFIER_FUNCS" => array('count') - ); + + + var $security = false; // enable template security (default false) + var $secure_dir = array("./templates"); // array of directories considered secure + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'in_array'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count') + ); var $left_delimiter = '{'; // template tag delimiters. var $right_delimiter = '}'; @@ -121,8 +123,8 @@ class Smarty 'html_select_time' => 'smarty_func_html_select_time', 'math' => 'smarty_func_math', 'fetch' => 'smarty_func_fetch', - 'counter' => 'smarty_func_counter', - 'assign' => 'smarty_func_assign' + 'counter' => 'smarty_func_counter', + 'assign' => 'smarty_func_assign' ); var $custom_mods = array( 'lower' => 'strtolower', @@ -162,8 +164,8 @@ class Smarty var $_conf_obj = null; // configuration object var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; // md5 checksum of the string 'Smarty' var $_version = '1.4.2'; // Smarty version number - var $_extract = false; // flag for custom functions - + var $_extract = false; // flag for custom functions + /*======================================================================*\ Function: Smarty Purpose: Constructor @@ -205,7 +207,7 @@ class Smarty if (!empty($tpl_var) && isset($value)) $this->_tpl_vars[$tpl_var] = $value; } - $this->_extract = true; + $this->_extract = true; } @@ -230,7 +232,7 @@ class Smarty $this->_tpl_vars[$tpl_var][] = $value; } } - $this->_extract = true; + $this->_extract = true; } @@ -426,8 +428,8 @@ class Smarty /*======================================================================*\ Function: clear_compile_dir() - Purpose: clears compiled version of specified template resource, - or all compiled template files if one is not specified. + Purpose: clears compiled version of specified template resource, + or all compiled template files if one is not specified. This function is for advanced use only, not normally needed. \*======================================================================*/ function clear_compile_dir($tpl_file = null) @@ -435,23 +437,23 @@ class Smarty if (!is_dir($this->compile_dir)) return false; - if (isset($tpl_file)) { - // remove compiled template file if it exists - $tpl_file = urlencode($tpl_file).'.php'; + if (isset($tpl_file)) { + // remove compiled template file if it exists + $tpl_file = urlencode($tpl_file).'.php'; if (file_exists($this->compile_dir.'/'.$tpl_file)) { unlink($this->compile_dir.'/'.$tpl_file); - } - } else { - // remove everything in $compile_dir - $dir_handle = opendir($this->compile_dir); - while ($curr_file = readdir($dir_handle)) { - if ($curr_file == '.' || $curr_dir == '..' || - !is_file($this->compile_dir.'/'.$curr_file)) { + } + } else { + // remove everything in $compile_dir + $dir_handle = opendir($this->compile_dir); + while ($curr_file = readdir($dir_handle)) { + if ($curr_file == '.' || $curr_dir == '..' || + !is_file($this->compile_dir.'/'.$curr_file)) { continue; } - unlink($this->compile_dir.'/'.$curr_file); - } - closedir($dir_handle); + unlink($this->compile_dir.'/'.$curr_file); + } + closedir($dir_handle); } return true; @@ -634,7 +636,7 @@ class Smarty Purpose: fetch the template source and timestamp \*======================================================================*/ function _fetch_template_source($tpl_path, &$template_source, &$template_timestamp) - { + { // split tpl_path by the first colon $tpl_path_parts = explode(':', $tpl_path, 2); @@ -653,20 +655,20 @@ class Smarty // relative pathname to $template_dir $resource_name = $this->template_dir.'/'.$resource_name; } - // if security is on, make sure template comes from a $secure_dir - if($this->security && !$this->security_settings["ALLOW_INCLUDE_ANY"]) { - $resource_is_secure = false; - foreach($this->secure_dir as $curr_dir) { - if(substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) { - $resource_is_secure = true; - break; - } - } - if(!$resource_is_secure) { - $this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed"); - return false; - } - } + // if security is on, make sure template comes from a $secure_dir + if ($this->security && !$this->security_settings['INCLUDE_ANY']) { + $resource_is_secure = false; + foreach ($this->secure_dir as $curr_dir) { + if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) { + $resource_is_secure = true; + break; + } + } + if (!$resource_is_secure) { + $this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed"); + return false; + } + } if (file_exists($resource_name) && is_readable($resource_name)) { $template_source = $this->_read_file($resource_name); $template_timestamp = filemtime($resource_name); @@ -721,8 +723,8 @@ class Smarty $smarty_compiler->_version = $this->_version; $smarty_compiler->prefilter_funcs = $this->prefilter_funcs; $smarty_compiler->compiler_funcs = $this->compiler_funcs; - $smarty_compiler->security = $this->security; - $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; $smarty_compiler->security_settings = $this->security_settings; if ($smarty_compiler->_compile_file($tpl_file, $template_source, $template_compiled)) @@ -818,10 +820,10 @@ class Smarty $this->_trigger_error_msg("problem writing '$filename.'"); return false; } - - // flock doesn't seem to work on several windows platforms (98, NT4, NT5, ?), - // so we'll not use it at all in windows. - + + // flock doesn't seem to work on several windows platforms (98, NT4, NT5, ?), + // so we'll not use it at all in windows. + if ( strtoupper(substr(PHP_OS,0,3)) == 'WIN' || (flock($fd, LOCK_EX)) ) { fwrite( $fd, $contents ); fclose($fd); diff --git a/Smarty_Compiler.class.php b/Smarty_Compiler.class.php index 1a3fae49..fdb09f2a 100644 --- a/Smarty_Compiler.class.php +++ b/Smarty_Compiler.class.php @@ -43,7 +43,7 @@ class Smarty_Compiler extends Smarty { // internal vars var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part var $_literal_blocks = array(); // keeps literal template blocks - var $_php_blocks = array(); // keeps php code blocks + var $_php_blocks = array(); // keeps php code blocks var $_current_file = null; // the current template being compiled var $_current_line_no = 1; // line number for error messages @@ -54,18 +54,17 @@ class Smarty_Compiler extends Smarty { \*======================================================================*/ function _compile_file($tpl_file, $template_source, &$template_compiled) { - - if($this->security) { - // do not allow php syntax to be executed unless specified - if($this->php_handling == SMARTY_PHP_ALLOW && - !$this->security_settings["ALLOW_PHP_HANDLING"]) { - $this->php_handling = SMARTY_PHP_PASSTHRU; - } - } - + if($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + // run template source through functions registered in prefilter_funcs if (is_array($this->prefilter_funcs) && count($this->prefilter_funcs) > 0) { - foreach($this->prefilter_funcs as $prefilter) { + foreach ($this->prefilter_funcs as $prefilter) { if (function_exists($prefilter)) { $template_source = $prefilter($template_source); } else { @@ -83,14 +82,14 @@ class Smarty_Compiler extends Smarty { preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_source, $match); $this->_literal_blocks = $match[1]; $template_source = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", - $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source); + $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source); /* Pull out the php code blocks. */ preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $template_source, $match); $this->_php_blocks = $match[1]; $template_source = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", - $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source); - + $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source); + /* Gather all template tags. */ preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_source, $match); $template_tags = $match[1]; @@ -150,7 +149,7 @@ class Smarty_Compiler extends Smarty { for ($i = 0; $i < count($strip_tags); $i++) $template_compiled = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $this->quote_replace($strip_tags_modified[$i]), - $template_compiled, 1); + $template_compiled, 1); } // put header at the top of the compiled template @@ -180,8 +179,8 @@ class Smarty_Compiler extends Smarty { ) (?:\s+(.*))? /xs', $template_tag, $match); - $tag_command = $match[1]; - $tag_args = isset($match[2]) ? $match[2] : ''; + $tag_command = $match[1]; + $tag_args = isset($match[2]) ? $match[2] : ''; /* If the tag name matches a variable or section property definition, we simply process it. */ @@ -209,12 +208,12 @@ class Smarty_Compiler extends Smarty { case '/if': return ''; - case 'capture': - return ''; - - case '/capture': - return 'assign("return", ob_get_contents()); ob_end_clean(); ?>'; - + case 'capture': + return ''; + + case '/capture': + return 'assign("return", ob_get_contents()); ob_end_clean(); ?>'; + case 'ldelim': return $this->left_delimiter; @@ -248,23 +247,23 @@ class Smarty_Compiler extends Smarty { return "\n"; case 'php': - if($this->security && !$this->security_settings["ALLOW_PHP_TAGS"]) { + if ($this->security && !$this->security_settings['PHP_TAGS']) { $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING); - return; - } + return; + } list (,$php_block) = each($this->_php_blocks); $this->_current_line_no += substr_count($php_block, "\n"); return ''; - + case 'insert': return $this->_compile_insert_tag($tag_args); default: - if (isset($this->compiler_funcs[$tag_command])) { - return $this->_compile_compiler_tag($tag_command, $tag_args); - } else if (isset($this->custom_funcs[$tag_command])) { - return $this->_compile_custom_tag($tag_command, $tag_args); - } else { + if (isset($this->compiler_funcs[$tag_command])) { + return $this->_compile_compiler_tag($tag_command, $tag_args); + } else if (isset($this->custom_funcs[$tag_command])) { + return $this->_compile_custom_tag($tag_command, $tag_args); + } else { $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING); return; } @@ -273,20 +272,20 @@ class Smarty_Compiler extends Smarty { /*======================================================================*\ - Function: _compile_compiler_tag - Purpose: compile the custom compiler tag + Function: _compile_compiler_tag + Purpose: compile the custom compiler tag \*======================================================================*/ - function _compile_compiler_tag($tag_command, $tag_args) - { - $function = $this->compiler_funcs[$tag_command]; + function _compile_compiler_tag($tag_command, $tag_args) + { + $function = $this->compiler_funcs[$tag_command]; - if (!function_exists($function)) { - $this->_syntax_error("compiler function '$tag_command' is not implemented", E_USER_WARNING); - return; - } + if (!function_exists($function)) { + $this->_syntax_error("compiler function '$tag_command' is not implemented", E_USER_WARNING); + return; + } - return ''; - } + return ''; + } /*======================================================================*\ @@ -348,21 +347,21 @@ class Smarty_Compiler extends Smarty { $this->_syntax_error("missing 'file' attribute in config_load tag"); } - if (!empty($attrs['global']) && $attrs['global']) - $update_parent = true; - else - $update_parent = false; + if (!empty($attrs['global']) && $attrs['global']) + $update_parent = true; + else + $update_parent = false; $output = "_conf_obj->get(".$attrs['file']."));\n"; - if ($update_parent) - $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file']."));\n"; + "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file']."));\n"; + if ($update_parent) + $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file']."));\n"; if (!empty($attrs['section'])) { - $output .= "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; - if ($update_parent) - $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; - } + $output .= "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; + if ($update_parent) + $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; + } $output .= '?>'; @@ -382,21 +381,21 @@ class Smarty_Compiler extends Smarty { $this->_syntax_error("missing 'file' attribute in include tag"); } - foreach ($attrs as $arg_name => $arg_value) { - if ($arg_name == 'file') { - $include_file = $arg_value; + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; continue; } - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } - return "_tpl_vars;\n" . - "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."), \$_smarty_config);\n" . - "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . - "unset(\$_smarty_tpl_vars); ?>"; + return "_tpl_vars;\n" . + "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."), \$_smarty_config);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars); ?>"; } @@ -456,8 +455,8 @@ class Smarty_Compiler extends Smarty { $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n"; $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - 1;\n"; $output .= "{$section_props}['index_next'] = {$section_props}['index'] + 1;\n"; - $output .= "{$section_props}['first'] = ({$section_props}['index'] == 0);\n"; - $output .= "{$section_props}['last'] = ({$section_props}['index'] == {$section_props}['loop']-1);\n"; + $output .= "{$section_props}['first'] = ({$section_props}['index'] == 0);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['index'] == {$section_props}['loop']-1);\n"; $output .= "?>"; @@ -485,7 +484,7 @@ class Smarty_Compiler extends Smarty { $is_arg_stack = array(); for ($i = 0; $i < count($tokens); $i++) { - + $token = &$tokens[$i]; switch ($token) { case 'eq': @@ -561,14 +560,15 @@ class Smarty_Compiler extends Smarty { current position for the next iteration. */ $i = $is_arg_start; break; - default: - if($this->security - && $tokens[$i+1] == '(' - && !preg_match("|[^a-zA-Z_-]|",$tokens[$i]) - && !in_array($tokens[$i],$this->security_settings["ALLOW_IF_FUNCS"])) { - $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement"); - } - break; + + default: + if($this->security && + $tokens[$i+1] == '(' && + !preg_match("|[^a-zA-Z_]|",$tokens[$i]) && + !in_array($tokens[$i], $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement"); + } + break; } } @@ -712,11 +712,11 @@ class Smarty_Compiler extends Smarty { return $attrs; } - + /*======================================================================*\ Function: _parse_vars_props Purpose: compile variables and section properties tokens into - PHP code + PHP code \*======================================================================*/ function _parse_vars_props(&$tokens) { @@ -752,28 +752,28 @@ class Smarty_Compiler extends Smarty { \*======================================================================*/ function _parse_var($var_expr) { - $parts = explode('|', substr($var_expr, 1), 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $parts = explode('|', substr($var_expr, 1), 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; - preg_match_all('!\[\w+(\.\w+)?\]|(->|\.)\w+|^\w+!', $var_ref, $match); - $indexes = $match[0]; + preg_match_all('!\[\w+(\.\w+)?\]|(->|\.)\w+|^\w+!', $var_ref, $match); + $indexes = $match[0]; $var_name = array_shift($indexes); $output = "\$this->_tpl_vars['$var_name']"; - foreach ($indexes as $index) { - if ($index{0} == '[') { - $parts = explode('.', substr($index, 1, -1)); - $section = $parts[0]; - $section_prop = isset($parts[1]) ? $parts[1] : 'index'; - $output .= "[\$this->_sections['$section']['properties']['$section_prop']]"; - } else if ($index{0} == '.') { - $output .= "['" . substr($index, 1) . "']"; - } else { - $output .= $index; - } - } + foreach ($indexes as $index) { + if ($index{0} == '[') { + $parts = explode('.', substr($index, 1, -1)); + $section = $parts[0]; + $section_prop = isset($parts[1]) ? $parts[1] : 'index'; + $output .= "[\$this->_sections['$section']['properties']['$section_prop']]"; + } else if ($index{0} == '.') { + $output .= "['" . substr($index, 1) . "']"; + } else { + $output .= $index; + } + } $this->_parse_modifiers($output, $modifiers); @@ -788,8 +788,8 @@ class Smarty_Compiler extends Smarty { function _parse_conf_var($conf_var_expr) { $parts = explode('|', $conf_var_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; $var_name = substr($var_ref, 1, -1); @@ -808,8 +808,8 @@ class Smarty_Compiler extends Smarty { function _parse_section_prop($section_prop_expr) { $parts = explode('|', $section_prop_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); $section_name = $match[1]; @@ -855,13 +855,13 @@ class Smarty_Compiler extends Smarty { * function name. */ if (!isset($mod_func_name)) { - if($this->security && !in_array($modifier_name,$this->security_settings["ALLOW_MODIFIER_FUNCS"])) { - $this->_syntax_error("(secure mode) modifier '$modifier_name' is not allowed", E_USER_WARNING); - continue; - } else { - $mod_func_name = $modifier_name; - } - } + if ($this->security && !in_array($modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_syntax_error("(secure mode) modifier '$modifier_name' is not allowed", E_USER_WARNING); + continue; + } else { + $mod_func_name = $modifier_name; + } + } if (!function_exists($mod_func_name)) { $this->_syntax_error("modifier '$modifier_name' is not implemented", E_USER_WARNING); diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index 126a3584..029b524d 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -98,17 +98,19 @@ class Smarty // SMARTY_PHP_REMOVE -> remove php tags // SMARTY_PHP_ALLOW -> execute php tags // default: SMARTY_PHP_PASSTHRU - - - var $security = false; // enable template security (default false) - var $secure_dir = array("./templates"); // array of directories considered secure - var $security_settings = array( - "ALLOW_PHP_HANDLING" => false, - "ALLOW_IF_FUNCS" => array('count','is_array'), - "ALLOW_INCLUDE_ANY" => false, - "ALLOW_PHP_TAGS" => false, - "ALLOW_MODIFIER_FUNCS" => array('count') - ); + + + var $security = false; // enable template security (default false) + var $secure_dir = array("./templates"); // array of directories considered secure + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'in_array'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count') + ); var $left_delimiter = '{'; // template tag delimiters. var $right_delimiter = '}'; @@ -121,8 +123,8 @@ class Smarty 'html_select_time' => 'smarty_func_html_select_time', 'math' => 'smarty_func_math', 'fetch' => 'smarty_func_fetch', - 'counter' => 'smarty_func_counter', - 'assign' => 'smarty_func_assign' + 'counter' => 'smarty_func_counter', + 'assign' => 'smarty_func_assign' ); var $custom_mods = array( 'lower' => 'strtolower', @@ -162,8 +164,8 @@ class Smarty var $_conf_obj = null; // configuration object var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; // md5 checksum of the string 'Smarty' var $_version = '1.4.2'; // Smarty version number - var $_extract = false; // flag for custom functions - + var $_extract = false; // flag for custom functions + /*======================================================================*\ Function: Smarty Purpose: Constructor @@ -205,7 +207,7 @@ class Smarty if (!empty($tpl_var) && isset($value)) $this->_tpl_vars[$tpl_var] = $value; } - $this->_extract = true; + $this->_extract = true; } @@ -230,7 +232,7 @@ class Smarty $this->_tpl_vars[$tpl_var][] = $value; } } - $this->_extract = true; + $this->_extract = true; } @@ -426,8 +428,8 @@ class Smarty /*======================================================================*\ Function: clear_compile_dir() - Purpose: clears compiled version of specified template resource, - or all compiled template files if one is not specified. + Purpose: clears compiled version of specified template resource, + or all compiled template files if one is not specified. This function is for advanced use only, not normally needed. \*======================================================================*/ function clear_compile_dir($tpl_file = null) @@ -435,23 +437,23 @@ class Smarty if (!is_dir($this->compile_dir)) return false; - if (isset($tpl_file)) { - // remove compiled template file if it exists - $tpl_file = urlencode($tpl_file).'.php'; + if (isset($tpl_file)) { + // remove compiled template file if it exists + $tpl_file = urlencode($tpl_file).'.php'; if (file_exists($this->compile_dir.'/'.$tpl_file)) { unlink($this->compile_dir.'/'.$tpl_file); - } - } else { - // remove everything in $compile_dir - $dir_handle = opendir($this->compile_dir); - while ($curr_file = readdir($dir_handle)) { - if ($curr_file == '.' || $curr_dir == '..' || - !is_file($this->compile_dir.'/'.$curr_file)) { + } + } else { + // remove everything in $compile_dir + $dir_handle = opendir($this->compile_dir); + while ($curr_file = readdir($dir_handle)) { + if ($curr_file == '.' || $curr_dir == '..' || + !is_file($this->compile_dir.'/'.$curr_file)) { continue; } - unlink($this->compile_dir.'/'.$curr_file); - } - closedir($dir_handle); + unlink($this->compile_dir.'/'.$curr_file); + } + closedir($dir_handle); } return true; @@ -634,7 +636,7 @@ class Smarty Purpose: fetch the template source and timestamp \*======================================================================*/ function _fetch_template_source($tpl_path, &$template_source, &$template_timestamp) - { + { // split tpl_path by the first colon $tpl_path_parts = explode(':', $tpl_path, 2); @@ -653,20 +655,20 @@ class Smarty // relative pathname to $template_dir $resource_name = $this->template_dir.'/'.$resource_name; } - // if security is on, make sure template comes from a $secure_dir - if($this->security && !$this->security_settings["ALLOW_INCLUDE_ANY"]) { - $resource_is_secure = false; - foreach($this->secure_dir as $curr_dir) { - if(substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) { - $resource_is_secure = true; - break; - } - } - if(!$resource_is_secure) { - $this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed"); - return false; - } - } + // if security is on, make sure template comes from a $secure_dir + if ($this->security && !$this->security_settings['INCLUDE_ANY']) { + $resource_is_secure = false; + foreach ($this->secure_dir as $curr_dir) { + if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) { + $resource_is_secure = true; + break; + } + } + if (!$resource_is_secure) { + $this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed"); + return false; + } + } if (file_exists($resource_name) && is_readable($resource_name)) { $template_source = $this->_read_file($resource_name); $template_timestamp = filemtime($resource_name); @@ -721,8 +723,8 @@ class Smarty $smarty_compiler->_version = $this->_version; $smarty_compiler->prefilter_funcs = $this->prefilter_funcs; $smarty_compiler->compiler_funcs = $this->compiler_funcs; - $smarty_compiler->security = $this->security; - $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; $smarty_compiler->security_settings = $this->security_settings; if ($smarty_compiler->_compile_file($tpl_file, $template_source, $template_compiled)) @@ -818,10 +820,10 @@ class Smarty $this->_trigger_error_msg("problem writing '$filename.'"); return false; } - - // flock doesn't seem to work on several windows platforms (98, NT4, NT5, ?), - // so we'll not use it at all in windows. - + + // flock doesn't seem to work on several windows platforms (98, NT4, NT5, ?), + // so we'll not use it at all in windows. + if ( strtoupper(substr(PHP_OS,0,3)) == 'WIN' || (flock($fd, LOCK_EX)) ) { fwrite( $fd, $contents ); fclose($fd); diff --git a/libs/Smarty_Compiler.class.php b/libs/Smarty_Compiler.class.php index 1a3fae49..fdb09f2a 100644 --- a/libs/Smarty_Compiler.class.php +++ b/libs/Smarty_Compiler.class.php @@ -43,7 +43,7 @@ class Smarty_Compiler extends Smarty { // internal vars var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part var $_literal_blocks = array(); // keeps literal template blocks - var $_php_blocks = array(); // keeps php code blocks + var $_php_blocks = array(); // keeps php code blocks var $_current_file = null; // the current template being compiled var $_current_line_no = 1; // line number for error messages @@ -54,18 +54,17 @@ class Smarty_Compiler extends Smarty { \*======================================================================*/ function _compile_file($tpl_file, $template_source, &$template_compiled) { - - if($this->security) { - // do not allow php syntax to be executed unless specified - if($this->php_handling == SMARTY_PHP_ALLOW && - !$this->security_settings["ALLOW_PHP_HANDLING"]) { - $this->php_handling = SMARTY_PHP_PASSTHRU; - } - } - + if($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + // run template source through functions registered in prefilter_funcs if (is_array($this->prefilter_funcs) && count($this->prefilter_funcs) > 0) { - foreach($this->prefilter_funcs as $prefilter) { + foreach ($this->prefilter_funcs as $prefilter) { if (function_exists($prefilter)) { $template_source = $prefilter($template_source); } else { @@ -83,14 +82,14 @@ class Smarty_Compiler extends Smarty { preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_source, $match); $this->_literal_blocks = $match[1]; $template_source = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", - $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source); + $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source); /* Pull out the php code blocks. */ preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $template_source, $match); $this->_php_blocks = $match[1]; $template_source = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", - $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source); - + $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source); + /* Gather all template tags. */ preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_source, $match); $template_tags = $match[1]; @@ -150,7 +149,7 @@ class Smarty_Compiler extends Smarty { for ($i = 0; $i < count($strip_tags); $i++) $template_compiled = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $this->quote_replace($strip_tags_modified[$i]), - $template_compiled, 1); + $template_compiled, 1); } // put header at the top of the compiled template @@ -180,8 +179,8 @@ class Smarty_Compiler extends Smarty { ) (?:\s+(.*))? /xs', $template_tag, $match); - $tag_command = $match[1]; - $tag_args = isset($match[2]) ? $match[2] : ''; + $tag_command = $match[1]; + $tag_args = isset($match[2]) ? $match[2] : ''; /* If the tag name matches a variable or section property definition, we simply process it. */ @@ -209,12 +208,12 @@ class Smarty_Compiler extends Smarty { case '/if': return ''; - case 'capture': - return ''; - - case '/capture': - return 'assign("return", ob_get_contents()); ob_end_clean(); ?>'; - + case 'capture': + return ''; + + case '/capture': + return 'assign("return", ob_get_contents()); ob_end_clean(); ?>'; + case 'ldelim': return $this->left_delimiter; @@ -248,23 +247,23 @@ class Smarty_Compiler extends Smarty { return "\n"; case 'php': - if($this->security && !$this->security_settings["ALLOW_PHP_TAGS"]) { + if ($this->security && !$this->security_settings['PHP_TAGS']) { $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING); - return; - } + return; + } list (,$php_block) = each($this->_php_blocks); $this->_current_line_no += substr_count($php_block, "\n"); return ''; - + case 'insert': return $this->_compile_insert_tag($tag_args); default: - if (isset($this->compiler_funcs[$tag_command])) { - return $this->_compile_compiler_tag($tag_command, $tag_args); - } else if (isset($this->custom_funcs[$tag_command])) { - return $this->_compile_custom_tag($tag_command, $tag_args); - } else { + if (isset($this->compiler_funcs[$tag_command])) { + return $this->_compile_compiler_tag($tag_command, $tag_args); + } else if (isset($this->custom_funcs[$tag_command])) { + return $this->_compile_custom_tag($tag_command, $tag_args); + } else { $this->_syntax_error("unknown tag - '$tag_command'", E_USER_WARNING); return; } @@ -273,20 +272,20 @@ class Smarty_Compiler extends Smarty { /*======================================================================*\ - Function: _compile_compiler_tag - Purpose: compile the custom compiler tag + Function: _compile_compiler_tag + Purpose: compile the custom compiler tag \*======================================================================*/ - function _compile_compiler_tag($tag_command, $tag_args) - { - $function = $this->compiler_funcs[$tag_command]; + function _compile_compiler_tag($tag_command, $tag_args) + { + $function = $this->compiler_funcs[$tag_command]; - if (!function_exists($function)) { - $this->_syntax_error("compiler function '$tag_command' is not implemented", E_USER_WARNING); - return; - } + if (!function_exists($function)) { + $this->_syntax_error("compiler function '$tag_command' is not implemented", E_USER_WARNING); + return; + } - return ''; - } + return ''; + } /*======================================================================*\ @@ -348,21 +347,21 @@ class Smarty_Compiler extends Smarty { $this->_syntax_error("missing 'file' attribute in config_load tag"); } - if (!empty($attrs['global']) && $attrs['global']) - $update_parent = true; - else - $update_parent = false; + if (!empty($attrs['global']) && $attrs['global']) + $update_parent = true; + else + $update_parent = false; $output = "_conf_obj->get(".$attrs['file']."));\n"; - if ($update_parent) - $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file']."));\n"; + "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file']."));\n"; + if ($update_parent) + $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file']."));\n"; if (!empty($attrs['section'])) { - $output .= "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; - if ($update_parent) - $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; - } + $output .= "\$_smarty_config = array_merge((array)\$_smarty_config, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; + if ($update_parent) + $output .= "\$_smarty_config_parent = array_merge((array)\$_smarty_config_parent, \$this->_conf_obj->get(".$attrs['file'].", ".$attrs['section']."));\n"; + } $output .= '?>'; @@ -382,21 +381,21 @@ class Smarty_Compiler extends Smarty { $this->_syntax_error("missing 'file' attribute in include tag"); } - foreach ($attrs as $arg_name => $arg_value) { - if ($arg_name == 'file') { - $include_file = $arg_value; + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; continue; } - if (is_bool($arg_value)) - $arg_value = $arg_value ? 'true' : 'false'; - $arg_list[] = "'$arg_name' => $arg_value"; - } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } - return "_tpl_vars;\n" . - "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."), \$_smarty_config);\n" . - "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . - "unset(\$_smarty_tpl_vars); ?>"; + return "_tpl_vars;\n" . + "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."), \$_smarty_config);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars); ?>"; } @@ -456,8 +455,8 @@ class Smarty_Compiler extends Smarty { $output .= "{$section_props}['rownum'] = {$section_props}['index'] + 1;\n"; $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - 1;\n"; $output .= "{$section_props}['index_next'] = {$section_props}['index'] + 1;\n"; - $output .= "{$section_props}['first'] = ({$section_props}['index'] == 0);\n"; - $output .= "{$section_props}['last'] = ({$section_props}['index'] == {$section_props}['loop']-1);\n"; + $output .= "{$section_props}['first'] = ({$section_props}['index'] == 0);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['index'] == {$section_props}['loop']-1);\n"; $output .= "?>"; @@ -485,7 +484,7 @@ class Smarty_Compiler extends Smarty { $is_arg_stack = array(); for ($i = 0; $i < count($tokens); $i++) { - + $token = &$tokens[$i]; switch ($token) { case 'eq': @@ -561,14 +560,15 @@ class Smarty_Compiler extends Smarty { current position for the next iteration. */ $i = $is_arg_start; break; - default: - if($this->security - && $tokens[$i+1] == '(' - && !preg_match("|[^a-zA-Z_-]|",$tokens[$i]) - && !in_array($tokens[$i],$this->security_settings["ALLOW_IF_FUNCS"])) { - $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement"); - } - break; + + default: + if($this->security && + $tokens[$i+1] == '(' && + !preg_match("|[^a-zA-Z_]|",$tokens[$i]) && + !in_array($tokens[$i], $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement"); + } + break; } } @@ -712,11 +712,11 @@ class Smarty_Compiler extends Smarty { return $attrs; } - + /*======================================================================*\ Function: _parse_vars_props Purpose: compile variables and section properties tokens into - PHP code + PHP code \*======================================================================*/ function _parse_vars_props(&$tokens) { @@ -752,28 +752,28 @@ class Smarty_Compiler extends Smarty { \*======================================================================*/ function _parse_var($var_expr) { - $parts = explode('|', substr($var_expr, 1), 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $parts = explode('|', substr($var_expr, 1), 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; - preg_match_all('!\[\w+(\.\w+)?\]|(->|\.)\w+|^\w+!', $var_ref, $match); - $indexes = $match[0]; + preg_match_all('!\[\w+(\.\w+)?\]|(->|\.)\w+|^\w+!', $var_ref, $match); + $indexes = $match[0]; $var_name = array_shift($indexes); $output = "\$this->_tpl_vars['$var_name']"; - foreach ($indexes as $index) { - if ($index{0} == '[') { - $parts = explode('.', substr($index, 1, -1)); - $section = $parts[0]; - $section_prop = isset($parts[1]) ? $parts[1] : 'index'; - $output .= "[\$this->_sections['$section']['properties']['$section_prop']]"; - } else if ($index{0} == '.') { - $output .= "['" . substr($index, 1) . "']"; - } else { - $output .= $index; - } - } + foreach ($indexes as $index) { + if ($index{0} == '[') { + $parts = explode('.', substr($index, 1, -1)); + $section = $parts[0]; + $section_prop = isset($parts[1]) ? $parts[1] : 'index'; + $output .= "[\$this->_sections['$section']['properties']['$section_prop']]"; + } else if ($index{0} == '.') { + $output .= "['" . substr($index, 1) . "']"; + } else { + $output .= $index; + } + } $this->_parse_modifiers($output, $modifiers); @@ -788,8 +788,8 @@ class Smarty_Compiler extends Smarty { function _parse_conf_var($conf_var_expr) { $parts = explode('|', $conf_var_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; $var_name = substr($var_ref, 1, -1); @@ -808,8 +808,8 @@ class Smarty_Compiler extends Smarty { function _parse_section_prop($section_prop_expr) { $parts = explode('|', $section_prop_expr, 2); - $var_ref = $parts[0]; - $modifiers = isset($parts[1]) ? $parts[1] : ''; + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); $section_name = $match[1]; @@ -855,13 +855,13 @@ class Smarty_Compiler extends Smarty { * function name. */ if (!isset($mod_func_name)) { - if($this->security && !in_array($modifier_name,$this->security_settings["ALLOW_MODIFIER_FUNCS"])) { - $this->_syntax_error("(secure mode) modifier '$modifier_name' is not allowed", E_USER_WARNING); - continue; - } else { - $mod_func_name = $modifier_name; - } - } + if ($this->security && !in_array($modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_syntax_error("(secure mode) modifier '$modifier_name' is not allowed", E_USER_WARNING); + continue; + } else { + $mod_func_name = $modifier_name; + } + } if (!function_exists($mod_func_name)) { $this->_syntax_error("modifier '$modifier_name' is not implemented", E_USER_WARNING);