19
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
21
* @link http://smarty.php.net/
22
* @author Monte Ohrt <monte@ispi.net>
22
* @author Monte Ohrt <monte at ohrt dot com>
23
23
* @author Andrei Zmievski <andrei@php.net>
25
* @copyright 2001-2004 ispi of Lincoln, Inc.
25
* @copyright 2001-2005 New Digital Group, Inc.
29
/* $Id: Smarty_Compiler.class.php,v 1.314 2004/02/17 15:52:02 mohrt Exp $ */
29
/* $Id: Smarty_Compiler.class.php,v 1.364 2005/03/19 18:28:46 messju Exp $ */
32
32
* Template compiling class
49
49
var $_si_qstr_regexp = null;
50
50
var $_qstr_regexp = null;
51
51
var $_func_regexp = null;
52
var $_reg_obj_regexp = null;
52
53
var $_var_bracket_regexp = null;
54
var $_num_const_regexp = null;
53
55
var $_dvar_guts_regexp = null;
54
56
var $_dvar_regexp = null;
55
57
var $_cvar_regexp = null;
107
115
// $foo[5].bar[$foobar][4]
108
$this->_dvar_math_regexp = '[\+\-\*\/\%]';
116
$this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
109
117
$this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
110
$this->_dvar_num_var_regexp = '\-?\d+(?:\.\d+)?' . $this->_dvar_math_var_regexp;
111
118
$this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
112
. ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:\-?\d+(?:\.\d+)?|' . $this->_dvar_math_var_regexp . ')*)?';
119
. ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
113
120
$this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
115
122
// matches config vars:
142
149
// $foo->bar($foo, "foo")
143
150
// $foo->bar->foo()
144
151
// $foo->bar->foo->bar()
152
// $foo->bar($foo->bar)
153
// $foo->bar($foo->bar())
154
// $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
145
155
$this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
146
$this->_obj_params_regexp = '\((?:\w+|'
147
. $this->_var_regexp . '(?:\s*,\s*(?:(?:\w+|'
148
. $this->_var_regexp . ')))*)?\)';
156
$this->_obj_restricted_param_regexp = '(?:'
157
. '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
158
. '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
159
$this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
160
. $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
161
$this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
162
. '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
149
163
$this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
150
$this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?)';
164
$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 . ')*)?)';
152
166
// matches valid modifier syntax:
224
238
$this->_current_file = $resource_name;
225
239
$this->_current_line_no = 1;
226
$ldq = preg_quote($this->left_delimiter, '!');
227
$rdq = preg_quote($this->right_delimiter, '!');
240
$ldq = preg_quote($this->left_delimiter, '~');
241
$rdq = preg_quote($this->right_delimiter, '~');
229
243
// run template source through prefilter functions
230
244
if (count($this->_plugins['prefilter']) > 0) {
243
257
/* fetch all special blocks */
244
$search = "!{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s";
258
$search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
246
260
preg_match_all($search, $source_content, $match, PREG_SET_ORDER);
247
261
$this->_folded_blocks = $match;
256
270
, $source_content);
258
272
/* Gather all template tags. */
259
preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match);
273
preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
260
274
$template_tags = $_match[1];
261
275
/* Split content by template tags to obtain non-template content. */
262
$text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content);
276
$text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
264
278
/* loop through text blocks */
265
279
for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
266
280
/* match anything resembling php tags */
267
if (preg_match_all('!(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)!is', $text_blocks[$curr_tb], $sp_match)) {
281
if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
268
282
/* replace tags with placeholders to prevent recursive replacements */
269
283
$sp_match[1] = array_unique($sp_match[1]);
270
284
usort($sp_match[1], '_smarty_sort_length');
284
298
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
286
300
/* SMARTY_PHP_ALLOW, but echo non php starting tags */
287
$sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
301
$sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
288
302
$text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
321
/* Reformat $text_blocks between 'strip' and '/strip' tags,
322
removing spaces, tabs and newlines. */
324
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
325
if ($compiled_tags[$i] == '{strip}') {
326
$compiled_tags[$i] = '';
328
/* remove leading whitespaces */
329
$text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
332
/* strip all $text_blocks before the next '/strip' */
333
for ($j = $i + 1; $j < $for_max; $j++) {
334
/* remove leading and trailing whitespaces of each line */
335
$text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
336
if ($compiled_tags[$j] == '{/strip}') {
337
/* remove trailing whitespaces from the last text_block */
338
$text_blocks[$j] = rtrim($text_blocks[$j]);
340
$text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
341
if ($compiled_tags[$j] == '{/strip}') {
342
$compiled_tags[$j] = "\n"; /* slurped by php, but necessary
343
if a newline is following the closing strip-tag */
307
351
$compiled_content = '';
309
353
/* Interleave the compiled contents and text blocks to get the final result. */
310
354
for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
311
355
if ($compiled_tags[$i] == '') {
312
356
// tag result empty, remove first newline from following text block
313
$text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]);
357
$text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
315
359
$compiled_content .= $text_blocks[$i].$compiled_tags[$i];
317
361
$compiled_content .= $text_blocks[$i];
319
/* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
320
if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) {
321
$strip_tags = $_match[0];
322
$strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
323
$strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
324
for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)
325
$compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
326
$this->_quote_replace($strip_tags_modified[$i]),
327
$compiled_content, 1);
330
363
// remove \n from the end of the file, if any
331
364
if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
332
365
$compiled_content = substr($compiled_content, 0, -1);
339
372
// remove unnecessary close/open tags
340
$compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content);
373
$compiled_content = preg_replace('~\?>\n?<\?php~', '', $compiled_content);
342
375
// run compiled template through postfilter functions
343
376
if (count($this->_plugins['postfilter']) > 0) {
363
396
$_plugins_params = "array('plugins' => array(";
364
397
foreach ($this->_plugin_info as $plugin_type => $plugins) {
365
398
foreach ($plugins as $plugin_name => $plugin_info) {
366
$_plugins_params .= "array('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], ";
399
$_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
367
400
$_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
370
403
$_plugins_params .= '))';
371
$plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
404
$plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
372
405
$template_header .= $plugins_code;
373
406
$this->_plugin_info = array();
374
407
$this->_plugins_code = $plugins_code;
377
410
if ($this->_init_smarty_vars) {
378
$template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
411
$template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
379
412
$this->_init_smarty_vars = false;
394
427
/* Matched comment. */
395
428
if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
398
431
/* Split tag into two three parts: command, command modifiers and the arguments. */
399
if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp
432
if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
400
433
. '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
402
/xs', $template_tag, $match)) {
435
~xs', $template_tag, $match)) {
403
436
$this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
406
439
$tag_command = $match[1];
407
440
$tag_modifier = isset($match[2]) ? $match[2] : null;
408
441
$tag_args = isset($match[3]) ? $match[3] : null;
410
if (preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$!', $tag_command)) {
443
if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
411
444
/* tag name is a variable or object */
412
$_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args));
413
if(isset($_tag_attrs['assign'])) {
414
return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n";
416
return "<?php echo $_return; ?>" . $this->_additional_newline;
445
$_return = $this->_parse_var_props($tag_command . $tag_modifier);
446
return "<?php echo $_return; ?>" . $this->_additional_newline;
420
449
/* If the tag name is a registered object, we process it. */
421
if (preg_match('!^\/?' . $this->_reg_obj_regexp . '$!', $tag_command)) {
450
if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
422
451
return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
437
466
list($_open_tag) = end($this->_tag_stack);
438
467
if ($_open_tag != 'if' && $_open_tag != 'elseif')
439
$this->_syntax_error('unxepected {else}', E_USER_ERROR, __FILE__, __LINE__);
468
$this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
441
470
$this->_push_tag('else');
442
471
return '<?php else: ?>';
445
474
list($_open_tag) = end($this->_tag_stack);
446
475
if ($_open_tag != 'if' && $_open_tag != 'elseif')
447
$this->_syntax_error('unxepected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
476
$this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
448
477
if ($_open_tag == 'if')
449
478
$this->_push_tag('elseif');
450
479
return $this->_compile_if_tag($tag_args, true);
489
518
case 'foreachelse':
490
519
$this->_push_tag('foreachelse');
491
return "<?php endforeach; unset(\$_from); else: ?>";
520
return "<?php endforeach; else: ?>";
494
523
$_open_tag = $this->_pop_tag('foreach');
495
524
if ($_open_tag == 'foreachelse')
496
return "<?php endif; ?>";
525
return "<?php endif; unset(\$_from); ?>";
498
return "<?php endforeach; unset(\$_from); endif; ?>";
527
return "<?php endforeach; endif; unset(\$_from); ?>";
504
533
$this->_pop_tag('strip');
505
534
if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
506
535
$this->_additional_newline = "\n";
507
return $this->left_delimiter.$tag_command.$this->right_delimiter;
536
return '{' . $tag_command . '}';
510
539
$this->_push_tag('strip');
511
540
if ($this->_strip_depth++==0) { /* outermost opening {strip} */
512
541
$this->_additional_newline = "";
513
return $this->left_delimiter.$tag_command.$this->right_delimiter;
542
return '{' . $tag_command . '}';
702
731
$output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);';
703
732
$output .= 'while ($_block_repeat) { ob_start(); ?>';
705
$output = '<?php $this->_block_content = ob_get_contents(); ob_end_clean(); ';
706
$_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)';
734
$output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
735
$_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)';
707
736
if ($tag_modifier != '') {
708
737
$this->_parse_modifiers($_out_tag_text, $tag_modifier);
853
$prefix = "\$this->_obj_block_content = ob_get_contents(); ob_end_clean(); ";
854
$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)";
882
$prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); ";
883
$return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat=false)";
855
884
$postfix = "} array_pop(\$this->_tag_stack);";
997
1026
$_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
999
return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
1028
return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
1017
1046
$this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
1020
$output .= "if (isset(\$this->_sections[$section_name])) unset(\$this->_sections[$section_name]);\n";
1049
$output .= "unset(\$this->_sections[$section_name]);\n";
1021
1050
$section_props = "\$this->_sections[$section_name]";
1023
1052
foreach ($attrs as $attr_name => $attr_value) {
1117
1146
$arg_list = array();
1119
1148
if (empty($attrs['from'])) {
1120
$this->_syntax_error("missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
1149
return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
1151
$from = $attrs['from'];
1123
1153
if (empty($attrs['item'])) {
1124
$this->_syntax_error("missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
1154
return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
1127
$from = $attrs['from'];
1128
1156
$item = $this->_dequote($attrs['item']);
1129
if (isset($attrs['name']))
1157
if (!preg_match('~^\w+$~', $item)) {
1158
return $this->_syntax_error("'foreach: item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1161
if (isset($attrs['key'])) {
1162
$key = $this->_dequote($attrs['key']);
1163
if (!preg_match('~^\w+$~', $key)) {
1164
return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1166
$key_part = "\$this->_tpl_vars['$key'] => ";
1172
if (isset($attrs['name'])) {
1130
1173
$name = $attrs['name'];
1132
1178
$output = '<?php ';
1179
$output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
1133
1180
if (isset($name)) {
1134
$output .= "if (isset(\$this->_foreach[$name])) unset(\$this->_foreach[$name]);\n";
1135
1181
$foreach_props = "\$this->_foreach[$name]";
1140
foreach ($attrs as $attr_name => $attr_value) {
1141
switch ($attr_name) {
1143
$key = $this->_dequote($attrs['key']);
1144
$key_part = "\$this->_tpl_vars['$key'] => ";
1148
$output .= "{$foreach_props}['$attr_name'] = $attr_value;\n";
1154
$output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n";
1155
$output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";
1156
$output .= "if ({$foreach_props}['show']):\n";
1157
$output .= "{$foreach_props}['iteration'] = 0;\n";
1182
$output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
1183
$output .= "if ({$foreach_props}['total'] > 0):\n";
1158
1184
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1159
1185
$output .= " {$foreach_props}['iteration']++;\n";
1160
$output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";
1161
$output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
1163
$output .= "if (count(\$_from = (array)$from)):\n";
1187
$output .= "if (count(\$_from)):\n";
1164
1188
$output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1166
1190
$output .= '?>';
1218
1242
/* Tokenize args for 'if' tag. */
1219
preg_match_all('/(?>
1243
preg_match_all('~(?>
1220
1244
' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
1221
1245
' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string
1222
1246
\-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token
1223
1247
\b\w+\b | # valid word token
1224
1248
\S+ # anything else
1225
)/x', $tag_args, $match);
1249
)~x', $tag_args, $match);
1227
1251
$tokens = $match[0];
1345
if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) {
1369
if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
1346
1370
// function call
1347
1371
if($this->security &&
1348
1372
!in_array($token, $this->security_settings['IF_FUNCS'])) {
1349
1373
$this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
1351
} elseif(preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$!', $token)) {
1375
} elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
1352
1376
// object or variable
1353
1377
$token = $this->_parse_var_props($token);
1354
1378
} elseif(is_numeric($token)) {
1511
1535
if ($token != '=') {
1512
1536
/* We booleanize the token if it's a non-quoted possible
1513
1537
boolean value. */
1514
if (preg_match('!^(on|yes|true)$!', $token)) {
1538
if (preg_match('~^(on|yes|true)$~', $token)) {
1515
1539
$token = 'true';
1516
} else if (preg_match('!^(off|no|false)$!', $token)) {
1540
} else if (preg_match('~^(off|no|false)$~', $token)) {
1517
1541
$token = 'false';
1518
1542
} else if ($token == 'null') {
1519
1543
$token = 'null';
1520
} else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) {
1544
} else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
1521
1545
/* treat integer literally */
1522
} else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
1546
} else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
1523
1547
/* treat as a string, double-quote it escaping quotes */
1524
1548
$token = '"'.addslashes($token).'"';
1572
1596
$val = trim($val);
1574
if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$!', $val, $match)) {
1598
if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
1575
1599
// $ variable or object
1576
1600
$return = $this->_parse_var($match[1]);
1577
1601
$modifiers = $match[2];
1578
if (!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) {
1602
if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
1579
1603
$_default_mod_string = implode('|',(array)$this->default_modifiers);
1580
1604
$modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
1582
1606
$this->_parse_modifiers($return, $modifiers);
1583
1607
return $return;
1584
} elseif (preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1608
} elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1585
1609
// double quoted text
1586
preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
1610
preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1587
1611
$return = $this->_expand_quoted_text($match[1]);
1588
1612
if($match[2] != '') {
1589
1613
$this->_parse_modifiers($return, $match[2]);
1591
1615
return $return;
1593
elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1617
elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1618
// numerical constant
1619
preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1620
if($match[2] != '') {
1621
$this->_parse_modifiers($match[1], $match[2]);
1625
elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1594
1626
// single quoted text
1595
preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
1627
preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1596
1628
if($match[2] != '') {
1597
1629
$this->_parse_modifiers($match[1], $match[2]);
1598
1630
return $match[1];
1601
elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1633
elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1603
1635
return $this->_parse_conf_var($val);
1605
elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1637
elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1607
1639
return $this->_parse_section_prop($val);
1622
1654
function _expand_quoted_text($var_expr)
1624
1656
// if contains unescaped $, expand it
1625
if(preg_match_all('%(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)%', $var_expr, $_match)) {
1657
if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
1626
1658
$_match = $_match[0];
1627
1659
rsort($_match);
1628
1660
reset($_match);
1629
1661
foreach($_match as $_var) {
1630
1662
$var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr);
1632
$_return = preg_replace('%\.""|(?<!\\\\)""\.%', '', $var_expr);
1664
$_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
1634
1666
$_return = $var_expr;
1636
1668
// replace double quoted literal string with single quotes
1637
$_return = preg_replace('!^"([\s\w]+)"$!',"'\\1'",$_return);
1669
$_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
1638
1670
return $_return;
1648
1680
function _parse_var($var_expr)
1650
1682
$_has_math = false;
1651
$_math_vars = preg_split('!('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
1683
$_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
1653
1685
if(count($_math_vars) > 1) {
1654
1686
$_first_var = "";
1661
1693
if(!empty($_math_var) || is_numeric($_math_var)) {
1662
1694
// hit a math operator, so process the stuff which came before it
1663
if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) {
1695
if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
1664
1696
$_has_math = true;
1665
1697
if(!empty($_complete_var) || is_numeric($_complete_var)) {
1666
1698
$_output .= $this->_parse_var($_complete_var);
1675
1707
$_complete_var = "";
1677
// 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
1678
for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) {
1679
// fetch -> because it gets splitted at - and move it back together
1680
if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) {
1681
$_math_var .= $_math_vars[$_i].$_math_vars[$_i+1];
1682
$_math_vars[$_i] = $_math_vars[$_i+1] = '';
1687
1709
$_complete_var .= $_math_var;
1691
1713
if($_has_math) {
1692
1714
if(!empty($_complete_var) || is_numeric($_complete_var))
1693
$_output .= $this->_parse_var($_complete_var, true);
1715
$_output .= $this->_parse_var($_complete_var);
1695
1717
// get the modifiers working (only the last var from math + modifier is left)
1696
1718
$var_expr = $_complete_var;
1702
1724
$_var_ref = $var_expr;
1704
1726
$_var_ref = substr($var_expr, 1);
1706
1728
if(!$_has_math) {
1707
1730
// get [foo] and .foo and ->foo and (...) pieces
1708
preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match);
1731
preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
1710
1733
$_indexes = $match[0];
1711
1734
$_var_name = array_shift($_indexes);
1792
1815
function _parse_parenth_args($parenth_args)
1794
preg_match_all('!' . $this->_param_regexp . '!',$parenth_args, $match);
1798
$orig_vals = $match;
1817
preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
1818
$orig_vals = $match = $match[0];
1799
1819
$this->_parse_vars_props($match);
1800
return str_replace($orig_vals, $match, $parenth_args);
1821
for ($i = 0, $count = count($match); $i < $count; $i++) {
1822
$replace[$orig_vals[$i]] = $match[$i];
1824
return strtr($parenth_args, $replace);
1854
1878
function _parse_modifiers(&$output, $modifier_string)
1856
preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $_match);
1880
preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
1857
1881
list(, $_modifiers, $modifier_arg_strings) = $_match;
1859
1883
for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
1944
1968
/* Extract the reference name. */
1945
1969
$_ref = substr($indexes[0], 1);
1946
1970
foreach($indexes as $_index_no=>$_index) {
1947
if ($_index{0} != '.' && $_index_no<2 || !preg_match('!^(\.|\[|->)!', $_index)) {
1971
if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
1948
1972
$this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
1958
1982
case 'foreach':
1983
array_shift($indexes);
1984
$_var = $this->_parse_var_props(substr($indexes[0], 1));
1985
$_propname = substr($indexes[1], 1);
1987
switch ($_propname) {
1989
array_shift($indexes);
1990
$compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
1994
array_shift($indexes);
1995
$compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
1999
array_shift($indexes);
2000
$compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
2004
array_shift($indexes);
2005
$compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
2010
$compiled_ref = "\$this->_foreach[$_var]";
1959
2014
case 'section':
1960
2015
array_shift($indexes);
1961
2016
$_var = $this->_parse_var_props(substr($indexes[0], 1));
1962
if ($_ref == 'foreach')
1963
$compiled_ref = "\$this->_foreach[$_var]";
1965
$compiled_ref = "\$this->_sections[$_var]";
2017
$compiled_ref = "\$this->_sections[$_var]";
2071
if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
2072
$this->_syntax_error("(secure mode) constants not permitted",
2073
E_USER_WARNING, __FILE__, __LINE__);
2019
2076
array_shift($indexes);
2020
$_val = $this->_parse_var_props(substr($indexes[0],1));
2021
$compiled_ref = '@constant(' . $_val . ')';
2077
if (preg_match('!^\.\w+$!', $indexes[0])) {
2078
$compiled_ref = '@' . substr($indexes[0], 1);
2080
$_val = $this->_parse_var_props(substr($indexes[0], 1));
2081
$compiled_ref = '@constant(' . $_val . ')';
2022
2083
$_max_index = 1;
2081
2150
if ($prefilter === false) {
2082
2151
unset($this->_plugins['prefilter'][$filter_name]);
2083
2152
$_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
2084
require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
2153
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2085
2154
smarty_core_load_plugins($_params, $this);
2091
2160
if ($postfilter === false) {
2092
2161
unset($this->_plugins['postfilter'][$filter_name]);
2093
2162
$_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
2094
require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
2163
require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2095
2164
smarty_core_load_plugins($_params, $this);