4 * Project: Smarty: the PHP compiling template engine
\r
5 * File: Smarty_Compiler.class.php
\r
7 * This library is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU Lesser General Public
\r
9 * License as published by the Free Software Foundation; either
\r
10 * version 2.1 of the License, or (at your option) any later version.
\r
12 * This library is distributed in the hope that it will be useful,
\r
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
15 * Lesser General Public License for more details.
\r
17 * You should have received a copy of the GNU Lesser General Public
\r
18 * License along with this library; if not, write to the Free Software
\r
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
21 * You may contact the authors of Smarty by e-mail at:
\r
27 * Director of Technology, ispi
\r
28 * 237 S. 70th suite 220
\r
31 * The latest version of Smarty can be obtained from:
\r
32 * http://smarty.php.net/
\r
34 * @link http://smarty.php.net/
\r
35 * @author Monte Ohrt <monte@ispi.net>
\r
36 * @author Andrei Zmievski <andrei@php.net>
\r
38 * @copyright 2001-2003 ispi of Lincoln, Inc.
\r
42 /* $Id: Smarty_Compiler.class.php,v 1.1 2005/10/17 18:37:39 jeichorn Exp $ */
\r
45 * Template compiling class
\r
48 class Smarty_Compiler extends Smarty {
\r
54 var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
\r
55 var $_foreachelse_stack = array(); // keeps track of whether foreach had 'else' part
\r
56 var $_literal_blocks = array(); // keeps literal template blocks
\r
57 var $_php_blocks = array(); // keeps php code blocks
\r
58 var $_current_file = null; // the current template being compiled
\r
59 var $_current_line_no = 1; // line number for error messages
\r
60 var $_capture_stack = array(); // keeps track of nested capture buffers
\r
61 var $_plugin_info = array(); // keeps track of plugins to load
\r
62 var $_init_smarty_vars = false;
\r
63 var $_permitted_tokens = array('true','false','yes','no','on','off','null');
\r
64 var $_db_qstr_regexp = null; // regexps are setup in the constructor
\r
65 var $_si_qstr_regexp = null;
\r
66 var $_qstr_regexp = null;
\r
67 var $_func_regexp = null;
\r
68 var $_var_bracket_regexp = null;
\r
69 var $_dvar_guts_regexp = null;
\r
70 var $_dvar_regexp = null;
\r
71 var $_cvar_regexp = null;
\r
72 var $_svar_regexp = null;
\r
73 var $_avar_regexp = null;
\r
74 var $_mod_regexp = null;
\r
75 var $_var_regexp = null;
\r
76 var $_parenth_param_regexp = null;
\r
77 var $_func_call_regexp = null;
\r
78 var $_obj_ext_regexp = null;
\r
79 var $_obj_start_regexp = null;
\r
80 var $_obj_params_regexp = null;
\r
81 var $_obj_call_regexp = null;
\r
82 var $_cacheable_state = 0;
\r
83 var $_cache_attrs_count = 0;
\r
84 var $_nocache_count = 0;
\r
85 var $_cache_serial = null;
\r
86 var $_cache_include = null;
\r
88 var $_strip_depth = 0;
\r
89 var $_additional_newline = "\n";
\r
93 * The class constructor.
\r
95 function Smarty_Compiler()
\r
97 // matches double quoted strings:
\r
100 $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
\r
102 // matches single quoted strings:
\r
105 $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
\r
107 // matches single or double quoted strings
\r
108 $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
\r
110 // matches bracket portion of vars
\r
114 $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
\r
116 // matches $ vars (not objects):
\r
123 // $foo[5].bar[$foobar][4]
\r
124 $this->_dvar_math_regexp = '[\+\-\*\/\%]';
\r
125 $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
\r
126 $this->_dvar_num_var_regexp = '\-?\d+(?:\.\d+)?' . $this->_dvar_math_var_regexp;
\r
127 $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
\r
128 . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:\-?\d+(?:\.\d+)?|' . $this->_dvar_math_var_regexp . ')*)?';
\r
129 $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
\r
131 // matches config vars:
\r
134 $this->_cvar_regexp = '\#\w+\#';
\r
136 // matches section vars:
\r
138 $this->_svar_regexp = '\%\w+\.\w+\%';
\r
140 // matches all valid variables (no quotes, no modifiers)
\r
141 $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
\r
142 . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
\r
144 // matches valid variable syntax:
\r
151 $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
\r
153 // matches valid object call (no objects allowed in parameters):
\r
156 // $foo->bar("text")
\r
157 // $foo->bar($foo, $bar, "text")
\r
158 // $foo->bar($foo, "foo")
\r
159 // $foo->bar->foo()
\r
160 // $foo->bar->foo->bar()
\r
161 $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
\r
162 $this->_obj_params_regexp = '\((?:\w+|'
\r
163 . $this->_var_regexp . '(?:\s*,\s*(?:(?:\w+|'
\r
164 . $this->_var_regexp . ')))*)?\)';
\r
165 $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
\r
166 $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?)';
\r
168 // matches valid modifier syntax:
\r
173 // |foo:"bar":$foobar
\r
176 $this->_mod_regexp = '(?:\|@?\w+(?::(?>-?\w+|'
\r
177 . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
\r
179 // matches valid function name:
\r
182 $this->_func_regexp = '[a-zA-Z_]\w*';
\r
184 // matches valid registered object:
\r
186 $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
\r
188 // matches valid parameter values:
\r
197 $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
\r
198 . $this->_var_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
\r
200 // matches valid parenthesised function parameters:
\r
203 // $foo, $bar, "text"
\r
204 // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
\r
205 $this->_parenth_param_regexp = '(?:\((?:\w+|'
\r
206 . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
\r
207 . $this->_param_regexp . ')))*)?\))';
\r
209 // matches valid function call:
\r
212 // _foo_bar($foo,"bar")
\r
213 // foo123($foo,$foo->bar(),"foo")
\r
214 $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
\r
215 . $this->_parenth_param_regexp . '))';
\r
219 * compile a resource
\r
221 * sets $compiled_content to the compiled source
\r
222 * @param string $resource_name
\r
223 * @param string $source_content
\r
224 * @param string $compiled_content
\r
227 function _compile_file($resource_name, $source_content, &$compiled_content)
\r
230 if ($this->security) {
\r
231 // do not allow php syntax to be executed unless specified
\r
232 if ($this->php_handling == SMARTY_PHP_ALLOW &&
\r
233 !$this->security_settings['PHP_HANDLING']) {
\r
234 $this->php_handling = SMARTY_PHP_PASSTHRU;
\r
238 $this->_load_filters();
\r
240 $this->_current_file = $resource_name;
\r
241 $this->_current_line_no = 1;
\r
242 $ldq = preg_quote($this->left_delimiter, '!');
\r
243 $rdq = preg_quote($this->right_delimiter, '!');
\r
245 // run template source through prefilter functions
\r
246 if (count($this->_plugins['prefilter']) > 0) {
\r
247 foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
\r
248 if ($prefilter === false) continue;
\r
249 if ($prefilter[3] || is_callable($prefilter[0])) {
\r
250 $source_content = call_user_func_array($prefilter[0],
\r
251 array($source_content, &$this));
\r
252 $this->_plugins['prefilter'][$filter_name][3] = true;
\r
254 $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
\r
259 /* Annihilate the comments. */
\r
260 $source_content = preg_replace("!({$ldq})\*(.*?)\*({$rdq})!se",
\r
261 "'\\1*'.str_repeat(\"\n\", substr_count('\\2', \"\n\")) .'*\\3'",
\r
264 /* Pull out the literal blocks. */
\r
265 preg_match_all("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", $source_content, $_match);
\r
266 $this->_literal_blocks = $_match[1];
\r
267 $source_content = preg_replace("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s",
\r
268 $this->_quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $source_content);
\r
270 /* Pull out the php code blocks. */
\r
271 preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $source_content, $_match);
\r
272 $this->_php_blocks = $_match[1];
\r
273 $source_content = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s",
\r
274 $this->_quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $source_content);
\r
276 /* Gather all template tags. */
\r
277 preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match);
\r
278 $template_tags = $_match[1];
\r
279 /* Split content by template tags to obtain non-template content. */
\r
280 $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content);
\r
282 /* loop through text blocks */
\r
283 for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
\r
284 /* match anything resembling php tags */
\r
285 if (preg_match_all('!(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)!is', $text_blocks[$curr_tb], $sp_match)) {
\r
286 /* replace tags with placeholders to prevent recursive replacements */
\r
287 $sp_match[1] = array_unique($sp_match[1]);
\r
288 usort($sp_match[1], '_smarty_sort_length');
\r
289 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
\r
290 $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
\r
292 /* process each one */
\r
293 for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
\r
294 if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
\r
295 /* echo php contents */
\r
296 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
\r
297 } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
\r
298 /* quote php tags */
\r
299 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
\r
300 } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
\r
301 /* remove php tags */
\r
302 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
\r
304 /* SMARTY_PHP_ALLOW, but echo non php starting tags */
\r
305 $sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
\r
306 $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
\r
312 /* Compile the template tags into PHP code. */
\r
313 $compiled_tags = array();
\r
314 for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
\r
315 $this->_current_line_no += substr_count($text_blocks[$i], "\n");
\r
316 $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
\r
317 $this->_current_line_no += substr_count($template_tags[$i], "\n");
\r
320 $compiled_content = '';
\r
322 /* Interleave the compiled contents and text blocks to get the final result. */
\r
323 for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
\r
324 if ($compiled_tags[$i] == '') {
\r
325 // tag result empty, remove first newline from following text block
\r
326 $text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]);
\r
328 $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
\r
330 $compiled_content .= $text_blocks[$i];
\r
332 /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
\r
333 if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) {
\r
334 $strip_tags = $_match[0];
\r
335 $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
\r
336 $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
\r
337 for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)
\r
338 $compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
\r
339 $this->_quote_replace($strip_tags_modified[$i]),
\r
340 $compiled_content, 1);
\r
343 // remove \n from the end of the file, if any
\r
344 if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
\r
345 $compiled_content = substr($compiled_content, 0, -1);
\r
348 if (!empty($this->_cache_serial)) {
\r
349 $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
\r
352 // remove unnecessary close/open tags
\r
353 $compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content);
\r
355 // run compiled template through postfilter functions
\r
356 if (count($this->_plugins['postfilter']) > 0) {
\r
357 foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
\r
358 if ($postfilter === false) continue;
\r
359 if ($postfilter[3] || is_callable($postfilter[0])) {
\r
360 $compiled_content = call_user_func_array($postfilter[0],
\r
361 array($compiled_content, &$this));
\r
362 $this->_plugins['postfilter'][$filter_name][3] = true;
\r
364 $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
\r
369 // put header at the top of the compiled template
\r
370 $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
\r
371 $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
\r
373 /* Emit code to load needed plugins. */
\r
374 $this->_plugins_code = '';
\r
375 if (count($this->_plugin_info)) {
\r
376 $_plugins_params = "array('plugins' => array(";
\r
377 foreach ($this->_plugin_info as $plugin_type => $plugins) {
\r
378 foreach ($plugins as $plugin_name => $plugin_info) {
\r
379 $_plugins_params .= "array('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], ";
\r
380 $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
\r
383 $_plugins_params .= '))';
\r
384 $plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
\r
385 $template_header .= $plugins_code;
\r
386 $this->_plugin_info = array();
\r
387 $this->_plugins_code = $plugins_code;
\r
390 if ($this->_init_smarty_vars) {
\r
391 $template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
\r
392 $this->_init_smarty_vars = false;
\r
395 $compiled_content = $template_header . $compiled_content;
\r
401 * Compile a template tag
\r
403 * @param string $template_tag
\r
406 function _compile_tag($template_tag)
\r
408 /* Matched comment. */
\r
409 if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
\r
412 /* Split tag into two three parts: command, command modifiers and the arguments. */
\r
413 if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp
\r
414 . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
\r
416 /xs', $template_tag, $match)) {
\r
417 $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
\r
420 $tag_command = $match[1];
\r
421 $tag_modifier = isset($match[2]) ? $match[2] : null;
\r
422 $tag_args = isset($match[3]) ? $match[3] : null;
\r
424 if (preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$!', $tag_command)) {
\r
425 /* tag name is a variable or object */
\r
426 $_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args));
\r
427 if(isset($_tag_attrs['assign'])) {
\r
428 return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n";
\r
430 return "<?php echo $_return; ?>" . $this->_additional_newline;
\r
434 /* If the tag name is a registered object, we process it. */
\r
435 if (preg_match('!^\/?' . $this->_reg_obj_regexp . '$!', $tag_command)) {
\r
436 return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
\r
439 switch ($tag_command) {
\r
441 return $this->_compile_include_tag($tag_args);
\r
443 case 'include_php':
\r
444 return $this->_compile_include_php_tag($tag_args);
\r
447 return $this->_compile_if_tag($tag_args);
\r
450 return '<?php else: ?>';
\r
453 return $this->_compile_if_tag($tag_args, true);
\r
456 return '<?php endif; ?>';
\r
459 return $this->_compile_capture_tag(true, $tag_args);
\r
462 return $this->_compile_capture_tag(false);
\r
465 return $this->left_delimiter;
\r
468 return $this->right_delimiter;
\r
471 array_push($this->_sectionelse_stack, false);
\r
472 return $this->_compile_section_start($tag_args);
\r
474 case 'sectionelse':
\r
475 $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
\r
476 return "<?php endfor; else: ?>";
\r
479 if (array_pop($this->_sectionelse_stack))
\r
480 return "<?php endif; ?>";
\r
482 return "<?php endfor; endif; ?>";
\r
485 array_push($this->_foreachelse_stack, false);
\r
486 return $this->_compile_foreach_start($tag_args);
\r
489 case 'foreachelse':
\r
490 $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true;
\r
491 return "<?php endforeach; unset(\$_from); else: ?>";
\r
494 if (array_pop($this->_foreachelse_stack))
\r
495 return "<?php endif; ?>";
\r
497 return "<?php endforeach; unset(\$_from); endif; ?>";
\r
501 if ($tag_command{0}=='/') {
\r
502 if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
\r
503 $this->_additional_newline = "\n";
\r
504 return $this->left_delimiter.$tag_command.$this->right_delimiter;
\r
507 if ($this->_strip_depth++==0) { /* outermost opening {strip} */
\r
508 $this->_additional_newline = "";
\r
509 return $this->left_delimiter.$tag_command.$this->right_delimiter;
\r
515 list (,$literal_block) = each($this->_literal_blocks);
\r
516 $this->_current_line_no += substr_count($literal_block, "\n");
\r
517 return "<?php echo '".str_replace("'", "\'", str_replace("\\", "\\\\", $literal_block))."'; ?>" . $this->_additional_newline;
\r
520 if ($this->security && !$this->security_settings['PHP_TAGS']) {
\r
521 $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
\r
524 list (,$php_block) = each($this->_php_blocks);
\r
525 $this->_current_line_no += substr_count($php_block, "\n");
\r
526 return '<?php '.$php_block.' ?>';
\r
529 return $this->_compile_insert_tag($tag_args);
\r
532 if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
\r
534 } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
\r
537 return $this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier);
\r
544 * compile the custom compiler tag
\r
546 * sets $output to the compiled custom compiler tag
\r
547 * @param string $tag_command
\r
548 * @param string $tag_args
\r
549 * @param string $output
\r
552 function _compile_compiler_tag($tag_command, $tag_args, &$output)
\r
555 $have_function = true;
\r
558 * First we check if the compiler function has already been registered
\r
559 * or loaded from a plugin file.
\r
561 if (isset($this->_plugins['compiler'][$tag_command])) {
\r
563 $plugin_func = $this->_plugins['compiler'][$tag_command][0];
\r
564 if (!is_callable($plugin_func)) {
\r
565 $message = "compiler function '$tag_command' is not implemented";
\r
566 $have_function = false;
\r
570 * Otherwise we need to load plugin file and look for the function
\r
573 else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
\r
576 include_once $plugin_file;
\r
578 $plugin_func = 'smarty_compiler_' . $tag_command;
\r
579 if (!is_callable($plugin_func)) {
\r
580 $message = "plugin function $plugin_func() not found in $plugin_file\n";
\r
581 $have_function = false;
\r
583 $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
\r
588 * True return value means that we either found a plugin or a
\r
589 * dynamically registered function. False means that we didn't and the
\r
590 * compiler should now emit code to load custom function plugin for this
\r
594 if ($have_function) {
\r
595 $output = call_user_func_array($plugin_func, array($tag_args, &$this));
\r
596 if($output != '') {
\r
597 $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
\r
599 . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
\r
602 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
\r
612 * compile block function tag
\r
614 * sets $output to compiled block function tag
\r
615 * @param string $tag_command
\r
616 * @param string $tag_args
\r
617 * @param string $tag_modifier
\r
618 * @param string $output
\r
621 function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
\r
623 if ($tag_command{0} == '/') {
\r
624 $start_tag = false;
\r
625 $tag_command = substr($tag_command, 1);
\r
630 $have_function = true;
\r
633 * First we check if the block function has already been registered
\r
634 * or loaded from a plugin file.
\r
636 if (isset($this->_plugins['block'][$tag_command])) {
\r
638 $plugin_func = $this->_plugins['block'][$tag_command][0];
\r
639 if (!is_callable($plugin_func)) {
\r
640 $message = "block function '$tag_command' is not implemented";
\r
641 $have_function = false;
\r
645 * Otherwise we need to load plugin file and look for the function
\r
648 else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
\r
651 include_once $plugin_file;
\r
653 $plugin_func = 'smarty_block_' . $tag_command;
\r
654 if (!function_exists($plugin_func)) {
\r
655 $message = "plugin function $plugin_func() not found in $plugin_file\n";
\r
656 $have_function = false;
\r
658 $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
\r
665 } else if (!$have_function) {
\r
666 $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
\r
671 * Even though we've located the plugin function, compilation
\r
672 * happens only once, so the plugin will still need to be loaded
\r
673 * at runtime for future requests.
\r
675 $this->_add_plugin('block', $tag_command);
\r
678 $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
\r
679 $attrs = $this->_parse_attrs($tag_args);
\r
680 $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs='');
\r
681 $output .= "$_cache_attrs\$_params = \$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
\r
682 $output .= $this->_compile_plugin_call('block', $tag_command).'($_params[1], null, $this, $_block_repeat=true); unset($_params);';
\r
683 $output .= 'while ($_block_repeat) { ob_start(); ?>';
\r
685 $output = '<?php $this->_block_content = ob_get_contents(); ob_end_clean(); ';
\r
686 $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $this->_block_content, $this, $_block_repeat=false)';
\r
687 if ($tag_modifier != '') {
\r
688 $this->_parse_modifiers($_out_tag_text, $tag_modifier);
\r
690 $output .= 'echo '.$_out_tag_text.'; } ';
\r
691 $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
\r
699 * compile custom function tag
\r
701 * @param string $tag_command
\r
702 * @param string $tag_args
\r
703 * @param string $tag_modifier
\r
706 function _compile_custom_tag($tag_command, $tag_args, $tag_modifier)
\r
708 $this->_add_plugin('function', $tag_command);
\r
710 $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
\r
711 $attrs = $this->_parse_attrs($tag_args);
\r
712 $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs='');
\r
714 $_return = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
\r
715 if($tag_modifier != '') {
\r
716 $this->_parse_modifiers($_return, $tag_modifier);
\r
719 if($_return != '') {
\r
720 $_return = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $_return . ';'
\r
721 . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
\r
728 * compile a registered object tag
\r
730 * @param string $tag_command
\r
731 * @param array $attrs
\r
732 * @param string $tag_modifier
\r
735 function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
\r
737 if ($tag_command{0} == '/') {
\r
738 $start_tag = false;
\r
739 $tag_command = substr($tag_command, 1);
\r
744 list($object, $obj_comp) = explode('->', $tag_command);
\r
746 $arg_list = array();
\r
747 if(count($attrs)) {
\r
748 $_assign_var = false;
\r
749 foreach ($attrs as $arg_name => $arg_value) {
\r
750 if($arg_name == 'assign') {
\r
751 $_assign_var = $arg_value;
\r
752 unset($attrs['assign']);
\r
755 if (is_bool($arg_value))
\r
756 $arg_value = $arg_value ? 'true' : 'false';
\r
757 $arg_list[] = "'$arg_name' => $arg_value";
\r
761 if($this->_reg_objects[$object][2]) {
\r
762 // smarty object argument format
\r
763 $args = "array(".implode(',', (array)$arg_list)."), \$this";
\r
765 // traditional argument format
\r
766 $args = implode(',', array_values($attrs));
\r
767 if (empty($args)) {
\r
775 if(!is_object($this->_reg_objects[$object][0])) {
\r
776 $this->_trigger_fatal_error("registered '$object' is not an object");
\r
777 } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
\r
778 $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'");
\r
779 } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
\r
781 if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
\r
784 $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
\r
785 $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); ";
\r
786 $prefix .= "while (\$_block_repeat) { ob_start();";
\r
790 $prefix = "\$this->_obj_block_content = ob_get_contents(); ob_end_clean(); ";
\r
791 $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_obj_block_content, \$this, \$_block_repeat=false)";
\r
792 $postfix = "} array_pop(\$this->_tag_stack);";
\r
795 // non-block method
\r
796 $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
\r
800 $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
\r
803 if($return != null) {
\r
804 if($tag_modifier != '') {
\r
805 $this->_parse_modifiers($return, $tag_modifier);
\r
808 if(!empty($_assign_var)) {
\r
809 $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);";
\r
811 $output = 'echo ' . $return . ';';
\r
812 $newline = $this->_additional_newline;
\r
818 return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
\r
822 * Compile {insert ...} tag
\r
824 * @param string $tag_args
\r
827 function _compile_insert_tag($tag_args)
\r
829 $attrs = $this->_parse_attrs($tag_args);
\r
830 $name = $this->_dequote($attrs['name']);
\r
832 if (empty($name)) {
\r
833 $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
\r
836 if (!empty($attrs['script'])) {
\r
837 $delayed_loading = true;
\r
839 $delayed_loading = false;
\r
842 foreach ($attrs as $arg_name => $arg_value) {
\r
843 if (is_bool($arg_value))
\r
844 $arg_value = $arg_value ? 'true' : 'false';
\r
845 $arg_list[] = "'$arg_name' => $arg_value";
\r
848 $this->_add_plugin('insert', $name, $delayed_loading);
\r
850 $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
\r
852 return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
\r
856 * Compile {include ...} tag
\r
858 * @param string $tag_args
\r
861 function _compile_include_tag($tag_args)
\r
863 $attrs = $this->_parse_attrs($tag_args);
\r
864 $arg_list = array();
\r
866 if (empty($attrs['file'])) {
\r
867 $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
\r
870 foreach ($attrs as $arg_name => $arg_value) {
\r
871 if ($arg_name == 'file') {
\r
872 $include_file = $arg_value;
\r
874 } else if ($arg_name == 'assign') {
\r
875 $assign_var = $arg_value;
\r
878 if (is_bool($arg_value))
\r
879 $arg_value = $arg_value ? 'true' : 'false';
\r
880 $arg_list[] = "'$arg_name' => $arg_value";
\r
883 $output = '<?php ';
\r
885 if (isset($assign_var)) {
\r
886 $output .= "ob_start();\n";
\r
890 "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
\r
893 $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
\r
894 $output .= "\$this->_smarty_include($_params);\n" .
\r
895 "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
\r
896 "unset(\$_smarty_tpl_vars);\n";
\r
898 if (isset($assign_var)) {
\r
899 $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
\r
909 * Compile {include ...} tag
\r
911 * @param string $tag_args
\r
914 function _compile_include_php_tag($tag_args)
\r
916 $attrs = $this->_parse_attrs($tag_args);
\r
918 if (empty($attrs['file'])) {
\r
919 $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
\r
922 $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
\r
923 $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
\r
925 foreach($attrs as $arg_name => $arg_value) {
\r
926 if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
\r
927 if(is_bool($arg_value))
\r
928 $arg_value = $arg_value ? 'true' : 'false';
\r
929 $arg_list[] = "'$arg_name' => $arg_value";
\r
933 $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
\r
935 return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
\r
940 * Compile {section ...} tag
\r
942 * @param string $tag_args
\r
945 function _compile_section_start($tag_args)
\r
947 $attrs = $this->_parse_attrs($tag_args);
\r
948 $arg_list = array();
\r
950 $output = '<?php ';
\r
951 $section_name = $attrs['name'];
\r
952 if (empty($section_name)) {
\r
953 $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
\r
956 $output .= "if (isset(\$this->_sections[$section_name])) unset(\$this->_sections[$section_name]);\n";
\r
957 $section_props = "\$this->_sections[$section_name]";
\r
959 foreach ($attrs as $attr_name => $attr_value) {
\r
960 switch ($attr_name) {
\r
962 $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
\r
966 if (is_bool($attr_value))
\r
967 $show_attr_value = $attr_value ? 'true' : 'false';
\r
969 $show_attr_value = "(bool)$attr_value";
\r
970 $output .= "{$section_props}['show'] = $show_attr_value;\n";
\r
974 $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
\r
979 $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
\r
983 $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
\r
987 $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
\r
992 if (!isset($attrs['show']))
\r
993 $output .= "{$section_props}['show'] = true;\n";
\r
995 if (!isset($attrs['loop']))
\r
996 $output .= "{$section_props}['loop'] = 1;\n";
\r
998 if (!isset($attrs['max']))
\r
999 $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
\r
1001 $output .= "if ({$section_props}['max'] < 0)\n" .
\r
1002 " {$section_props}['max'] = {$section_props}['loop'];\n";
\r
1004 if (!isset($attrs['step']))
\r
1005 $output .= "{$section_props}['step'] = 1;\n";
\r
1007 if (!isset($attrs['start']))
\r
1008 $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
\r
1010 $output .= "if ({$section_props}['start'] < 0)\n" .
\r
1011 " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
\r
1013 " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
\r
1016 $output .= "if ({$section_props}['show']) {\n";
\r
1017 if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
\r
1018 $output .= " {$section_props}['total'] = {$section_props}['loop'];\n";
\r
1020 $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";
\r
1022 $output .= " if ({$section_props}['total'] == 0)\n" .
\r
1023 " {$section_props}['show'] = false;\n" .
\r
1025 " {$section_props}['total'] = 0;\n";
\r
1027 $output .= "if ({$section_props}['show']):\n";
\r
1029 for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
\r
1030 {$section_props}['iteration'] <= {$section_props}['total'];
\r
1031 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
\r
1032 $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
\r
1033 $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
\r
1034 $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
\r
1035 $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n";
\r
1036 $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n";
\r
1045 * Compile {foreach ...} tag.
\r
1047 * @param string $tag_args
\r
1050 function _compile_foreach_start($tag_args)
\r
1052 $attrs = $this->_parse_attrs($tag_args);
\r
1053 $arg_list = array();
\r
1055 if (empty($attrs['from'])) {
\r
1056 $this->_syntax_error("missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
\r
1059 if (empty($attrs['item'])) {
\r
1060 $this->_syntax_error("missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
\r
1063 $from = $attrs['from'];
\r
1064 $item = $this->_dequote($attrs['item']);
\r
1065 if (isset($attrs['name']))
\r
1066 $name = $attrs['name'];
\r
1068 $output = '<?php ';
\r
1069 if (isset($name)) {
\r
1070 $output .= "if (isset(\$this->_foreach[$name])) unset(\$this->_foreach[$name]);\n";
\r
1071 $foreach_props = "\$this->_foreach[$name]";
\r
1076 foreach ($attrs as $attr_name => $attr_value) {
\r
1077 switch ($attr_name) {
\r
1079 $key = $this->_dequote($attrs['key']);
\r
1080 $key_part = "\$this->_tpl_vars['$key'] => ";
\r
1084 $output .= "{$foreach_props}['$attr_name'] = $attr_value;\n";
\r
1089 if (isset($name)) {
\r
1090 $output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n";
\r
1091 $output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";
\r
1092 $output .= "if ({$foreach_props}['show']):\n";
\r
1093 $output .= "{$foreach_props}['iteration'] = 0;\n";
\r
1094 $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
\r
1095 $output .= " {$foreach_props}['iteration']++;\n";
\r
1096 $output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";
\r
1097 $output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
\r
1099 $output .= "if (count(\$_from = (array)$from)):\n";
\r
1100 $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
\r
1109 * Compile {capture} .. {/capture} tags
\r
1111 * @param boolean $start true if this is the {capture} tag
\r
1112 * @param string $tag_args
\r
1116 function _compile_capture_tag($start, $tag_args = '')
\r
1118 $attrs = $this->_parse_attrs($tag_args);
\r
1121 if (isset($attrs['name']))
\r
1122 $buffer = $attrs['name'];
\r
1124 $buffer = "'default'";
\r
1126 if (isset($attrs['assign']))
\r
1127 $assign = $attrs['assign'];
\r
1130 $output = "<?php ob_start(); ?>";
\r
1131 $this->_capture_stack[] = array($buffer, $assign);
\r
1133 list($buffer, $assign) = array_pop($this->_capture_stack);
\r
1134 $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
\r
1135 if (isset($assign)) {
\r
1136 $output .= " \$this->assign($assign, ob_get_contents());";
\r
1138 $output .= "ob_end_clean(); ?>";
\r
1145 * Compile {if ...} tag
\r
1147 * @param string $tag_args
\r
1148 * @param boolean $elseif if true, uses elseif instead of if
\r
1151 function _compile_if_tag($tag_args, $elseif = false)
\r
1154 /* Tokenize args for 'if' tag. */
\r
1155 preg_match_all('/(?>
\r
1156 ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
\r
1157 ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string
\r
1158 \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token
\r
1159 \b\w+\b | # valid word token
\r
1160 \S+ # anything else
\r
1161 )/x', $tag_args, $match);
\r
1163 $tokens = $match[0];
\r
1165 // make sure we have balanced parenthesis
\r
1166 $token_count = array_count_values($tokens);
\r
1167 if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
\r
1168 $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
\r
1171 $is_arg_stack = array();
\r
1173 for ($i = 0; $i < count($tokens); $i++) {
\r
1175 $token = &$tokens[$i];
\r
1177 switch (strtolower($token)) {
\r
1250 array_push($is_arg_stack, $i);
\r
1254 /* If last token was a ')', we operate on the parenthesized
\r
1255 expression. The start of the expression is on the stack.
\r
1256 Otherwise, we operate on the last encountered token. */
\r
1257 if ($tokens[$i-1] == ')')
\r
1258 $is_arg_start = array_pop($is_arg_stack);
\r
1260 $is_arg_start = $i-1;
\r
1261 /* Construct the argument for 'is' expression, so it knows
\r
1262 what to operate on. */
\r
1263 $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
\r
1265 /* Pass all tokens from next one until the end to the
\r
1266 'is' expression parsing function. The function will
\r
1267 return modified tokens, where the first one is the result
\r
1268 of the 'is' expression and the rest are the tokens it
\r
1270 $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
\r
1272 /* Replace the old tokens with the new ones. */
\r
1273 array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
\r
1275 /* Adjust argument start so that it won't change from the
\r
1276 current position for the next iteration. */
\r
1277 $i = $is_arg_start;
\r
1281 if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) {
\r
1283 if($this->security &&
\r
1284 !in_array($token, $this->security_settings['IF_FUNCS'])) {
\r
1285 $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
\r
1287 } elseif(preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$!', $token)) {
\r
1288 // object or variable
\r
1289 $token = $this->_parse_var_props($token);
\r
1290 } elseif(is_numeric($token)) {
\r
1291 // number, skip it
\r
1293 $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
\r
1300 return '<?php elseif ('.implode(' ', $tokens).'): ?>';
\r
1302 return '<?php if ('.implode(' ', $tokens).'): ?>';
\r
1306 function _compile_arg_list($type, $name, $attrs, &$cache_code) {
\r
1307 $arg_list = array();
\r
1309 if (isset($type) && isset($name)
\r
1310 && isset($this->_plugins[$type])
\r
1311 && isset($this->_plugins[$type][$name])
\r
1312 && empty($this->_plugins[$type][$name][4])
\r
1313 && is_array($this->_plugins[$type][$name][5])
\r
1315 /* we have a list of parameters that should be cached */
\r
1316 $_cache_attrs = $this->_plugins[$type][$name][5];
\r
1317 $_count = $this->_cache_attrs_count++;
\r
1318 $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
\r
1321 /* no parameters are cached */
\r
1322 $_cache_attrs = null;
\r
1325 foreach ($attrs as $arg_name => $arg_value) {
\r
1326 if (is_bool($arg_value))
\r
1327 $arg_value = $arg_value ? 'true' : 'false';
\r
1328 if (is_null($arg_value))
\r
1329 $arg_value = 'null';
\r
1330 if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
\r
1331 $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
\r
1333 $arg_list[] = "'$arg_name' => $arg_value";
\r
1340 * Parse is expression
\r
1342 * @param string $is_arg
\r
1343 * @param array $tokens
\r
1346 function _parse_is_expr($is_arg, $tokens)
\r
1349 $negate_expr = false;
\r
1351 if (($first_token = array_shift($tokens)) == 'not') {
\r
1352 $negate_expr = true;
\r
1353 $expr_type = array_shift($tokens);
\r
1355 $expr_type = $first_token;
\r
1357 switch ($expr_type) {
\r
1359 if (@$tokens[$expr_end] == 'by') {
\r
1361 $expr_arg = $tokens[$expr_end++];
\r
1362 $expr = "!(($is_arg / $expr_arg) % " . $this->_parse_var_props($expr_arg) . ")";
\r
1364 $expr = "!($is_arg % 2)";
\r
1368 if (@$tokens[$expr_end] == 'by') {
\r
1370 $expr_arg = $tokens[$expr_end++];
\r
1371 $expr = "(($is_arg / $expr_arg) % ". $this->_parse_var_props($expr_arg) . ")";
\r
1373 $expr = "($is_arg % 2)";
\r
1377 if (@$tokens[$expr_end] == 'by') {
\r
1379 $expr_arg = $tokens[$expr_end++];
\r
1380 $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
\r
1382 $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
\r
1387 $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
\r
1391 if ($negate_expr) {
\r
1392 $expr = "!($expr)";
\r
1395 array_splice($tokens, 0, $expr_end, $expr);
\r
1402 * Parse attribute string
\r
1404 * @param string $tag_args
\r
1407 function _parse_attrs($tag_args)
\r
1410 /* Tokenize tag attributes. */
\r
1411 preg_match_all('/(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
\r
1414 /x', $tag_args, $match);
\r
1415 $tokens = $match[0];
\r
1419 0 - expecting attribute name
\r
1421 2 - expecting attribute value (not '=') */
\r
1424 foreach ($tokens as $token) {
\r
1427 /* If the token is a valid identifier, we set attribute name
\r
1428 and go to state 1. */
\r
1429 if (preg_match('!^\w+$!', $token)) {
\r
1430 $attr_name = $token;
\r
1433 $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
\r
1437 /* If the token is '=', then we go to state 2. */
\r
1438 if ($token == '=') {
\r
1441 $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
\r
1445 /* If token is not '=', we set the attribute value and go to
\r
1447 if ($token != '=') {
\r
1448 /* We booleanize the token if it's a non-quoted possible
\r
1450 if (preg_match('!^(on|yes|true)$!', $token)) {
\r
1452 } else if (preg_match('!^(off|no|false)$!', $token)) {
\r
1454 } else if ($token == 'null') {
\r
1456 } else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) {
\r
1457 /* treat integer literally */
\r
1458 } else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
\r
1459 /* treat as a string, double-quote it escaping quotes */
\r
1460 $token = '"'.addslashes($token).'"';
\r
1463 $attrs[$attr_name] = $token;
\r
1466 $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
\r
1469 $last_token = $token;
\r
1474 $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
\r
1476 $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
\r
1480 $this->_parse_vars_props($attrs);
\r
1486 * compile multiple variables and section properties tokens into
\r
1489 * @param array $tokens
\r
1491 function _parse_vars_props(&$tokens)
\r
1493 foreach($tokens as $key => $val) {
\r
1494 $tokens[$key] = $this->_parse_var_props($val);
\r
1499 * compile single variable and section properties token into
\r
1502 * @param string $val
\r
1503 * @param string $tag_attrs
\r
1506 function _parse_var_props($val)
\r
1508 $val = trim($val);
\r
1510 if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$!', $val, $match)) {
\r
1511 // $ variable or object
\r
1512 $return = $this->_parse_var($match[1]);
\r
1513 if($match[2] != '') {
\r
1514 $this->_parse_modifiers($return, $match[2]);
\r
1518 elseif(preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
\r
1519 // double quoted text
\r
1520 preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
\r
1521 $return = $this->_expand_quoted_text($match[1]);
\r
1522 if($match[2] != '') {
\r
1523 $this->_parse_modifiers($return, $match[2]);
\r
1527 elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
\r
1528 // single quoted text
\r
1529 preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
\r
1530 if($match[2] != '') {
\r
1531 $this->_parse_modifiers($match[1], $match[2]);
\r
1535 elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
\r
1537 return $this->_parse_conf_var($val);
\r
1539 elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
\r
1541 return $this->_parse_section_prop($val);
\r
1543 elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
\r
1545 return $this->_expand_quoted_text('"' . $val .'"');
\r
1551 * expand quoted text with embedded variables
\r
1553 * @param string $var_expr
\r
1556 function _expand_quoted_text($var_expr)
\r
1558 // if contains unescaped $, expand it
\r
1559 if(preg_match_all('%(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)%', $var_expr, $_match)) {
\r
1560 $_match = $_match[0];
\r
1563 foreach($_match as $_var) {
\r
1564 $var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr);
\r
1566 $_return = preg_replace('%\.""|(?<!\\\\)""\.%', '', $var_expr);
\r
1568 $_return = $var_expr;
\r
1570 // replace double quoted literal string with single quotes
\r
1571 $_return = preg_replace('!^"([\s\w]+)"$!',"'\\1'",$_return);
\r
1576 * parse variable expression into PHP code
\r
1578 * @param string $var_expr
\r
1579 * @param string $output
\r
1582 function _parse_var($var_expr)
\r
1584 $_has_math = false;
\r
1585 $_math_vars = preg_split('!('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
\r
1587 if(count($_math_vars) > 1) {
\r
1589 $_complete_var = "";
\r
1590 // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
\r
1591 foreach($_math_vars as $_k => $_math_var) {
\r
1592 $_math_var = $_math_vars[$_k];
\r
1594 if(!empty($_math_var) || is_numeric($_math_var)) {
\r
1595 // hit a math operator, so process the stuff which came before it
\r
1596 if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) {
\r
1597 $_has_math = true;
\r
1598 if(!empty($_complete_var) || is_numeric($_complete_var)) {
\r
1599 $_output .= $this->_parse_var($_complete_var);
\r
1602 // just output the math operator to php
\r
1603 $_output .= $_math_var;
\r
1605 if(empty($_first_var))
\r
1606 $_first_var = $_complete_var;
\r
1608 $_complete_var = "";
\r
1610 // 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
\r
1611 for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) {
\r
1612 // fetch -> because it gets splitted at - and move it back together
\r
1613 if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) {
\r
1614 $_math_var .= $_math_vars[$_i].$_math_vars[$_i+1];
\r
1615 $_math_vars[$_i] = $_math_vars[$_i+1] = '';
\r
1620 $_complete_var .= $_math_var;
\r
1625 if(!empty($_complete_var) || is_numeric($_complete_var))
\r
1626 $_output .= $this->_parse_var($_complete_var, true);
\r
1628 // get the modifiers working (only the last var from math + modifier is left)
\r
1629 $var_expr = $_complete_var;
\r
1633 // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
\r
1634 if(is_numeric($var_expr{0}))
\r
1635 $_var_ref = $var_expr;
\r
1637 $_var_ref = substr($var_expr, 1);
\r
1640 // get [foo] and .foo and ->foo and (...) pieces
\r
1641 preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match);
\r
1643 $_indexes = $match[0];
\r
1644 $_var_name = array_shift($_indexes);
\r
1646 /* Handle $smarty.* variable references as a special case. */
\r
1647 if ($_var_name == 'smarty') {
\r
1649 * If the reference could be compiled, use the compiled output;
\r
1650 * otherwise, fall back on the $smarty variable generated at
\r
1653 if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
\r
1654 $_output = $smarty_ref;
\r
1656 $_var_name = substr(array_shift($_indexes), 1);
\r
1657 $_output = "\$this->_smarty_vars['$_var_name']";
\r
1659 } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) {
\r
1660 // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
\r
1661 if(count($_indexes) > 0)
\r
1663 $_var_name .= implode("", $_indexes);
\r
1664 $_indexes = array();
\r
1666 $_output = $_var_name;
\r
1668 $_output = "\$this->_tpl_vars['$_var_name']";
\r
1671 foreach ($_indexes as $_index) {
\r
1672 if ($_index{0} == '[') {
\r
1673 $_index = substr($_index, 1, -1);
\r
1674 if (is_numeric($_index)) {
\r
1675 $_output .= "[$_index]";
\r
1676 } elseif ($_index{0} == '$') {
\r
1677 if (strpos($_index, '.') !== false) {
\r
1678 $_output .= '[' . $this->_parse_var($_index) . ']';
\r
1680 $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
\r
1683 $_var_parts = explode('.', $_index);
\r
1684 $_var_section = $_var_parts[0];
\r
1685 $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
\r
1686 $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
\r
1688 } else if ($_index{0} == '.') {
\r
1689 if ($_index{1} == '$')
\r
1690 $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
\r
1692 $_output .= "['" . substr($_index, 1) . "']";
\r
1693 } else if (substr($_index,0,2) == '->') {
\r
1694 if(substr($_index,2,2) == '__') {
\r
1695 $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
\r
1696 } elseif($this->security && substr($_index, 2, 1) == '_') {
\r
1697 $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
\r
1698 } elseif ($_index{2} == '$') {
\r
1699 if ($this->security) {
\r
1700 $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
\r
1702 $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
\r
1705 $_output .= $_index;
\r
1707 } elseif ($_index{0} == '(') {
\r
1708 $_index = $this->_parse_parenth_args($_index);
\r
1709 $_output .= $_index;
\r
1711 $_output .= $_index;
\r
1720 * parse arguments in function call parenthesis
\r
1722 * @param string $parenth_args
\r
1725 function _parse_parenth_args($parenth_args)
\r
1727 preg_match_all('!' . $this->_param_regexp . '!',$parenth_args, $match);
\r
1728 $match = $match[0];
\r
1731 $orig_vals = $match;
\r
1732 $this->_parse_vars_props($match);
\r
1733 return str_replace($orig_vals, $match, $parenth_args);
\r
1737 * parse configuration variable expression into PHP code
\r
1739 * @param string $conf_var_expr
\r
1741 function _parse_conf_var($conf_var_expr)
\r
1743 $parts = explode('|', $conf_var_expr, 2);
\r
1744 $var_ref = $parts[0];
\r
1745 $modifiers = isset($parts[1]) ? $parts[1] : '';
\r
1747 $var_name = substr($var_ref, 1, -1);
\r
1749 $output = "\$this->_config[0]['vars']['$var_name']";
\r
1751 $this->_parse_modifiers($output, $modifiers);
\r
1757 * parse section property expression into PHP code
\r
1759 * @param string $section_prop_expr
\r
1762 function _parse_section_prop($section_prop_expr)
\r
1764 $parts = explode('|', $section_prop_expr, 2);
\r
1765 $var_ref = $parts[0];
\r
1766 $modifiers = isset($parts[1]) ? $parts[1] : '';
\r
1768 preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
\r
1769 $section_name = $match[1];
\r
1770 $prop_name = $match[2];
\r
1772 $output = "\$this->_sections['$section_name']['$prop_name']";
\r
1774 $this->_parse_modifiers($output, $modifiers);
\r
1781 * parse modifier chain into PHP code
\r
1783 * sets $output to parsed modified chain
\r
1784 * @param string $output
\r
1785 * @param string $modifier_string
\r
1787 function _parse_modifiers(&$output, $modifier_string)
\r
1789 preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $_match);
\r
1790 list(, $_modifiers, $modifier_arg_strings) = $_match;
\r
1792 for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
\r
1793 $_modifier_name = $_modifiers[$_i];
\r
1795 if($_modifier_name == 'smarty') {
\r
1796 // skip smarty modifier
\r
1800 preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$_i], $_match);
\r
1801 $_modifier_args = $_match[1];
\r
1803 if ($_modifier_name{0} == '@') {
\r
1804 $_map_array = false;
\r
1805 $_modifier_name = substr($_modifier_name, 1);
\r
1807 $_map_array = true;
\r
1810 $this->_add_plugin('modifier', $_modifier_name);
\r
1811 if (empty($this->_plugins['modifier'][$_modifier_name])
\r
1812 && !$this->_get_plugin_filepath('modifier', $_modifier_name)
\r
1813 && function_exists($_modifier_name)) {
\r
1814 if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
\r
1815 $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $_tpl_file, $_tpl_line, __FILE__, __LINE__);
\r
1817 $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false);
\r
1821 $this->_parse_vars_props($_modifier_args);
\r
1823 if($_modifier_name == 'default') {
\r
1824 // supress notifications of default modifier vars and args
\r
1825 if($output{0} == '$') {
\r
1826 $output = '@' . $output;
\r
1828 if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') {
\r
1829 $_modifier_args[0] = '@' . $_modifier_args[0];
\r
1832 if (count($_modifier_args) > 0)
\r
1833 $_modifier_args = ', '.implode(', ', $_modifier_args);
\r
1835 $_modifier_args = '';
\r
1837 if ($_map_array) {
\r
1838 $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))";
\r
1842 $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
\r
1852 * @param string $type
\r
1853 * @param string $name
\r
1854 * @param boolean? $delayed_loading
\r
1856 function _add_plugin($type, $name, $delayed_loading = null)
\r
1858 if (!isset($this->_plugin_info[$type])) {
\r
1859 $this->_plugin_info[$type] = array();
\r
1861 if (!isset($this->_plugin_info[$type][$name])) {
\r
1862 $this->_plugin_info[$type][$name] = array($this->_current_file,
\r
1863 $this->_current_line_no,
\r
1864 $delayed_loading);
\r
1870 * Compiles references of type $smarty.foo
\r
1872 * @param string $indexes
\r
1875 function _compile_smarty_ref(&$indexes)
\r
1877 /* Extract the reference name. */
\r
1878 $_ref = substr($indexes[0], 1);
\r
1879 foreach($indexes as $_index_no=>$_index) {
\r
1880 if ($_index{0} != '.' && $_index_no<2 || !preg_match('!^(\.|\[|->)!', $_index)) {
\r
1881 $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
\r
1887 $compiled_ref = 'time()';
\r
1893 array_shift($indexes);
\r
1894 $_var = $this->_parse_var_props(substr($indexes[0], 1));
\r
1895 if ($_ref == 'foreach')
\r
1896 $compiled_ref = "\$this->_foreach[$_var]";
\r
1898 $compiled_ref = "\$this->_sections[$_var]";
\r
1902 $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
\r
1906 $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
\r
1910 $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
\r
1914 $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
\r
1918 $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
\r
1922 $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
\r
1926 * These cases are handled either at run-time or elsewhere in the
\r
1930 if ($this->request_use_auto_globals) {
\r
1931 $compiled_ref = '$_REQUEST';
\r
1934 $this->_init_smarty_vars = true;
\r
1942 $compiled_ref = "'$this->_current_file'";
\r
1947 $compiled_ref = "'$this->_version'";
\r
1952 array_shift($indexes);
\r
1953 $_val = $this->_parse_var_props(substr($indexes[0],1));
\r
1954 $compiled_ref = '@constant(' . $_val . ')';
\r
1959 $compiled_ref = "\$this->_config[0]['vars']";
\r
1964 $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
\r
1968 if (isset($_max_index) && count($indexes) > $_max_index) {
\r
1969 $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
\r
1972 array_shift($indexes);
\r
1973 return $compiled_ref;
\r
1977 * compiles call to plugin of type $type with name $name
\r
1978 * returns a string containing the function-name or method call
\r
1979 * without the paramter-list that would have follow to make the
\r
1980 * call valid php-syntax
\r
1982 * @param string $type
\r
1983 * @param string $name
\r
1986 function _compile_plugin_call($type, $name) {
\r
1987 if (isset($this->_plugins[$type][$name])) {
\r
1988 /* plugin loaded */
\r
1989 if (is_array($this->_plugins[$type][$name][0])) {
\r
1990 return ((is_object($this->_plugins[$type][$name][0][0])) ?
\r
1991 "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */
\r
1992 : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */
\r
1993 ). $this->_plugins[$type][$name][0][1];
\r
1996 /* function callback */
\r
1997 return $this->_plugins[$type][$name][0];
\r
2001 /* plugin not loaded -> auto-loadable-plugin */
\r
2002 return 'smarty_'.$type.'_'.$name;
\r
2008 * load pre- and post-filters
\r
2010 function _load_filters()
\r
2012 if (count($this->_plugins['prefilter']) > 0) {
\r
2013 foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
\r
2014 if ($prefilter === false) {
\r
2015 unset($this->_plugins['prefilter'][$filter_name]);
\r
2016 $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
\r
2017 require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
\r
2018 smarty_core_load_plugins($_params, $this);
\r
2022 if (count($this->_plugins['postfilter']) > 0) {
\r
2023 foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
\r
2024 if ($postfilter === false) {
\r
2025 unset($this->_plugins['postfilter'][$filter_name]);
\r
2026 $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
\r
2027 require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
\r
2028 smarty_core_load_plugins($_params, $this);
\r
2036 * Quote subpattern references
\r
2038 * @param string $string
\r
2041 function _quote_replace($string)
\r
2043 return preg_replace('![\\$]\d!', '\\\\\\0', $string);
\r
2047 * display Smarty syntax error
\r
2049 * @param string $error_msg
\r
2050 * @param integer $error_type
\r
2051 * @param string $file
\r
2052 * @param integer $line
\r
2054 function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
\r
2056 if(isset($file) && isset($line)) {
\r
2057 $info = ' ('.basename($file).", line $line)";
\r
2061 trigger_error('Smarty: [in ' . $this->_current_file . ' line ' .
\r
2062 $this->_current_line_no . "]: syntax error: $error_msg$info", $error_type);
\r
2067 * check if the compilation changes from cacheable to
\r
2068 * non-cacheable state with the beginning of the current
\r
2069 * plugin. return php-code to reflect the transition.
\r
2072 function _push_cacheable_state($type, $name) {
\r
2073 $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
\r
2075 || 0<$this->_cacheable_state++) return '';
\r
2076 if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
\r
2077 $_ret = 'if ($this->caching) { echo \'{nocache:'
\r
2078 . $this->_cache_serial . '#' . $this->_nocache_count
\r
2085 * check if the compilation changes from non-cacheable to
\r
2086 * cacheable state with the end of the current plugin return
\r
2087 * php-code to reflect the transition.
\r
2090 function _pop_cacheable_state($type, $name) {
\r
2091 $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
\r
2093 || --$this->_cacheable_state>0) return '';
\r
2094 return 'if ($this->caching) { echo \'{/nocache:'
\r
2095 . $this->_cache_serial . '#' . ($this->_nocache_count++)
\r
2102 * compare to values by their string length
\r
2105 * @param string $a
\r
2106 * @param string $b
\r
2109 function _smarty_sort_length($a, $b)
\r
2114 if(strlen($a) == strlen($b))
\r
2115 return ($a > $b) ? -1 : 1;
\r
2117 return (strlen($a) > strlen($b)) ? -1 : 1;
\r
2121 /* vim: set et: */
\r