00001 <?php 00002 00029 /* $Id: Smarty_Compiler.class.php 3163 2009-06-17 14:39:24Z monte.ohrt $ */ 00030 00035 class Smarty_Compiler extends Smarty { 00036 00037 // internal vars 00041 var $_folded_blocks = array(); // keeps folded template blocks 00042 var $_current_file = null; // the current template being compiled 00043 var $_current_line_no = 1; // line number for error messages 00044 var $_capture_stack = array(); // keeps track of nested capture buffers 00045 var $_plugin_info = array(); // keeps track of plugins to load 00046 var $_init_smarty_vars = false; 00047 var $_permitted_tokens = array('true','false','yes','no','on','off','null'); 00048 var $_db_qstr_regexp = null; // regexps are setup in the constructor 00049 var $_si_qstr_regexp = null; 00050 var $_qstr_regexp = null; 00051 var $_func_regexp = null; 00052 var $_reg_obj_regexp = null; 00053 var $_var_bracket_regexp = null; 00054 var $_num_const_regexp = null; 00055 var $_dvar_guts_regexp = null; 00056 var $_dvar_regexp = null; 00057 var $_cvar_regexp = null; 00058 var $_svar_regexp = null; 00059 var $_avar_regexp = null; 00060 var $_mod_regexp = null; 00061 var $_var_regexp = null; 00062 var $_parenth_param_regexp = null; 00063 var $_func_call_regexp = null; 00064 var $_obj_ext_regexp = null; 00065 var $_obj_start_regexp = null; 00066 var $_obj_params_regexp = null; 00067 var $_obj_call_regexp = null; 00068 var $_cacheable_state = 0; 00069 var $_cache_attrs_count = 0; 00070 var $_nocache_count = 0; 00071 var $_cache_serial = null; 00072 var $_cache_include = null; 00073 00074 var $_strip_depth = 0; 00075 var $_additional_newline = "\n"; 00076 00081 function Smarty_Compiler() 00082 { 00083 // matches double quoted strings: 00084 // "foobar" 00085 // "foo\"bar" 00086 $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; 00087 00088 // matches single quoted strings: 00089 // 'foobar' 00090 // 'foo\'bar' 00091 $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; 00092 00093 // matches single or double quoted strings 00094 $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; 00095 00096 // matches bracket portion of vars 00097 // [0] 00098 // [foo] 00099 // [$bar] 00100 $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; 00101 00102 // matches numerical constants 00103 // 30 00104 // -12 00105 // 13.22 00106 $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; 00107 00108 // matches $ vars (not objects): 00109 // $foo 00110 // $foo.bar 00111 // $foo.bar.foobar 00112 // $foo[0] 00113 // $foo[$bar] 00114 // $foo[5][blah] 00115 // $foo[5].bar[$foobar][4] 00116 $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; 00117 $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d>\[\]]'; 00118 $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp 00119 . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; 00120 $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; 00121 00122 // matches config vars: 00123 // #foo# 00124 // #foobar123_foo# 00125 $this->_cvar_regexp = '\#\w+\#'; 00126 00127 // matches section vars: 00128 // %foo.bar% 00129 $this->_svar_regexp = '\%\w+\.\w+\%'; 00130 00131 // matches all valid variables (no quotes, no modifiers) 00132 $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' 00133 . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; 00134 00135 // matches valid variable syntax: 00136 // $foo 00137 // $foo 00138 // #foo# 00139 // #foo# 00140 // "text" 00141 // "text" 00142 $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; 00143 00144 // matches valid object call (one level of object nesting allowed in parameters): 00145 // $foo->bar 00146 // $foo->bar() 00147 // $foo->bar("text") 00148 // $foo->bar($foo, $bar, "text") 00149 // $foo->bar($foo, "foo") 00150 // $foo->bar->foo() 00151 // $foo->bar->foo->bar() 00152 // $foo->bar($foo->bar) 00153 // $foo->bar($foo->bar()) 00154 // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) 00155 $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; 00156 $this->_obj_restricted_param_regexp = '(?:' 00157 . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' 00158 . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; 00159 $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' 00160 . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; 00161 $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp 00162 . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; 00163 $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; 00164 $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; 00165 00166 // matches valid modifier syntax: 00167 // |foo 00168 // |@foo 00169 // |foo:"bar" 00170 // |foo:$bar 00171 // |foo:"bar":$foobar 00172 // |foo|bar 00173 // |foo:$foo->bar 00174 $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' 00175 . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; 00176 00177 // matches valid function name: 00178 // foo123 00179 // _foo_bar 00180 $this->_func_regexp = '[a-zA-Z_]\w*'; 00181 00182 // matches valid registered object: 00183 // foo->bar 00184 $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; 00185 00186 // matches valid parameter values: 00187 // true 00188 // $foo 00189 // $foo|bar 00190 // #foo# 00191 // #foo#|bar 00192 // "text" 00193 // "text"|bar 00194 // $foo->bar 00195 $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' 00196 . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; 00197 00198 // matches valid parenthesised function parameters: 00199 // 00200 // "text" 00201 // $foo, $bar, "text" 00202 // $foo|bar, "foo"|bar, $foo->bar($foo)|bar 00203 $this->_parenth_param_regexp = '(?:\((?:\w+|' 00204 . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' 00205 . $this->_param_regexp . ')))*)?\))'; 00206 00207 // matches valid function call: 00208 // foo() 00209 // foo_bar($foo) 00210 // _foo_bar($foo,"bar") 00211 // foo123($foo,$foo->bar(),"foo") 00212 $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' 00213 . $this->_parenth_param_regexp . '))'; 00214 } 00215 00225 function _compile_file($resource_name, $source_content, &$compiled_content) 00226 { 00227 00228 if ($this->security) { 00229 // do not allow php syntax to be executed unless specified 00230 if ($this->php_handling == SMARTY_PHP_ALLOW && 00231 !$this->security_settings['PHP_HANDLING']) { 00232 $this->php_handling = SMARTY_PHP_PASSTHRU; 00233 } 00234 } 00235 00236 $this->_load_filters(); 00237 00238 $this->_current_file = $resource_name; 00239 $this->_current_line_no = 1; 00240 $ldq = preg_quote($this->left_delimiter, '~'); 00241 $rdq = preg_quote($this->right_delimiter, '~'); 00242 00243 // run template source through prefilter functions 00244 if (count($this->_plugins['prefilter']) > 0) { 00245 foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { 00246 if ($prefilter === false) continue; 00247 if ($prefilter[3] || is_callable($prefilter[0])) { 00248 $source_content = call_user_func_array($prefilter[0], 00249 array($source_content, &$this)); 00250 $this->_plugins['prefilter'][$filter_name][3] = true; 00251 } else { 00252 $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); 00253 } 00254 } 00255 } 00256 00257 /* fetch all special blocks */ 00258 $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; 00259 00260 preg_match_all($search, $source_content, $match, PREG_SET_ORDER); 00261 $this->_folded_blocks = $match; 00262 reset($this->_folded_blocks); 00263 00264 /* replace special blocks by "{php}" */ 00265 $source_content = preg_replace($search.'e', "'" 00266 . $this->_quote_replace($this->left_delimiter) . 'php' 00267 . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" 00268 . $this->_quote_replace($this->right_delimiter) 00269 . "'" 00270 , $source_content); 00271 00272 /* Gather all template tags. */ 00273 preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); 00274 $template_tags = $_match[1]; 00275 /* Split content by template tags to obtain non-template content. */ 00276 $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); 00277 00278 /* loop through text blocks */ 00279 for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { 00280 /* match anything resembling php tags */ 00281 if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { 00282 /* replace tags with placeholders to prevent recursive replacements */ 00283 $sp_match[1] = array_unique($sp_match[1]); 00284 usort($sp_match[1], '_smarty_sort_length'); 00285 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { 00286 $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); 00287 } 00288 /* process each one */ 00289 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { 00290 if ($this->php_handling == SMARTY_PHP_PASSTHRU) { 00291 /* echo php contents */ 00292 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]); 00293 } else if ($this->php_handling == SMARTY_PHP_QUOTE) { 00294 /* quote php tags */ 00295 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); 00296 } else if ($this->php_handling == SMARTY_PHP_REMOVE) { 00297 /* remove php tags */ 00298 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); 00299 } else { 00300 /* SMARTY_PHP_ALLOW, but echo non php starting tags */ 00301 $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]); 00302 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); 00303 } 00304 } 00305 } 00306 } 00307 00308 /* Compile the template tags into PHP code. */ 00309 $compiled_tags = array(); 00310 for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { 00311 $this->_current_line_no += substr_count($text_blocks[$i], "\n"); 00312 $compiled_tags[] = $this->_compile_tag($template_tags[$i]); 00313 $this->_current_line_no += substr_count($template_tags[$i], "\n"); 00314 } 00315 if (count($this->_tag_stack)>0) { 00316 list($_open_tag, $_line_no) = end($this->_tag_stack); 00317 $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); 00318 return; 00319 } 00320 00321 /* Reformat $text_blocks between 'strip' and '/strip' tags, 00322 removing spaces, tabs and newlines. */ 00323 $strip = false; 00324 for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { 00325 if ($compiled_tags[$i] == '{strip}') { 00326 $compiled_tags[$i] = ''; 00327 $strip = true; 00328 /* remove leading whitespaces */ 00329 $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); 00330 } 00331 if ($strip) { 00332 /* strip all $text_blocks before the next '/strip' */ 00333 for ($j = $i + 1; $j < $for_max; $j++) { 00334 /* remove leading and trailing whitespaces of each line */ 00335 $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); 00336 if ($compiled_tags[$j] == '{/strip}') { 00337 /* remove trailing whitespaces from the last text_block */ 00338 $text_blocks[$j] = rtrim($text_blocks[$j]); 00339 } 00340 $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>"; 00341 if ($compiled_tags[$j] == '{/strip}') { 00342 $compiled_tags[$j] = "\n"; /* slurped by php, but necessary 00343 if a newline is following the closing strip-tag */ 00344 $strip = false; 00345 $i = $j; 00346 break; 00347 } 00348 } 00349 } 00350 } 00351 $compiled_content = ''; 00352 00353 $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; 00354 00355 /* Interleave the compiled contents and text blocks to get the final result. */ 00356 for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { 00357 if ($compiled_tags[$i] == '') { 00358 // tag result empty, remove first newline from following text block 00359 $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); 00360 } 00361 // replace legit PHP tags with placeholder 00362 $text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]); 00363 $compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]); 00364 00365 $compiled_content .= $text_blocks[$i] . $compiled_tags[$i]; 00366 } 00367 $compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]); 00368 00369 // escape php tags created by interleaving 00370 $compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content); 00371 $compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content); 00372 00373 // recover legit tags 00374 $compiled_content = str_replace($tag_guard, '<?', $compiled_content); 00375 00376 // remove \n from the end of the file, if any 00377 if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) { 00378 $compiled_content = substr($compiled_content, 0, -1); 00379 } 00380 00381 if (!empty($this->_cache_serial)) { 00382 $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; 00383 } 00384 00385 // run compiled template through postfilter functions 00386 if (count($this->_plugins['postfilter']) > 0) { 00387 foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { 00388 if ($postfilter === false) continue; 00389 if ($postfilter[3] || is_callable($postfilter[0])) { 00390 $compiled_content = call_user_func_array($postfilter[0], 00391 array($compiled_content, &$this)); 00392 $this->_plugins['postfilter'][$filter_name][3] = true; 00393 } else { 00394 $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); 00395 } 00396 } 00397 } 00398 00399 // put header at the top of the compiled template 00400 $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; 00401 $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; 00402 00403 /* Emit code to load needed plugins. */ 00404 $this->_plugins_code = ''; 00405 if (count($this->_plugin_info)) { 00406 $_plugins_params = "array('plugins' => array("; 00407 foreach ($this->_plugin_info as $plugin_type => $plugins) { 00408 foreach ($plugins as $plugin_name => $plugin_info) { 00409 $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; 00410 $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; 00411 } 00412 } 00413 $_plugins_params .= '))'; 00414 $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n"; 00415 $template_header .= $plugins_code; 00416 $this->_plugin_info = array(); 00417 $this->_plugins_code = $plugins_code; 00418 } 00419 00420 if ($this->_init_smarty_vars) { 00421 $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n"; 00422 $this->_init_smarty_vars = false; 00423 } 00424 00425 $compiled_content = $template_header . $compiled_content; 00426 return true; 00427 } 00428 00435 function _compile_tag($template_tag) 00436 { 00437 /* Matched comment. */ 00438 if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') 00439 return ''; 00440 00441 /* Split tag into two three parts: command, command modifiers and the arguments. */ 00442 if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp 00443 . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) 00444 (?:\s+(.*))?$ 00445 ~xs', $template_tag, $match)) { 00446 $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); 00447 } 00448 00449 $tag_command = $match[1]; 00450 $tag_modifier = isset($match[2]) ? $match[2] : null; 00451 $tag_args = isset($match[3]) ? $match[3] : null; 00452 00453 if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { 00454 /* tag name is a variable or object */ 00455 $_return = $this->_parse_var_props($tag_command . $tag_modifier); 00456 return "<?php echo $_return; ?>" . $this->_additional_newline; 00457 } 00458 00459 /* If the tag name is a registered object, we process it. */ 00460 if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { 00461 return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); 00462 } 00463 00464 switch ($tag_command) { 00465 case 'include': 00466 return $this->_compile_include_tag($tag_args); 00467 00468 case 'include_php': 00469 return $this->_compile_include_php_tag($tag_args); 00470 00471 case 'if': 00472 $this->_push_tag('if'); 00473 return $this->_compile_if_tag($tag_args); 00474 00475 case 'else': 00476 list($_open_tag) = end($this->_tag_stack); 00477 if ($_open_tag != 'if' && $_open_tag != 'elseif') 00478 $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); 00479 else 00480 $this->_push_tag('else'); 00481 return '<?php else: ?>'; 00482 00483 case 'elseif': 00484 list($_open_tag) = end($this->_tag_stack); 00485 if ($_open_tag != 'if' && $_open_tag != 'elseif') 00486 $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); 00487 if ($_open_tag == 'if') 00488 $this->_push_tag('elseif'); 00489 return $this->_compile_if_tag($tag_args, true); 00490 00491 case '/if': 00492 $this->_pop_tag('if'); 00493 return '<?php endif; ?>'; 00494 00495 case 'capture': 00496 return $this->_compile_capture_tag(true, $tag_args); 00497 00498 case '/capture': 00499 return $this->_compile_capture_tag(false); 00500 00501 case 'ldelim': 00502 return $this->left_delimiter; 00503 00504 case 'rdelim': 00505 return $this->right_delimiter; 00506 00507 case 'section': 00508 $this->_push_tag('section'); 00509 return $this->_compile_section_start($tag_args); 00510 00511 case 'sectionelse': 00512 $this->_push_tag('sectionelse'); 00513 return "<?php endfor; else: ?>"; 00514 break; 00515 00516 case '/section': 00517 $_open_tag = $this->_pop_tag('section'); 00518 if ($_open_tag == 'sectionelse') 00519 return "<?php endif; ?>"; 00520 else 00521 return "<?php endfor; endif; ?>"; 00522 00523 case 'foreach': 00524 $this->_push_tag('foreach'); 00525 return $this->_compile_foreach_start($tag_args); 00526 break; 00527 00528 case 'foreachelse': 00529 $this->_push_tag('foreachelse'); 00530 return "<?php endforeach; else: ?>"; 00531 00532 case '/foreach': 00533 $_open_tag = $this->_pop_tag('foreach'); 00534 if ($_open_tag == 'foreachelse') 00535 return "<?php endif; unset(\$_from); ?>"; 00536 else 00537 return "<?php endforeach; endif; unset(\$_from); ?>"; 00538 break; 00539 00540 case 'strip': 00541 case '/strip': 00542 if (substr($tag_command, 0, 1)=='/') { 00543 $this->_pop_tag('strip'); 00544 if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ 00545 $this->_additional_newline = "\n"; 00546 return '{' . $tag_command . '}'; 00547 } 00548 } else { 00549 $this->_push_tag('strip'); 00550 if ($this->_strip_depth++==0) { /* outermost opening {strip} */ 00551 $this->_additional_newline = ""; 00552 return '{' . $tag_command . '}'; 00553 } 00554 } 00555 return ''; 00556 00557 case 'php': 00558 /* handle folded tags replaced by {php} */ 00559 list(, $block) = each($this->_folded_blocks); 00560 $this->_current_line_no += substr_count($block[0], "\n"); 00561 /* the number of matched elements in the regexp in _compile_file() 00562 determins the type of folded tag that was found */ 00563 switch (count($block)) { 00564 case 2: /* comment */ 00565 return ''; 00566 00567 case 3: /* literal */ 00568 return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; 00569 00570 case 4: /* php */ 00571 if ($this->security && !$this->security_settings['PHP_TAGS']) { 00572 $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); 00573 return; 00574 } 00575 return '<?php ' . $block[3] .' ?>'; 00576 } 00577 break; 00578 00579 case 'insert': 00580 return $this->_compile_insert_tag($tag_args); 00581 00582 default: 00583 if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { 00584 return $output; 00585 } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { 00586 return $output; 00587 } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { 00588 return $output; 00589 } else { 00590 $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); 00591 } 00592 00593 } 00594 } 00595 00596 00606 function _compile_compiler_tag($tag_command, $tag_args, &$output) 00607 { 00608 $found = false; 00609 $have_function = true; 00610 00611 /* 00612 * First we check if the compiler function has already been registered 00613 * or loaded from a plugin file. 00614 */ 00615 if (isset($this->_plugins['compiler'][$tag_command])) { 00616 $found = true; 00617 $plugin_func = $this->_plugins['compiler'][$tag_command][0]; 00618 if (!is_callable($plugin_func)) { 00619 $message = "compiler function '$tag_command' is not implemented"; 00620 $have_function = false; 00621 } 00622 } 00623 /* 00624 * Otherwise we need to load plugin file and look for the function 00625 * inside it. 00626 */ 00627 else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { 00628 $found = true; 00629 00630 include_once $plugin_file; 00631 00632 $plugin_func = 'smarty_compiler_' . $tag_command; 00633 if (!is_callable($plugin_func)) { 00634 $message = "plugin function $plugin_func() not found in $plugin_file\n"; 00635 $have_function = false; 00636 } else { 00637 $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); 00638 } 00639 } 00640 00641 /* 00642 * True return value means that we either found a plugin or a 00643 * dynamically registered function. False means that we didn't and the 00644 * compiler should now emit code to load custom function plugin for this 00645 * tag. 00646 */ 00647 if ($found) { 00648 if ($have_function) { 00649 $output = call_user_func_array($plugin_func, array($tag_args, &$this)); 00650 if($output != '') { 00651 $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command) 00652 . $output 00653 . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; 00654 } 00655 } else { 00656 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); 00657 } 00658 return true; 00659 } else { 00660 return false; 00661 } 00662 } 00663 00664 00675 function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) 00676 { 00677 if (substr($tag_command, 0, 1) == '/') { 00678 $start_tag = false; 00679 $tag_command = substr($tag_command, 1); 00680 } else 00681 $start_tag = true; 00682 00683 $found = false; 00684 $have_function = true; 00685 00686 /* 00687 * First we check if the block function has already been registered 00688 * or loaded from a plugin file. 00689 */ 00690 if (isset($this->_plugins['block'][$tag_command])) { 00691 $found = true; 00692 $plugin_func = $this->_plugins['block'][$tag_command][0]; 00693 if (!is_callable($plugin_func)) { 00694 $message = "block function '$tag_command' is not implemented"; 00695 $have_function = false; 00696 } 00697 } 00698 /* 00699 * Otherwise we need to load plugin file and look for the function 00700 * inside it. 00701 */ 00702 else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { 00703 $found = true; 00704 00705 include_once $plugin_file; 00706 00707 $plugin_func = 'smarty_block_' . $tag_command; 00708 if (!function_exists($plugin_func)) { 00709 $message = "plugin function $plugin_func() not found in $plugin_file\n"; 00710 $have_function = false; 00711 } else { 00712 $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); 00713 00714 } 00715 } 00716 00717 if (!$found) { 00718 return false; 00719 } else if (!$have_function) { 00720 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); 00721 return true; 00722 } 00723 00724 /* 00725 * Even though we've located the plugin function, compilation 00726 * happens only once, so the plugin will still need to be loaded 00727 * at runtime for future requests. 00728 */ 00729 $this->_add_plugin('block', $tag_command); 00730 00731 if ($start_tag) 00732 $this->_push_tag($tag_command); 00733 else 00734 $this->_pop_tag($tag_command); 00735 00736 if ($start_tag) { 00737 $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command); 00738 $attrs = $this->_parse_attrs($tag_args); 00739 $_cache_attrs=''; 00740 $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); 00741 $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; 00742 $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; 00743 $output .= 'while ($_block_repeat) { ob_start(); ?>'; 00744 } else { 00745 $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); '; 00746 $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; 00747 if ($tag_modifier != '') { 00748 $this->_parse_modifiers($_out_tag_text, $tag_modifier); 00749 } 00750 $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; 00751 $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; 00752 } 00753 00754 return true; 00755 } 00756 00757 00766 function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) 00767 { 00768 $found = false; 00769 $have_function = true; 00770 00771 /* 00772 * First we check if the custom function has already been registered 00773 * or loaded from a plugin file. 00774 */ 00775 if (isset($this->_plugins['function'][$tag_command])) { 00776 $found = true; 00777 $plugin_func = $this->_plugins['function'][$tag_command][0]; 00778 if (!is_callable($plugin_func)) { 00779 $message = "custom function '$tag_command' is not implemented"; 00780 $have_function = false; 00781 } 00782 } 00783 /* 00784 * Otherwise we need to load plugin file and look for the function 00785 * inside it. 00786 */ 00787 else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { 00788 $found = true; 00789 00790 include_once $plugin_file; 00791 00792 $plugin_func = 'smarty_function_' . $tag_command; 00793 if (!function_exists($plugin_func)) { 00794 $message = "plugin function $plugin_func() not found in $plugin_file\n"; 00795 $have_function = false; 00796 } else { 00797 $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); 00798 00799 } 00800 } 00801 00802 if (!$found) { 00803 return false; 00804 } else if (!$have_function) { 00805 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); 00806 return true; 00807 } 00808 00809 /* declare plugin to be loaded on display of the template that 00810 we compile right now */ 00811 $this->_add_plugin('function', $tag_command); 00812 00813 $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); 00814 $attrs = $this->_parse_attrs($tag_args); 00815 $_cache_attrs = ''; 00816 $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); 00817 00818 $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; 00819 if($tag_modifier != '') { 00820 $this->_parse_modifiers($output, $tag_modifier); 00821 } 00822 00823 if($output != '') { 00824 $output = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';' 00825 . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; 00826 } 00827 00828 return true; 00829 } 00830 00839 function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) 00840 { 00841 if (substr($tag_command, 0, 1) == '/') { 00842 $start_tag = false; 00843 $tag_command = substr($tag_command, 1); 00844 } else { 00845 $start_tag = true; 00846 } 00847 00848 list($object, $obj_comp) = explode('->', $tag_command); 00849 00850 $arg_list = array(); 00851 if(count($attrs)) { 00852 $_assign_var = false; 00853 foreach ($attrs as $arg_name => $arg_value) { 00854 if($arg_name == 'assign') { 00855 $_assign_var = $arg_value; 00856 unset($attrs['assign']); 00857 continue; 00858 } 00859 if (is_bool($arg_value)) 00860 $arg_value = $arg_value ? 'true' : 'false'; 00861 $arg_list[] = "'$arg_name' => $arg_value"; 00862 } 00863 } 00864 00865 if($this->_reg_objects[$object][2]) { 00866 // smarty object argument format 00867 $args = "array(".implode(',', (array)$arg_list)."), \$this"; 00868 } else { 00869 // traditional argument format 00870 $args = implode(',', array_values($attrs)); 00871 if (empty($args)) { 00872 $args = ''; 00873 } 00874 } 00875 00876 $prefix = ''; 00877 $postfix = ''; 00878 $newline = ''; 00879 if(!is_object($this->_reg_objects[$object][0])) { 00880 $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); 00881 } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { 00882 $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); 00883 } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { 00884 // method 00885 if(in_array($obj_comp, $this->_reg_objects[$object][3])) { 00886 // block method 00887 if ($start_tag) { 00888 $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; 00889 $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; 00890 $prefix .= "while (\$_block_repeat) { ob_start();"; 00891 $return = null; 00892 $postfix = ''; 00893 } else { 00894 $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; 00895 $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; 00896 $postfix = "} array_pop(\$this->_tag_stack);"; 00897 } 00898 } else { 00899 // non-block method 00900 $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; 00901 } 00902 } else { 00903 // property 00904 $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; 00905 } 00906 00907 if($return != null) { 00908 if($tag_modifier != '') { 00909 $this->_parse_modifiers($return, $tag_modifier); 00910 } 00911 00912 if(!empty($_assign_var)) { 00913 $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; 00914 } else { 00915 $output = 'echo ' . $return . ';'; 00916 $newline = $this->_additional_newline; 00917 } 00918 } else { 00919 $output = ''; 00920 } 00921 00922 return '<?php ' . $prefix . $output . $postfix . "?>" . $newline; 00923 } 00924 00931 function _compile_insert_tag($tag_args) 00932 { 00933 $attrs = $this->_parse_attrs($tag_args); 00934 $name = $this->_dequote($attrs['name']); 00935 00936 if (empty($name)) { 00937 return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); 00938 } 00939 00940 if (!preg_match('~^\w+$~', $name)) { 00941 return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); 00942 } 00943 00944 if (!empty($attrs['script'])) { 00945 $delayed_loading = true; 00946 } else { 00947 $delayed_loading = false; 00948 } 00949 00950 foreach ($attrs as $arg_name => $arg_value) { 00951 if (is_bool($arg_value)) 00952 $arg_value = $arg_value ? 'true' : 'false'; 00953 $arg_list[] = "'$arg_name' => $arg_value"; 00954 } 00955 00956 $this->_add_plugin('insert', $name, $delayed_loading); 00957 00958 $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; 00959 00960 return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline; 00961 } 00962 00969 function _compile_include_tag($tag_args) 00970 { 00971 $attrs = $this->_parse_attrs($tag_args); 00972 $arg_list = array(); 00973 00974 if (empty($attrs['file'])) { 00975 $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); 00976 } 00977 00978 foreach ($attrs as $arg_name => $arg_value) { 00979 if ($arg_name == 'file') { 00980 $include_file = $arg_value; 00981 continue; 00982 } else if ($arg_name == 'assign') { 00983 $assign_var = $arg_value; 00984 continue; 00985 } 00986 if (is_bool($arg_value)) 00987 $arg_value = $arg_value ? 'true' : 'false'; 00988 $arg_list[] = "'$arg_name' => $arg_value"; 00989 } 00990 00991 $output = '<?php '; 00992 00993 if (isset($assign_var)) { 00994 $output .= "ob_start();\n"; 00995 } 00996 00997 $output .= 00998 "\$_smarty_tpl_vars = \$this->_tpl_vars;\n"; 00999 01000 01001 $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; 01002 $output .= "\$this->_smarty_include($_params);\n" . 01003 "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . 01004 "unset(\$_smarty_tpl_vars);\n"; 01005 01006 if (isset($assign_var)) { 01007 $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; 01008 } 01009 01010 $output .= ' ?>'; 01011 01012 return $output; 01013 01014 } 01015 01022 function _compile_include_php_tag($tag_args) 01023 { 01024 $attrs = $this->_parse_attrs($tag_args); 01025 01026 if (empty($attrs['file'])) { 01027 $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); 01028 } 01029 01030 $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); 01031 $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; 01032 01033 $arg_list = array(); 01034 foreach($attrs as $arg_name => $arg_value) { 01035 if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { 01036 if(is_bool($arg_value)) 01037 $arg_value = $arg_value ? 'true' : 'false'; 01038 $arg_list[] = "'$arg_name' => $arg_value"; 01039 } 01040 } 01041 01042 $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; 01043 01044 return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline; 01045 } 01046 01047 01054 function _compile_section_start($tag_args) 01055 { 01056 $attrs = $this->_parse_attrs($tag_args); 01057 $arg_list = array(); 01058 01059 $output = '<?php '; 01060 $section_name = $attrs['name']; 01061 if (empty($section_name)) { 01062 $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); 01063 } 01064 01065 $output .= "unset(\$this->_sections[$section_name]);\n"; 01066 $section_props = "\$this->_sections[$section_name]"; 01067 01068 foreach ($attrs as $attr_name => $attr_value) { 01069 switch ($attr_name) { 01070 case 'loop': 01071 $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; 01072 break; 01073 01074 case 'show': 01075 if (is_bool($attr_value)) 01076 $show_attr_value = $attr_value ? 'true' : 'false'; 01077 else 01078 $show_attr_value = "(bool)$attr_value"; 01079 $output .= "{$section_props}['show'] = $show_attr_value;\n"; 01080 break; 01081 01082 case 'name': 01083 $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; 01084 break; 01085 01086 case 'max': 01087 case 'start': 01088 $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; 01089 break; 01090 01091 case 'step': 01092 $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; 01093 break; 01094 01095 default: 01096 $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); 01097 break; 01098 } 01099 } 01100 01101 if (!isset($attrs['show'])) 01102 $output .= "{$section_props}['show'] = true;\n"; 01103 01104 if (!isset($attrs['loop'])) 01105 $output .= "{$section_props}['loop'] = 1;\n"; 01106 01107 if (!isset($attrs['max'])) 01108 $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; 01109 else 01110 $output .= "if ({$section_props}['max'] < 0)\n" . 01111 " {$section_props}['max'] = {$section_props}['loop'];\n"; 01112 01113 if (!isset($attrs['step'])) 01114 $output .= "{$section_props}['step'] = 1;\n"; 01115 01116 if (!isset($attrs['start'])) 01117 $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; 01118 else { 01119 $output .= "if ({$section_props}['start'] < 0)\n" . 01120 " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . 01121 "else\n" . 01122 " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; 01123 } 01124 01125 $output .= "if ({$section_props}['show']) {\n"; 01126 if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { 01127 $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; 01128 } else { 01129 $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; 01130 } 01131 $output .= " if ({$section_props}['total'] == 0)\n" . 01132 " {$section_props}['show'] = false;\n" . 01133 "} else\n" . 01134 " {$section_props}['total'] = 0;\n"; 01135 01136 $output .= "if ({$section_props}['show']):\n"; 01137 $output .= " 01138 for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; 01139 {$section_props}['iteration'] <= {$section_props}['total']; 01140 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; 01141 $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; 01142 $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; 01143 $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; 01144 $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; 01145 $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; 01146 01147 $output .= "?>"; 01148 01149 return $output; 01150 } 01151 01152 01159 function _compile_foreach_start($tag_args) 01160 { 01161 $attrs = $this->_parse_attrs($tag_args); 01162 $arg_list = array(); 01163 01164 if (empty($attrs['from'])) { 01165 return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); 01166 } 01167 $from = $attrs['from']; 01168 01169 if (empty($attrs['item'])) { 01170 return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); 01171 } 01172 $item = $this->_dequote($attrs['item']); 01173 if (!preg_match('~^\w+$~', $item)) { 01174 return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); 01175 } 01176 01177 if (isset($attrs['key'])) { 01178 $key = $this->_dequote($attrs['key']); 01179 if (!preg_match('~^\w+$~', $key)) { 01180 return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); 01181 } 01182 $key_part = "\$this->_tpl_vars['$key'] => "; 01183 } else { 01184 $key = null; 01185 $key_part = ''; 01186 } 01187 01188 if (isset($attrs['name'])) { 01189 $name = $attrs['name']; 01190 } else { 01191 $name = null; 01192 } 01193 01194 $output = '<?php '; 01195 $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }"; 01196 if (isset($name)) { 01197 $foreach_props = "\$this->_foreach[$name]"; 01198 $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; 01199 $output .= "if ({$foreach_props}['total'] > 0):\n"; 01200 $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; 01201 $output .= " {$foreach_props}['iteration']++;\n"; 01202 } else { 01203 $output .= "if (count(\$_from)):\n"; 01204 $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; 01205 } 01206 $output .= '?>'; 01207 01208 return $output; 01209 } 01210 01211 01220 function _compile_capture_tag($start, $tag_args = '') 01221 { 01222 $attrs = $this->_parse_attrs($tag_args); 01223 01224 if ($start) { 01225 $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; 01226 $assign = isset($attrs['assign']) ? $attrs['assign'] : null; 01227 $append = isset($attrs['append']) ? $attrs['append'] : null; 01228 01229 $output = "<?php ob_start(); ?>"; 01230 $this->_capture_stack[] = array($buffer, $assign, $append); 01231 } else { 01232 list($buffer, $assign, $append) = array_pop($this->_capture_stack); 01233 $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); "; 01234 if (isset($assign)) { 01235 $output .= " \$this->assign($assign, ob_get_contents());"; 01236 } 01237 if (isset($append)) { 01238 $output .= " \$this->append($append, ob_get_contents());"; 01239 } 01240 $output .= "ob_end_clean(); ?>"; 01241 } 01242 01243 return $output; 01244 } 01245 01253 function _compile_if_tag($tag_args, $elseif = false) 01254 { 01255 01256 /* Tokenize args for 'if' tag. */ 01257 preg_match_all('~(?> 01258 ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call 01259 ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string 01260 \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token 01261 \b\w+\b | # valid word token 01262 \S+ # anything else 01263 )~x', $tag_args, $match); 01264 01265 $tokens = $match[0]; 01266 01267 if(empty($tokens)) { 01268 $_error_msg = $elseif ? "'elseif'" : "'if'"; 01269 $_error_msg .= ' statement requires arguments'; 01270 $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); 01271 } 01272 01273 01274 // make sure we have balanced parenthesis 01275 $token_count = array_count_values($tokens); 01276 if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { 01277 $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); 01278 } 01279 01280 $is_arg_stack = array(); 01281 01282 for ($i = 0; $i < count($tokens); $i++) { 01283 01284 $token = &$tokens[$i]; 01285 01286 switch (strtolower($token)) { 01287 case '!': 01288 case '%': 01289 case '!==': 01290 case '==': 01291 case '===': 01292 case '>': 01293 case '<': 01294 case '!=': 01295 case '<>': 01296 case '<<': 01297 case '>>': 01298 case '<=': 01299 case '>=': 01300 case '&&': 01301 case '||': 01302 case '|': 01303 case '^': 01304 case '&': 01305 case '~': 01306 case ')': 01307 case ',': 01308 case '+': 01309 case '-': 01310 case '*': 01311 case '/': 01312 case '@': 01313 break; 01314 01315 case 'eq': 01316 $token = '=='; 01317 break; 01318 01319 case 'ne': 01320 case 'neq': 01321 $token = '!='; 01322 break; 01323 01324 case 'lt': 01325 $token = '<'; 01326 break; 01327 01328 case 'le': 01329 case 'lte': 01330 $token = '<='; 01331 break; 01332 01333 case 'gt': 01334 $token = '>'; 01335 break; 01336 01337 case 'ge': 01338 case 'gte': 01339 $token = '>='; 01340 break; 01341 01342 case 'and': 01343 $token = '&&'; 01344 break; 01345 01346 case 'or': 01347 $token = '||'; 01348 break; 01349 01350 case 'not': 01351 $token = '!'; 01352 break; 01353 01354 case 'mod': 01355 $token = '%'; 01356 break; 01357 01358 case '(': 01359 array_push($is_arg_stack, $i); 01360 break; 01361 01362 case 'is': 01363 /* If last token was a ')', we operate on the parenthesized 01364 expression. The start of the expression is on the stack. 01365 Otherwise, we operate on the last encountered token. */ 01366 if ($tokens[$i-1] == ')') { 01367 $is_arg_start = array_pop($is_arg_stack); 01368 if ($is_arg_start != 0) { 01369 if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) { 01370 $is_arg_start--; 01371 } 01372 } 01373 } else 01374 $is_arg_start = $i-1; 01375 /* Construct the argument for 'is' expression, so it knows 01376 what to operate on. */ 01377 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); 01378 01379 /* Pass all tokens from next one until the end to the 01380 'is' expression parsing function. The function will 01381 return modified tokens, where the first one is the result 01382 of the 'is' expression and the rest are the tokens it 01383 didn't touch. */ 01384 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); 01385 01386 /* Replace the old tokens with the new ones. */ 01387 array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); 01388 01389 /* Adjust argument start so that it won't change from the 01390 current position for the next iteration. */ 01391 $i = $is_arg_start; 01392 break; 01393 01394 default: 01395 if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { 01396 // function call 01397 if($this->security && 01398 !in_array($token, $this->security_settings['IF_FUNCS'])) { 01399 $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); 01400 } 01401 } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { 01402 // variable function call 01403 $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); 01404 } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { 01405 // object or variable 01406 $token = $this->_parse_var_props($token); 01407 } elseif(is_numeric($token)) { 01408 // number, skip it 01409 } else { 01410 $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); 01411 } 01412 break; 01413 } 01414 } 01415 01416 if ($elseif) 01417 return '<?php elseif ('.implode(' ', $tokens).'): ?>'; 01418 else 01419 return '<?php if ('.implode(' ', $tokens).'): ?>'; 01420 } 01421 01422 01423 function _compile_arg_list($type, $name, $attrs, &$cache_code) { 01424 $arg_list = array(); 01425 01426 if (isset($type) && isset($name) 01427 && isset($this->_plugins[$type]) 01428 && isset($this->_plugins[$type][$name]) 01429 && empty($this->_plugins[$type][$name][4]) 01430 && is_array($this->_plugins[$type][$name][5]) 01431 ) { 01432 /* we have a list of parameters that should be cached */ 01433 $_cache_attrs = $this->_plugins[$type][$name][5]; 01434 $_count = $this->_cache_attrs_count++; 01435 $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; 01436 01437 } else { 01438 /* no parameters are cached */ 01439 $_cache_attrs = null; 01440 } 01441 01442 foreach ($attrs as $arg_name => $arg_value) { 01443 if (is_bool($arg_value)) 01444 $arg_value = $arg_value ? 'true' : 'false'; 01445 if (is_null($arg_value)) 01446 $arg_value = 'null'; 01447 if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { 01448 $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; 01449 } else { 01450 $arg_list[] = "'$arg_name' => $arg_value"; 01451 } 01452 } 01453 return $arg_list; 01454 } 01455 01463 function _parse_is_expr($is_arg, $tokens) 01464 { 01465 $expr_end = 0; 01466 $negate_expr = false; 01467 01468 if (($first_token = array_shift($tokens)) == 'not') { 01469 $negate_expr = true; 01470 $expr_type = array_shift($tokens); 01471 } else 01472 $expr_type = $first_token; 01473 01474 switch ($expr_type) { 01475 case 'even': 01476 if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { 01477 $expr_end++; 01478 $expr_arg = $tokens[$expr_end++]; 01479 $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; 01480 } else 01481 $expr = "!(1 & $is_arg)"; 01482 break; 01483 01484 case 'odd': 01485 if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { 01486 $expr_end++; 01487 $expr_arg = $tokens[$expr_end++]; 01488 $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; 01489 } else 01490 $expr = "(1 & $is_arg)"; 01491 break; 01492 01493 case 'div': 01494 if (@$tokens[$expr_end] == 'by') { 01495 $expr_end++; 01496 $expr_arg = $tokens[$expr_end++]; 01497 $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; 01498 } else { 01499 $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); 01500 } 01501 break; 01502 01503 default: 01504 $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); 01505 break; 01506 } 01507 01508 if ($negate_expr) { 01509 $expr = "!($expr)"; 01510 } 01511 01512 array_splice($tokens, 0, $expr_end, $expr); 01513 01514 return $tokens; 01515 } 01516 01517 01524 function _parse_attrs($tag_args) 01525 { 01526 01527 /* Tokenize tag attributes. */ 01528 preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) 01529 )+ | 01530 [=] 01531 ~x', $tag_args, $match); 01532 $tokens = $match[0]; 01533 01534 $attrs = array(); 01535 /* Parse state: 01536 0 - expecting attribute name 01537 1 - expecting '=' 01538 2 - expecting attribute value (not '=') */ 01539 $state = 0; 01540 01541 foreach ($tokens as $token) { 01542 switch ($state) { 01543 case 0: 01544 /* If the token is a valid identifier, we set attribute name 01545 and go to state 1. */ 01546 if (preg_match('~^\w+$~', $token)) { 01547 $attr_name = $token; 01548 $state = 1; 01549 } else 01550 $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); 01551 break; 01552 01553 case 1: 01554 /* If the token is '=', then we go to state 2. */ 01555 if ($token == '=') { 01556 $state = 2; 01557 } else 01558 $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); 01559 break; 01560 01561 case 2: 01562 /* If token is not '=', we set the attribute value and go to 01563 state 0. */ 01564 if ($token != '=') { 01565 /* We booleanize the token if it's a non-quoted possible 01566 boolean value. */ 01567 if (preg_match('~^(on|yes|true)$~', $token)) { 01568 $token = 'true'; 01569 } else if (preg_match('~^(off|no|false)$~', $token)) { 01570 $token = 'false'; 01571 } else if ($token == 'null') { 01572 $token = 'null'; 01573 } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { 01574 /* treat integer literally */ 01575 } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { 01576 /* treat as a string, double-quote it escaping quotes */ 01577 $token = '"'.addslashes($token).'"'; 01578 } 01579 01580 $attrs[$attr_name] = $token; 01581 $state = 0; 01582 } else 01583 $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); 01584 break; 01585 } 01586 $last_token = $token; 01587 } 01588 01589 if($state != 0) { 01590 if($state == 1) { 01591 $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); 01592 } else { 01593 $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); 01594 } 01595 } 01596 01597 $this->_parse_vars_props($attrs); 01598 01599 return $attrs; 01600 } 01601 01608 function _parse_vars_props(&$tokens) 01609 { 01610 foreach($tokens as $key => $val) { 01611 $tokens[$key] = $this->_parse_var_props($val); 01612 } 01613 } 01614 01623 function _parse_var_props($val) 01624 { 01625 $val = trim($val); 01626 01627 if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { 01628 // $ variable or object 01629 $return = $this->_parse_var($match[1]); 01630 $modifiers = $match[2]; 01631 if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { 01632 $_default_mod_string = implode('|',(array)$this->default_modifiers); 01633 $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; 01634 } 01635 $this->_parse_modifiers($return, $modifiers); 01636 return $return; 01637 } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { 01638 // double quoted text 01639 preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); 01640 $return = $this->_expand_quoted_text($match[1]); 01641 if($match[2] != '') { 01642 $this->_parse_modifiers($return, $match[2]); 01643 } 01644 return $return; 01645 } 01646 elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { 01647 // numerical constant 01648 preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); 01649 if($match[2] != '') { 01650 $this->_parse_modifiers($match[1], $match[2]); 01651 return $match[1]; 01652 } 01653 } 01654 elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { 01655 // single quoted text 01656 preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); 01657 if($match[2] != '') { 01658 $this->_parse_modifiers($match[1], $match[2]); 01659 return $match[1]; 01660 } 01661 } 01662 elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { 01663 // config var 01664 return $this->_parse_conf_var($val); 01665 } 01666 elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { 01667 // section var 01668 return $this->_parse_section_prop($val); 01669 } 01670 elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { 01671 // literal string 01672 return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); 01673 } 01674 return $val; 01675 } 01676 01683 function _expand_quoted_text($var_expr) 01684 { 01685 // if contains unescaped $, expand it 01686 if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) { 01687 $_match = $_match[0]; 01688 $_replace = array(); 01689 foreach($_match as $_var) { 01690 $_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."'; 01691 } 01692 $var_expr = strtr($var_expr, $_replace); 01693 $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr); 01694 } else { 01695 $_return = $var_expr; 01696 } 01697 // replace double quoted literal string with single quotes 01698 $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return); 01699 return $_return; 01700 } 01701 01709 function _parse_var($var_expr) 01710 { 01711 $_has_math = false; 01712 $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); 01713 01714 if(count($_math_vars) > 1) { 01715 $_first_var = ""; 01716 $_complete_var = ""; 01717 $_output = ""; 01718 // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) 01719 foreach($_math_vars as $_k => $_math_var) { 01720 $_math_var = $_math_vars[$_k]; 01721 01722 if(!empty($_math_var) || is_numeric($_math_var)) { 01723 // hit a math operator, so process the stuff which came before it 01724 if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { 01725 $_has_math = true; 01726 if(!empty($_complete_var) || is_numeric($_complete_var)) { 01727 $_output .= $this->_parse_var($_complete_var); 01728 } 01729 01730 // just output the math operator to php 01731 $_output .= $_math_var; 01732 01733 if(empty($_first_var)) 01734 $_first_var = $_complete_var; 01735 01736 $_complete_var = ""; 01737 } else { 01738 $_complete_var .= $_math_var; 01739 } 01740 } 01741 } 01742 if($_has_math) { 01743 if(!empty($_complete_var) || is_numeric($_complete_var)) 01744 $_output .= $this->_parse_var($_complete_var); 01745 01746 // get the modifiers working (only the last var from math + modifier is left) 01747 $var_expr = $_complete_var; 01748 } 01749 } 01750 01751 // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) 01752 if(is_numeric(substr($var_expr, 0, 1))) 01753 $_var_ref = $var_expr; 01754 else 01755 $_var_ref = substr($var_expr, 1); 01756 01757 if(!$_has_math) { 01758 01759 // get [foo] and .foo and ->foo and (...) pieces 01760 preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); 01761 01762 $_indexes = $match[0]; 01763 $_var_name = array_shift($_indexes); 01764 01765 /* Handle $smarty.* variable references as a special case. */ 01766 if ($_var_name == 'smarty') { 01767 /* 01768 * If the reference could be compiled, use the compiled output; 01769 * otherwise, fall back on the $smarty variable generated at 01770 * run-time. 01771 */ 01772 if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { 01773 $_output = $smarty_ref; 01774 } else { 01775 $_var_name = substr(array_shift($_indexes), 1); 01776 $_output = "\$this->_smarty_vars['$_var_name']"; 01777 } 01778 } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { 01779 // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers 01780 if(count($_indexes) > 0) 01781 { 01782 $_var_name .= implode("", $_indexes); 01783 $_indexes = array(); 01784 } 01785 $_output = $_var_name; 01786 } else { 01787 $_output = "\$this->_tpl_vars['$_var_name']"; 01788 } 01789 01790 foreach ($_indexes as $_index) { 01791 if (substr($_index, 0, 1) == '[') { 01792 $_index = substr($_index, 1, -1); 01793 if (is_numeric($_index)) { 01794 $_output .= "[$_index]"; 01795 } elseif (substr($_index, 0, 1) == '$') { 01796 if (strpos($_index, '.') !== false) { 01797 $_output .= '[' . $this->_parse_var($_index) . ']'; 01798 } else { 01799 $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; 01800 } 01801 } else { 01802 $_var_parts = explode('.', $_index); 01803 $_var_section = $_var_parts[0]; 01804 $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; 01805 $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; 01806 } 01807 } else if (substr($_index, 0, 1) == '.') { 01808 if (substr($_index, 1, 1) == '$') 01809 $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; 01810 else 01811 $_output .= "['" . substr($_index, 1) . "']"; 01812 } else if (substr($_index,0,2) == '->') { 01813 if(substr($_index,2,2) == '__') { 01814 $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); 01815 } elseif($this->security && substr($_index, 2, 1) == '_') { 01816 $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); 01817 } elseif (substr($_index, 2, 1) == '$') { 01818 if ($this->security) { 01819 $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); 01820 } else { 01821 $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; 01822 } 01823 } else { 01824 $_output .= $_index; 01825 } 01826 } elseif (substr($_index, 0, 1) == '(') { 01827 $_index = $this->_parse_parenth_args($_index); 01828 $_output .= $_index; 01829 } else { 01830 $_output .= $_index; 01831 } 01832 } 01833 } 01834 01835 return $_output; 01836 } 01837 01844 function _parse_parenth_args($parenth_args) 01845 { 01846 preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); 01847 $orig_vals = $match = $match[0]; 01848 $this->_parse_vars_props($match); 01849 $replace = array(); 01850 for ($i = 0, $count = count($match); $i < $count; $i++) { 01851 $replace[$orig_vals[$i]] = $match[$i]; 01852 } 01853 return strtr($parenth_args, $replace); 01854 } 01855 01861 function _parse_conf_var($conf_var_expr) 01862 { 01863 $parts = explode('|', $conf_var_expr, 2); 01864 $var_ref = $parts[0]; 01865 $modifiers = isset($parts[1]) ? $parts[1] : ''; 01866 01867 $var_name = substr($var_ref, 1, -1); 01868 01869 $output = "\$this->_config[0]['vars']['$var_name']"; 01870 01871 $this->_parse_modifiers($output, $modifiers); 01872 01873 return $output; 01874 } 01875 01882 function _parse_section_prop($section_prop_expr) 01883 { 01884 $parts = explode('|', $section_prop_expr, 2); 01885 $var_ref = $parts[0]; 01886 $modifiers = isset($parts[1]) ? $parts[1] : ''; 01887 01888 preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); 01889 $section_name = $match[1]; 01890 $prop_name = $match[2]; 01891 01892 $output = "\$this->_sections['$section_name']['$prop_name']"; 01893 01894 $this->_parse_modifiers($output, $modifiers); 01895 01896 return $output; 01897 } 01898 01899 01907 function _parse_modifiers(&$output, $modifier_string) 01908 { 01909 preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); 01910 list(, $_modifiers, $modifier_arg_strings) = $_match; 01911 01912 for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { 01913 $_modifier_name = $_modifiers[$_i]; 01914 01915 if($_modifier_name == 'smarty') { 01916 // skip smarty modifier 01917 continue; 01918 } 01919 01920 preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); 01921 $_modifier_args = $_match[1]; 01922 01923 if (substr($_modifier_name, 0, 1) == '@') { 01924 $_map_array = false; 01925 $_modifier_name = substr($_modifier_name, 1); 01926 } else { 01927 $_map_array = true; 01928 } 01929 01930 if (empty($this->_plugins['modifier'][$_modifier_name]) 01931 && !$this->_get_plugin_filepath('modifier', $_modifier_name) 01932 && function_exists($_modifier_name)) { 01933 if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { 01934 $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); 01935 } else { 01936 $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); 01937 } 01938 } 01939 $this->_add_plugin('modifier', $_modifier_name); 01940 01941 $this->_parse_vars_props($_modifier_args); 01942 01943 if($_modifier_name == 'default') { 01944 // supress notifications of default modifier vars and args 01945 if(substr($output, 0, 1) == '$') { 01946 $output = '@' . $output; 01947 } 01948 if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { 01949 $_modifier_args[0] = '@' . $_modifier_args[0]; 01950 } 01951 } 01952 if (count($_modifier_args) > 0) 01953 $_modifier_args = ', '.implode(', ', $_modifier_args); 01954 else 01955 $_modifier_args = ''; 01956 01957 if ($_map_array) { 01958 $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; 01959 01960 } else { 01961 01962 $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; 01963 01964 } 01965 } 01966 } 01967 01968 01976 function _add_plugin($type, $name, $delayed_loading = null) 01977 { 01978 if (!isset($this->_plugin_info[$type])) { 01979 $this->_plugin_info[$type] = array(); 01980 } 01981 if (!isset($this->_plugin_info[$type][$name])) { 01982 $this->_plugin_info[$type][$name] = array($this->_current_file, 01983 $this->_current_line_no, 01984 $delayed_loading); 01985 } 01986 } 01987 01988 01995 function _compile_smarty_ref(&$indexes) 01996 { 01997 /* Extract the reference name. */ 01998 $_ref = substr($indexes[0], 1); 01999 foreach($indexes as $_index_no=>$_index) { 02000 if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { 02001 $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); 02002 } 02003 } 02004 02005 switch ($_ref) { 02006 case 'now': 02007 $compiled_ref = 'time()'; 02008 $_max_index = 1; 02009 break; 02010 02011 case 'foreach': 02012 array_shift($indexes); 02013 $_var = $this->_parse_var_props(substr($indexes[0], 1)); 02014 $_propname = substr($indexes[1], 1); 02015 $_max_index = 1; 02016 switch ($_propname) { 02017 case 'index': 02018 array_shift($indexes); 02019 $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; 02020 break; 02021 02022 case 'first': 02023 array_shift($indexes); 02024 $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; 02025 break; 02026 02027 case 'last': 02028 array_shift($indexes); 02029 $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; 02030 break; 02031 02032 case 'show': 02033 array_shift($indexes); 02034 $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; 02035 break; 02036 02037 default: 02038 unset($_max_index); 02039 $compiled_ref = "\$this->_foreach[$_var]"; 02040 } 02041 break; 02042 02043 case 'section': 02044 array_shift($indexes); 02045 $_var = $this->_parse_var_props(substr($indexes[0], 1)); 02046 $compiled_ref = "\$this->_sections[$_var]"; 02047 break; 02048 02049 case 'get': 02050 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02051 $this->_syntax_error("(secure mode) super global access not permitted", 02052 E_USER_WARNING, __FILE__, __LINE__); 02053 return; 02054 } 02055 $compiled_ref = "\$_GET"; 02056 break; 02057 02058 case 'post': 02059 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02060 $this->_syntax_error("(secure mode) super global access not permitted", 02061 E_USER_WARNING, __FILE__, __LINE__); 02062 return; 02063 } 02064 $compiled_ref = "\$_POST"; 02065 break; 02066 02067 case 'cookies': 02068 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02069 $this->_syntax_error("(secure mode) super global access not permitted", 02070 E_USER_WARNING, __FILE__, __LINE__); 02071 return; 02072 } 02073 $compiled_ref = "\$_COOKIE"; 02074 break; 02075 02076 case 'env': 02077 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02078 $this->_syntax_error("(secure mode) super global access not permitted", 02079 E_USER_WARNING, __FILE__, __LINE__); 02080 return; 02081 } 02082 $compiled_ref = "\$_ENV"; 02083 break; 02084 02085 case 'server': 02086 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02087 $this->_syntax_error("(secure mode) super global access not permitted", 02088 E_USER_WARNING, __FILE__, __LINE__); 02089 return; 02090 } 02091 $compiled_ref = "\$_SERVER"; 02092 break; 02093 02094 case 'session': 02095 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02096 $this->_syntax_error("(secure mode) super global access not permitted", 02097 E_USER_WARNING, __FILE__, __LINE__); 02098 return; 02099 } 02100 $compiled_ref = "\$_SESSION"; 02101 break; 02102 02103 /* 02104 * These cases are handled either at run-time or elsewhere in the 02105 * compiler. 02106 */ 02107 case 'request': 02108 if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { 02109 $this->_syntax_error("(secure mode) super global access not permitted", 02110 E_USER_WARNING, __FILE__, __LINE__); 02111 return; 02112 } 02113 if ($this->request_use_auto_globals) { 02114 $compiled_ref = "\$_REQUEST"; 02115 break; 02116 } else { 02117 $this->_init_smarty_vars = true; 02118 } 02119 return null; 02120 02121 case 'capture': 02122 return null; 02123 02124 case 'template': 02125 $compiled_ref = "'$this->_current_file'"; 02126 $_max_index = 1; 02127 break; 02128 02129 case 'version': 02130 $compiled_ref = "'$this->_version'"; 02131 $_max_index = 1; 02132 break; 02133 02134 case 'const': 02135 if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { 02136 $this->_syntax_error("(secure mode) constants not permitted", 02137 E_USER_WARNING, __FILE__, __LINE__); 02138 return; 02139 } 02140 array_shift($indexes); 02141 if (preg_match('!^\.\w+$!', $indexes[0])) { 02142 $compiled_ref = '@' . substr($indexes[0], 1); 02143 } else { 02144 $_val = $this->_parse_var_props(substr($indexes[0], 1)); 02145 $compiled_ref = '@constant(' . $_val . ')'; 02146 } 02147 $_max_index = 1; 02148 break; 02149 02150 case 'config': 02151 $compiled_ref = "\$this->_config[0]['vars']"; 02152 $_max_index = 3; 02153 break; 02154 02155 case 'ldelim': 02156 $compiled_ref = "'$this->left_delimiter'"; 02157 break; 02158 02159 case 'rdelim': 02160 $compiled_ref = "'$this->right_delimiter'"; 02161 break; 02162 02163 default: 02164 $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); 02165 break; 02166 } 02167 02168 if (isset($_max_index) && count($indexes) > $_max_index) { 02169 $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); 02170 } 02171 02172 array_shift($indexes); 02173 return $compiled_ref; 02174 } 02175 02186 function _compile_plugin_call($type, $name) { 02187 if (isset($this->_plugins[$type][$name])) { 02188 /* plugin loaded */ 02189 if (is_array($this->_plugins[$type][$name][0])) { 02190 return ((is_object($this->_plugins[$type][$name][0][0])) ? 02191 "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ 02192 : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ 02193 ). $this->_plugins[$type][$name][0][1]; 02194 02195 } else { 02196 /* function callback */ 02197 return $this->_plugins[$type][$name][0]; 02198 02199 } 02200 } else { 02201 /* plugin not loaded -> auto-loadable-plugin */ 02202 return 'smarty_'.$type.'_'.$name; 02203 02204 } 02205 } 02206 02210 function _load_filters() 02211 { 02212 if (count($this->_plugins['prefilter']) > 0) { 02213 foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { 02214 if ($prefilter === false) { 02215 unset($this->_plugins['prefilter'][$filter_name]); 02216 $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); 02217 require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); 02218 smarty_core_load_plugins($_params, $this); 02219 } 02220 } 02221 } 02222 if (count($this->_plugins['postfilter']) > 0) { 02223 foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { 02224 if ($postfilter === false) { 02225 unset($this->_plugins['postfilter'][$filter_name]); 02226 $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); 02227 require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); 02228 smarty_core_load_plugins($_params, $this); 02229 } 02230 } 02231 } 02232 } 02233 02234 02241 function _quote_replace($string) 02242 { 02243 return strtr($string, array('\\' => '\\\\', '$' => '\\$')); 02244 } 02245 02254 function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) 02255 { 02256 $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); 02257 } 02258 02259 02266 function _push_cacheable_state($type, $name) { 02267 $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; 02268 if ($_cacheable 02269 || 0<$this->_cacheable_state++) return ''; 02270 if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); 02271 $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' 02272 . $this->_cache_serial . '#' . $this->_nocache_count 02273 . '}\'; endif;'; 02274 return $_ret; 02275 } 02276 02277 02284 function _pop_cacheable_state($type, $name) { 02285 $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; 02286 if ($_cacheable 02287 || --$this->_cacheable_state>0) return ''; 02288 return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' 02289 . $this->_cache_serial . '#' . ($this->_nocache_count++) 02290 . '}\'; endif;'; 02291 } 02292 02293 02298 function _push_tag($open_tag) 02299 { 02300 array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); 02301 } 02302 02309 function _pop_tag($close_tag) 02310 { 02311 $message = ''; 02312 if (count($this->_tag_stack)>0) { 02313 list($_open_tag, $_line_no) = array_pop($this->_tag_stack); 02314 if ($close_tag == $_open_tag) { 02315 return $_open_tag; 02316 } 02317 if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { 02318 return $this->_pop_tag($close_tag); 02319 } 02320 if ($close_tag == 'section' && $_open_tag == 'sectionelse') { 02321 $this->_pop_tag($close_tag); 02322 return $_open_tag; 02323 } 02324 if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { 02325 $this->_pop_tag($close_tag); 02326 return $_open_tag; 02327 } 02328 if ($_open_tag == 'else' || $_open_tag == 'elseif') { 02329 $_open_tag = 'if'; 02330 } elseif ($_open_tag == 'sectionelse') { 02331 $_open_tag = 'section'; 02332 } elseif ($_open_tag == 'foreachelse') { 02333 $_open_tag = 'foreach'; 02334 } 02335 $message = " expected {/$_open_tag} (opened line $_line_no)."; 02336 } 02337 $this->_syntax_error("mismatched tag {/$close_tag}.$message", 02338 E_USER_ERROR, __FILE__, __LINE__); 02339 } 02340 02341 } 02342 02351 function _smarty_sort_length($a, $b) 02352 { 02353 if($a == $b) 02354 return 0; 02355 02356 if(strlen($a) == strlen($b)) 02357 return ($a > $b) ? -1 : 1; 02358 02359 return (strlen($a) > strlen($b)) ? -1 : 1; 02360 } 02361 02362 02363 /* vim: set et: */ 02364
| Copyright © 2003 - 2009 MyOOS [Shopsystem]. All rights reserved. MyOOS [Shopsystem] is Free Software released under the GNU/GPL License. Webmaster: info@r23.de (Impressum) |
|
