📄 smarty_compiler.class.php
字号:
$expr = "($is_arg % 2)"; break; case 'div': if (@$tokens[$expr_end] == 'by') { $expr_end++; $expr_arg = $tokens[$expr_end++]; $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; } else { $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); } break; default: $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); break; } if ($negate_expr) { $expr = "!($expr)"; } array_splice($tokens, 0, $expr_end, $expr); return $tokens; } /** * Parse attribute string * * @param string $tag_args * @return array */ function _parse_attrs($tag_args) { /* Tokenize tag attributes. */ preg_match_all('/(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) )+ | [=] /x', $tag_args, $match); $tokens = $match[0]; $attrs = array(); /* Parse state: 0 - expecting attribute name 1 - expecting '=' 2 - expecting attribute value (not '=') */ $state = 0; foreach ($tokens as $token) { switch ($state) { case 0: /* If the token is a valid identifier, we set attribute name and go to state 1. */ if (preg_match('!^\w+$!', $token)) { $attr_name = $token; $state = 1; } else $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); break; case 1: /* If the token is '=', then we go to state 2. */ if ($token == '=') { $state = 2; } else $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); break; case 2: /* If token is not '=', we set the attribute value and go to state 0. */ if ($token != '=') { /* We booleanize the token if it's a non-quoted possible boolean value. */ if (preg_match('!^(on|yes|true)$!', $token)) { $token = 'true'; } else if (preg_match('!^(off|no|false)$!', $token)) { $token = 'false'; } else if ($token == 'null') { $token = 'null'; } else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) { /* treat integer literally */ } else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) { /* treat as a string, double-quote it escaping quotes */ $token = '"'.addslashes($token).'"'; } $attrs[$attr_name] = $token; $state = 0; } else $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); break; } $last_token = $token; } if($state != 0) { if($state == 1) { $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); } else { $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); } } $this->_parse_vars_props($attrs); return $attrs; } /** * compile multiple variables and section properties tokens into * PHP code * * @param array $tokens */ function _parse_vars_props(&$tokens) { foreach($tokens as $key => $val) { $tokens[$key] = $this->_parse_var_props($val); } } /** * compile single variable and section properties token into * PHP code * * @param string $val * @param string $tag_attrs * @return string */ function _parse_var_props($val, $tag_attrs = null) { $val = trim($val); if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(?:' . $this->_mod_regexp . '*)$!', $val)) { // $ variable or object return $this->_parse_var($val); } elseif(preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { // double quoted text preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); $return = $this->_expand_quoted_text($match[1]); if($match[2] != '') { $this->_parse_modifiers($return, $match[2]); } return $return; } elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { // single quoted text preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match); if($match[2] != '') { $this->_parse_modifiers($match[1], $match[2]); return $match[1]; } } elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { // config var return $this->_parse_conf_var($val); } elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) { // section var return $this->_parse_section_prop($val); } elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { // literal string return $this->_expand_quoted_text('"' . $val .'"'); } return $val; } /** * expand quoted text with embedded variables * * @param string $var_expr * @return string */ function _expand_quoted_text($var_expr) { // if contains unescaped $, expand it if(preg_match_all('%(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)%', $var_expr, $_match)) { $_match = $_match[0]; rsort($_match); reset($_match); foreach($_match as $_var) { $var_expr = str_replace ($_var, '".' . $this->_parse_var(str_replace('`','',$_var)) . '."', $var_expr); } $_return = preg_replace('%\.""|(?<!\\\\)""\.%', '', $var_expr); } else { $_return = $var_expr; } // replace double quoted literal string with single quotes $_return = preg_replace('!^"([\s\w]+)"$!',"'\\1'",$_return); return $_return; } /** * parse variable expression into PHP code or static value * * @param string $var_expr * @return string */ function _parse_var($var_expr) { // inform the calling expression the return type (php, static) $this->_output_type = 'php'; $_math_vars = preg_split('!('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); if(count($_math_vars) > 1) { $_output = ""; $_complete_var = ""; // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) $_has_math = false; foreach($_math_vars as $_k => $_math_var) { $_math_var = $_math_vars[$_k]; if(!empty($_math_var)) { // hit a math operator, so process the stuff which came before it if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) { $_has_math = true; if(!empty($_complete_var)) { $_output .= $this->_parse_var($_complete_var); } // just output the math operator to php $_output .= $_math_var; $_complete_var = ""; } else { // fetch multiple -> (like $foo->bar->baz ) which wouldn't get fetched else, because it would only get $foo->bar and treat the ->baz as "-" ">baz" then for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) { // fetch -> because it gets splitted at - and move it back together if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) { $_math_var .= $_math_vars[$_i].$_math_vars[$_i+1]; $_math_vars[$_i] = $_math_vars[$_i+1] = ''; } else break; } $_complete_var .= $_math_var; } } } if($_has_math) { if(!empty($_complete_var)) $_output .= $this->_parse_var($_complete_var); return $_output; } } preg_match('!(' . $this->_dvar_num_var_regexp . '*|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . ')(' . $this->_mod_regexp . '*)$!', $var_expr, $match); // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) if(!is_numeric($match[1]{0})) $_var_ref = substr($match[1],1); else $_var_ref = $match[1]; $modifiers = $match[2]; if(!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) { $_default_mod_string = implode('|',(array)$this->default_modifiers); $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; } // get [foo] and .foo and ->foo and (...) pieces preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match); $_indexes = $match[0]; $_var_name = array_shift($_indexes); /* Handle $smarty.* variable references as a special case. */ if ($_var_name == 'smarty') { /* * If the reference could be compiled, use the compiled output; * otherwise, fall back on the $smarty variable generated at * run-time. */ if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { $_output = $smarty_ref; } else { $_var_name = substr(array_shift($_indexes), 1); $_output = "\$this->_smarty_vars['$_var_name']"; } } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) { // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers if(count($_indexes) > 0) { $_var_name .= implode("", $_indexes); $_indexes = array(); } $_output = $_var_name; } else { $_output = "\$this->_tpl_vars['$_var_name']"; } foreach ($_indexes as $_index) { if ($_index{0} == '[') { $_index = substr($_index, 1, -1); if (is_numeric($_index)) { $_output .= "[$_index]"; } elseif ($_index{0} == '$') { $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; } else { $_var_parts = explode('.', $_index); $_var_section = $_var_parts[0]; $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; } } else if ($_index{0} == '.') { if ($_index{1} == '$') $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; else $_output .= "['" . substr($_index, 1) . "']"; } else if (substr($_index,0,2) == '->') { if(substr($_index,2,2) == '__') { $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); } elseif($this->security && substr($_index, 2, 1) == '_') { $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); } elseif ($_index{2} == '$') { if ($this->security) { $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); } else { $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; } } else { $_output .= $_index; } } elseif ($_index{0} == '(') { $_ind
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -