Хранилища Subversion ant

Редакция

Редакция 2 | Только различия | Не учитывать пробелы | Содержимое файла | Авторство | Последнее изменение | Открыть журнал | RSS

Редакция 2 Редакция 458
1
<?php
1
<?php
2
2
3
/**
3
/**
4
 * Project:     Smarty: the PHP compiling template engine
4
 * Project:     Smarty: the PHP compiling template engine
5
 * File:        Smarty_Compiler.class.php
5
 * File:        Smarty_Compiler.class.php
6
 *
6
 *
7
 * This library is free software; you can redistribute it and/or
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
11
 *
12
 * This library is distributed in the hope that it will be useful,
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
15
 * Lesser General Public License for more details.
16
 *
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 *
20
 *
21
 * @link http://www.smarty.net/
21
 * @link http://www.smarty.net/
22
 * @author Monte Ohrt <monte at ohrt dot com>
22
 * @author Monte Ohrt <monte at ohrt dot com>
23
 * @author Andrei Zmievski <andrei@php.net>
23
 * @author Andrei Zmievski <andrei@php.net>
24
 * @version 2.6.22
24
 * @version 2.6.22
25
 * @copyright 2001-2005 New Digital Group, Inc.
25
 * @copyright 2001-2005 New Digital Group, Inc.
26
 * @package Smarty
26
 * @package Smarty
27
 */
27
 */
28
28
29
/* $Id: Smarty_Compiler.class.php 2966 2008-12-08 15:10:03Z monte.ohrt $ */
29
/* $Id: Smarty_Compiler.class.php 2966 2008-12-08 15:10:03Z monte.ohrt $ */
30
30
31
/**
31
/**
32
 * Template compiling class
32
 * Template compiling class
33
 * @package Smarty
33
 * @package Smarty
34
 */
34
 */
35
class Smarty_Compiler extends Smarty {
35
class Smarty_Compiler extends Smarty {
36
36
37
    // internal vars
37
    // internal vars
38
    /**#@+
38
    /**#@+
39
     * @access private
39
     * @access private
40
     */
40
     */
41
    var $_folded_blocks         =   array();    // keeps folded template blocks
41
    var $_folded_blocks         =   array();    // keeps folded template blocks
42
    var $_current_file          =   null;       // the current template being compiled
42
    var $_current_file          =   null;       // the current template being compiled
43
    var $_current_line_no       =   1;          // line number for error messages
43
    var $_current_line_no       =   1;          // line number for error messages
44
    var $_capture_stack         =   array();    // keeps track of nested capture buffers
44
    var $_capture_stack         =   array();    // keeps track of nested capture buffers
45
    var $_plugin_info           =   array();    // keeps track of plugins to load
45
    var $_plugin_info           =   array();    // keeps track of plugins to load
46
    var $_init_smarty_vars      =   false;
46
    var $_init_smarty_vars      =   false;
47
    var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');
47
    var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');
48
    var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor
48
    var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor
49
    var $_si_qstr_regexp        =   null;
49
    var $_si_qstr_regexp        =   null;
50
    var $_qstr_regexp           =   null;
50
    var $_qstr_regexp           =   null;
51
    var $_func_regexp           =   null;
51
    var $_func_regexp           =   null;
52
    var $_reg_obj_regexp        =   null;
52
    var $_reg_obj_regexp        =   null;
53
    var $_var_bracket_regexp    =   null;
53
    var $_var_bracket_regexp    =   null;
54
    var $_num_const_regexp      =   null;
54
    var $_num_const_regexp      =   null;
55
    var $_dvar_guts_regexp      =   null;
55
    var $_dvar_guts_regexp      =   null;
56
    var $_dvar_regexp           =   null;
56
    var $_dvar_regexp           =   null;
57
    var $_cvar_regexp           =   null;
57
    var $_cvar_regexp           =   null;
58
    var $_svar_regexp           =   null;
58
    var $_svar_regexp           =   null;
59
    var $_avar_regexp           =   null;
59
    var $_avar_regexp           =   null;
60
    var $_mod_regexp            =   null;
60
    var $_mod_regexp            =   null;
61
    var $_var_regexp            =   null;
61
    var $_var_regexp            =   null;
62
    var $_parenth_param_regexp  =   null;
62
    var $_parenth_param_regexp  =   null;
63
    var $_func_call_regexp      =   null;
63
    var $_func_call_regexp      =   null;
64
    var $_obj_ext_regexp        =   null;
64
    var $_obj_ext_regexp        =   null;
65
    var $_obj_start_regexp      =   null;
65
    var $_obj_start_regexp      =   null;
66
    var $_obj_params_regexp     =   null;
66
    var $_obj_params_regexp     =   null;
67
    var $_obj_call_regexp       =   null;
67
    var $_obj_call_regexp       =   null;
68
    var $_cacheable_state       =   0;
68
    var $_cacheable_state       =   0;
69
    var $_cache_attrs_count     =   0;
69
    var $_cache_attrs_count     =   0;
70
    var $_nocache_count         =   0;
70
    var $_nocache_count         =   0;
71
    var $_cache_serial          =   null;
71
    var $_cache_serial          =   null;
72
    var $_cache_include         =   null;
72
    var $_cache_include         =   null;
73
73
74
    var $_strip_depth           =   0;
74
    var $_strip_depth           =   0;
75
    var $_additional_newline    =   "\n";
75
    var $_additional_newline    =   "\n";
76
   
76
   
77
    var $_phpversion            =   0;
77
    var $_phpversion            =   0;
78
78
79
79
80
    /**#@-*/
80
    /**#@-*/
81
    /**
81
    /**
82
     * The class constructor.
82
     * The class constructor.
83
     */
83
     */
84
    function Smarty_Compiler()
84
    function Smarty_Compiler()
85
    {
85
    {
86
        $this->_phpversion = substr(phpversion(),0,1);
86
        $this->_phpversion = substr(phpversion(),0,1);
87
87
88
        // matches double quoted strings:
88
        // matches double quoted strings:
89
        // "foobar"
89
        // "foobar"
90
        // "foo\"bar"
90
        // "foo\"bar"
91
        $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
91
        $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
92
92
93
        // matches single quoted strings:
93
        // matches single quoted strings:
94
        // 'foobar'
94
        // 'foobar'
95
        // 'foo\'bar'
95
        // 'foo\'bar'
96
        $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
96
        $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
97
97
98
        // matches single or double quoted strings
98
        // matches single or double quoted strings
99
        $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
99
        $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
100
100
101
        // matches bracket portion of vars
101
        // matches bracket portion of vars
102
        // [0]
102
        // [0]
103
        // [foo]
103
        // [foo]
104
        // [$bar]
104
        // [$bar]
105
        $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
105
        $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
106
106
107
        // matches numerical constants
107
        // matches numerical constants
108
        // 30
108
        // 30
109
        // -12
109
        // -12
110
        // 13.22
110
        // 13.22
111
        $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
111
        $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
112
112
113
        // matches $ vars (not objects):
113
        // matches $ vars (not objects):
114
        // $foo
114
        // $foo
115
        // $foo.bar
115
        // $foo.bar
116
        // $foo.bar.foobar
116
        // $foo.bar.foobar
117
        // $foo[0]
117
        // $foo[0]
118
        // $foo[$bar]
118
        // $foo[$bar]
119
        // $foo[5][blah]
119
        // $foo[5][blah]
120
        // $foo[5].bar[$foobar][4]
120
        // $foo[5].bar[$foobar][4]
121
        $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
121
        $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
122
        $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
122
        $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
123
        $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
123
        $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
124
                . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
124
                . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
125
        $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
125
        $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
126
126
127
        // matches config vars:
127
        // matches config vars:
128
        // #foo#
128
        // #foo#
129
        // #foobar123_foo#
129
        // #foobar123_foo#
130
        $this->_cvar_regexp = '\#\w+\#';
130
        $this->_cvar_regexp = '\#\w+\#';
131
131
132
        // matches section vars:
132
        // matches section vars:
133
        // %foo.bar%
133
        // %foo.bar%
134
        $this->_svar_regexp = '\%\w+\.\w+\%';
134
        $this->_svar_regexp = '\%\w+\.\w+\%';
135
135
136
        // matches all valid variables (no quotes, no modifiers)
136
        // matches all valid variables (no quotes, no modifiers)
137
        $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
137
        $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
138
           . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
138
           . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
139
139
140
        // matches valid variable syntax:
140
        // matches valid variable syntax:
141
        // $foo
141
        // $foo
142
        // $foo
142
        // $foo
143
        // #foo#
143
        // #foo#
144
        // #foo#
144
        // #foo#
145
        // "text"
145
        // "text"
146
        // "text"
146
        // "text"
147
        $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
147
        $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
148
148
149
        // matches valid object call (one level of object nesting allowed in parameters):
149
        // matches valid object call (one level of object nesting allowed in parameters):
150
        // $foo->bar
150
        // $foo->bar
151
        // $foo->bar()
151
        // $foo->bar()
152
        // $foo->bar("text")
152
        // $foo->bar("text")
153
        // $foo->bar($foo, $bar, "text")
153
        // $foo->bar($foo, $bar, "text")
154
        // $foo->bar($foo, "foo")
154
        // $foo->bar($foo, "foo")
155
        // $foo->bar->foo()
155
        // $foo->bar->foo()
156
        // $foo->bar->foo->bar()
156
        // $foo->bar->foo->bar()
157
        // $foo->bar($foo->bar)
157
        // $foo->bar($foo->bar)
158
        // $foo->bar($foo->bar())
158
        // $foo->bar($foo->bar())
159
        // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
159
        // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
160
        // $foo->getBar()->getFoo()
160
        // $foo->getBar()->getFoo()
161
        // $foo->getBar()->foo
161
        // $foo->getBar()->foo
162
        $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
162
        $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
163
        $this->_obj_restricted_param_regexp = '(?:'
163
        $this->_obj_restricted_param_regexp = '(?:'
164
             . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
164
             . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
165
             . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
165
             . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
166
166
167
       $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
167
       $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
168
                . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
168
                . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
169
169
170
       $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
170
       $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
171
                . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
171
                . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
172
       $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
172
       $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
173
       $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 . ')*)?)';
173
       $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 . ')*)?)';
174
       
174
       
175
        // matches valid modifier syntax:
175
        // matches valid modifier syntax:
176
        // |foo
176
        // |foo
177
        // |@foo
177
        // |@foo
178
        // |foo:"bar"
178
        // |foo:"bar"
179
        // |foo:$bar
179
        // |foo:$bar
180
        // |foo:"bar":$foobar
180
        // |foo:"bar":$foobar
181
        // |foo|bar
181
        // |foo|bar
182
        // |foo:$foo->bar
182
        // |foo:$foo->bar
183
        $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
183
        $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
184
           . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
184
           . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
185
185
186
        // matches valid function name:
186
        // matches valid function name:
187
        // foo123
187
        // foo123
188
        // _foo_bar
188
        // _foo_bar
189
        $this->_func_regexp = '[a-zA-Z_]\w*';
189
        $this->_func_regexp = '[a-zA-Z_]\w*';
190
190
191
        // matches valid registered object:
191
        // matches valid registered object:
192
        // foo->bar
192
        // foo->bar
193
        $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
193
        $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
194
194
195
        // matches valid parameter values:
195
        // matches valid parameter values:
196
        // true
196
        // true
197
        // $foo
197
        // $foo
198
        // $foo|bar
198
        // $foo|bar
199
        // #foo#
199
        // #foo#
200
        // #foo#|bar
200
        // #foo#|bar
201
        // "text"
201
        // "text"
202
        // "text"|bar
202
        // "text"|bar
203
        // $foo->bar
203
        // $foo->bar
204
        $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
204
        $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
205
           . $this->_var_regexp . '|' . $this->_num_const_regexp  . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
205
           . $this->_var_regexp . '|' . $this->_num_const_regexp  . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
206
206
207
        // matches valid parenthesised function parameters:
207
        // matches valid parenthesised function parameters:
208
        //
208
        //
209
        // "text"
209
        // "text"
210
        //    $foo, $bar, "text"
210
        //    $foo, $bar, "text"
211
        // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
211
        // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
212
        $this->_parenth_param_regexp = '(?:\((?:\w+|'
212
        $this->_parenth_param_regexp = '(?:\((?:\w+|'
213
                . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
213
                . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
214
                . $this->_param_regexp . ')))*)?\))';
214
                . $this->_param_regexp . ')))*)?\))';
215
215
216
        // matches valid function call:
216
        // matches valid function call:
217
        // foo()
217
        // foo()
218
        // foo_bar($foo)
218
        // foo_bar($foo)
219
        // _foo_bar($foo,"bar")
219
        // _foo_bar($foo,"bar")
220
        // foo123($foo,$foo->bar(),"foo")
220
        // foo123($foo,$foo->bar(),"foo")
221
        $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
221
        $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
222
           . $this->_parenth_param_regexp . '))';
222
           . $this->_parenth_param_regexp . '))';
223
    }
223
    }
224
224
225
    /**
225
    /**
226
     * compile a resource
226
     * compile a resource
227
     *
227
     *
228
     * sets $compiled_content to the compiled source
228
     * sets $compiled_content to the compiled source
229
     * @param string $resource_name
229
     * @param string $resource_name
230
     * @param string $source_content
230
     * @param string $source_content
231
     * @param string $compiled_content
231
     * @param string $compiled_content
232
     * @return true
232
     * @return true
233
     */
233
     */
234
    function _compile_file($resource_name, $source_content, &$compiled_content)
234
    function _compile_file($resource_name, $source_content, &$compiled_content)
235
    {
235
    {
236
236
237
        if ($this->security) {
237
        if ($this->security) {
238
            // do not allow php syntax to be executed unless specified
238
            // do not allow php syntax to be executed unless specified
239
            if ($this->php_handling == SMARTY_PHP_ALLOW &&
239
            if ($this->php_handling == SMARTY_PHP_ALLOW &&
240
                !$this->security_settings['PHP_HANDLING']) {
240
                !$this->security_settings['PHP_HANDLING']) {
241
                $this->php_handling = SMARTY_PHP_PASSTHRU;
241
                $this->php_handling = SMARTY_PHP_PASSTHRU;
242
            }
242
            }
243
        }
243
        }
244
244
245
        $this->_load_filters();
245
        $this->_load_filters();
246
246
247
        $this->_current_file = $resource_name;
247
        $this->_current_file = $resource_name;
248
        $this->_current_line_no = 1;
248
        $this->_current_line_no = 1;
249
        $ldq = preg_quote($this->left_delimiter, '~');
249
        $ldq = preg_quote($this->left_delimiter, '~');
250
        $rdq = preg_quote($this->right_delimiter, '~');
250
        $rdq = preg_quote($this->right_delimiter, '~');
251
251
252
        // run template source through prefilter functions
252
        // run template source through prefilter functions
253
        if (count($this->_plugins['prefilter']) > 0) {
253
        if (count($this->_plugins['prefilter']) > 0) {
254
            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
254
            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
255
                if ($prefilter === false) continue;
255
                if ($prefilter === false) continue;
256
                if ($prefilter[3] || is_callable($prefilter[0])) {
256
                if ($prefilter[3] || is_callable($prefilter[0])) {
257
                    $source_content = call_user_func_array($prefilter[0],
257
                    $source_content = call_user_func_array($prefilter[0],
258
                                                            array($source_content, &$this));
258
                                                            array($source_content, &$this));
259
                    $this->_plugins['prefilter'][$filter_name][3] = true;
259
                    $this->_plugins['prefilter'][$filter_name][3] = true;
260
                } else {
260
                } else {
261
                    $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
261
                    $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
262
                }
262
                }
263
            }
263
            }
264
        }
264
        }
265
265
266
        /* fetch all special blocks */
266
        /* fetch all special blocks */
267
        $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
267
        $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
268
268
269
        preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);
269
        preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);
270
        $this->_folded_blocks = $match;
270
        $this->_folded_blocks = $match;
271
        reset($this->_folded_blocks);
271
        reset($this->_folded_blocks);
272
272
273
        /* replace special blocks by "{php}" */
273
        /* replace special blocks by "{php}" */
274
        $source_content = preg_replace($search.'e', "'"
274
        $source_content = preg_replace($search.'e', "'"
275
                                       . $this->_quote_replace($this->left_delimiter) . 'php'
275
                                       . $this->_quote_replace($this->left_delimiter) . 'php'
276
                                       . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
276
                                       . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
277
                                       . $this->_quote_replace($this->right_delimiter)
277
                                       . $this->_quote_replace($this->right_delimiter)
278
                                       . "'"
278
                                       . "'"
279
                                       , $source_content);
279
                                       , $source_content);
280
280
281
        /* Gather all template tags. */
281
        /* Gather all template tags. */
282
        preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
282
        preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
283
        $template_tags = $_match[1];
283
        $template_tags = $_match[1];
284
        /* Split content by template tags to obtain non-template content. */
284
        /* Split content by template tags to obtain non-template content. */
285
        $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
285
        $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
286
286
287
        /* loop through text blocks */
287
        /* loop through text blocks */
288
        for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
288
        for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
289
            /* match anything resembling php tags */
289
            /* match anything resembling php tags */
290
            if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
290
            if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
291
                /* replace tags with placeholders to prevent recursive replacements */
291
                /* replace tags with placeholders to prevent recursive replacements */
292
                $sp_match[1] = array_unique($sp_match[1]);
292
                $sp_match[1] = array_unique($sp_match[1]);
293
                usort($sp_match[1], '_smarty_sort_length');
293
                usort($sp_match[1], '_smarty_sort_length');
294
                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
294
                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
295
                    $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
295
                    $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
296
                }
296
                }
297
                /* process each one */
297
                /* process each one */
298
                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
298
                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
299
                    if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
299
                    if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
300
                        /* echo php contents */
300
                        /* echo php contents */
301
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
301
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
302
                    } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
302
                    } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
303
                        /* quote php tags */
303
                        /* quote php tags */
304
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
304
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
305
                    } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
305
                    } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
306
                        /* remove php tags */
306
                        /* remove php tags */
307
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
307
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
308
                    } else {
308
                    } else {
309
                        /* SMARTY_PHP_ALLOW, but echo non php starting tags */
309
                        /* SMARTY_PHP_ALLOW, but echo non php starting tags */
310
                        $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
310
                        $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
311
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
311
                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
312
                    }
312
                    }
313
                }
313
                }
314
            }
314
            }
315
        }
315
        }
316
       
316
       
317
        /* Compile the template tags into PHP code. */
317
        /* Compile the template tags into PHP code. */
318
        $compiled_tags = array();
318
        $compiled_tags = array();
319
        for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
319
        for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
320
            $this->_current_line_no += substr_count($text_blocks[$i], "\n");
320
            $this->_current_line_no += substr_count($text_blocks[$i], "\n");
321
            $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
321
            $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
322
            $this->_current_line_no += substr_count($template_tags[$i], "\n");
322
            $this->_current_line_no += substr_count($template_tags[$i], "\n");
323
        }
323
        }
324
        if (count($this->_tag_stack)>0) {
324
        if (count($this->_tag_stack)>0) {
325
            list($_open_tag, $_line_no) = end($this->_tag_stack);
325
            list($_open_tag, $_line_no) = end($this->_tag_stack);
326
            $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
326
            $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
327
            return;
327
            return;
328
        }
328
        }
329
329
330
        /* Reformat $text_blocks between 'strip' and '/strip' tags,
330
        /* Reformat $text_blocks between 'strip' and '/strip' tags,
331
           removing spaces, tabs and newlines. */
331
           removing spaces, tabs and newlines. */
332
        $strip = false;
332
        $strip = false;
333
        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
333
        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
334
            if ($compiled_tags[$i] == '{strip}') {
334
            if ($compiled_tags[$i] == '{strip}') {
335
                $compiled_tags[$i] = '';
335
                $compiled_tags[$i] = '';
336
                $strip = true;
336
                $strip = true;
337
                /* remove leading whitespaces */
337
                /* remove leading whitespaces */
338
                $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
338
                $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
339
            }
339
            }
340
            if ($strip) {
340
            if ($strip) {
341
                /* strip all $text_blocks before the next '/strip' */
341
                /* strip all $text_blocks before the next '/strip' */
342
                for ($j = $i + 1; $j < $for_max; $j++) {
342
                for ($j = $i + 1; $j < $for_max; $j++) {
343
                    /* remove leading and trailing whitespaces of each line */
343
                    /* remove leading and trailing whitespaces of each line */
344
                    $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
344
                    $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
345
                    if ($compiled_tags[$j] == '{/strip}') {                      
345
                    if ($compiled_tags[$j] == '{/strip}') {                      
346
                        /* remove trailing whitespaces from the last text_block */
346
                        /* remove trailing whitespaces from the last text_block */
347
                        $text_blocks[$j] = rtrim($text_blocks[$j]);
347
                        $text_blocks[$j] = rtrim($text_blocks[$j]);
348
                    }
348
                    }
349
                    $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
349
                    $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
350
                    if ($compiled_tags[$j] == '{/strip}') {
350
                    if ($compiled_tags[$j] == '{/strip}') {
351
                        $compiled_tags[$j] = "\n"; /* slurped by php, but necessary
351
                        $compiled_tags[$j] = "\n"; /* slurped by php, but necessary
352
                                    if a newline is following the closing strip-tag */
352
                                    if a newline is following the closing strip-tag */
353
                        $strip = false;
353
                        $strip = false;
354
                        $i = $j;
354
                        $i = $j;
355
                        break;
355
                        break;
356
                    }
356
                    }
357
                }
357
                }
358
            }
358
            }
359
        }
359
        }
360
        $compiled_content = '';
360
        $compiled_content = '';
361
       
361
       
362
        $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%';
362
        $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%';
363
       
363
       
364
        /* Interleave the compiled contents and text blocks to get the final result. */
364
        /* Interleave the compiled contents and text blocks to get the final result. */
365
        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
365
        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
366
            if ($compiled_tags[$i] == '') {
366
            if ($compiled_tags[$i] == '') {
367
                // tag result empty, remove first newline from following text block
367
                // tag result empty, remove first newline from following text block
368
                $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
368
                $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
369
            }
369
            }
370
            // replace legit PHP tags with placeholder
370
            // replace legit PHP tags with placeholder
371
            $text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]);
371
            $text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]);
372
            $compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]);
372
            $compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]);
373
           
373
           
374
            $compiled_content .= $text_blocks[$i] . $compiled_tags[$i];
374
            $compiled_content .= $text_blocks[$i] . $compiled_tags[$i];
375
        }
375
        }
376
        $compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]);
376
        $compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]);
377
377
378
        // escape php tags created by interleaving
378
        // escape php tags created by interleaving
379
        $compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content);
379
        $compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content);
380
        $compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content);
380
        $compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content);
381
381
382
        // recover legit tags
382
        // recover legit tags
383
        $compiled_content = str_replace($tag_guard, '<?', $compiled_content);
383
        $compiled_content = str_replace($tag_guard, '<?', $compiled_content);
384
       
384
       
385
        // remove \n from the end of the file, if any
385
        // remove \n from the end of the file, if any
386
        if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) {
386
        if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) {
387
            $compiled_content = substr($compiled_content, 0, -1);
387
            $compiled_content = substr($compiled_content, 0, -1);
388
        }
388
        }
389
389
390
        if (!empty($this->_cache_serial)) {
390
        if (!empty($this->_cache_serial)) {
391
            $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
391
            $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
392
        }
392
        }
393
393
394
        // run compiled template through postfilter functions
394
        // run compiled template through postfilter functions
395
        if (count($this->_plugins['postfilter']) > 0) {
395
        if (count($this->_plugins['postfilter']) > 0) {
396
            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
396
            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
397
                if ($postfilter === false) continue;
397
                if ($postfilter === false) continue;
398
                if ($postfilter[3] || is_callable($postfilter[0])) {
398
                if ($postfilter[3] || is_callable($postfilter[0])) {
399
                    $compiled_content = call_user_func_array($postfilter[0],
399
                    $compiled_content = call_user_func_array($postfilter[0],
400
                                                              array($compiled_content, &$this));
400
                                                              array($compiled_content, &$this));
401
                    $this->_plugins['postfilter'][$filter_name][3] = true;
401
                    $this->_plugins['postfilter'][$filter_name][3] = true;
402
                } else {
402
                } else {
403
                    $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
403
                    $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
404
                }
404
                }
405
            }
405
            }
406
        }
406
        }
407
407
408
        // put header at the top of the compiled template
408
        // put header at the top of the compiled template
409
        $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
409
        $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
410
        $template_header .= "         compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
410
        $template_header .= "         compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
411
411
412
        /* Emit code to load needed plugins. */
412
        /* Emit code to load needed plugins. */
413
        $this->_plugins_code = '';
413
        $this->_plugins_code = '';
414
        if (count($this->_plugin_info)) {
414
        if (count($this->_plugin_info)) {
415
            $_plugins_params = "array('plugins' => array(";
415
            $_plugins_params = "array('plugins' => array(";
416
            foreach ($this->_plugin_info as $plugin_type => $plugins) {
416
            foreach ($this->_plugin_info as $plugin_type => $plugins) {
417
                foreach ($plugins as $plugin_name => $plugin_info) {
417
                foreach ($plugins as $plugin_name => $plugin_info) {
418
                    $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
418
                    $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
419
                    $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
419
                    $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
420
                }
420
                }
421
            }
421
            }
422
            $_plugins_params .= '))';
422
            $_plugins_params .= '))';
423
            $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
423
            $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
424
            $template_header .= $plugins_code;
424
            $template_header .= $plugins_code;
425
            $this->_plugin_info = array();
425
            $this->_plugin_info = array();
426
            $this->_plugins_code = $plugins_code;
426
            $this->_plugins_code = $plugins_code;
427
        }
427
        }
428
428
429
        if ($this->_init_smarty_vars) {
429
        if ($this->_init_smarty_vars) {
430
            $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
430
            $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
431
            $this->_init_smarty_vars = false;
431
            $this->_init_smarty_vars = false;
432
        }
432
        }
433
433
434
        $compiled_content = $template_header . $compiled_content;
434
        $compiled_content = $template_header . $compiled_content;
435
        return true;
435
        return true;
436
    }
436
    }
437
437
438
    /**
438
    /**
439
     * Compile a template tag
439
     * Compile a template tag
440
     *
440
     *
441
     * @param string $template_tag
441
     * @param string $template_tag
442
     * @return string
442
     * @return string
443
     */
443
     */
444
    function _compile_tag($template_tag)
444
    function _compile_tag($template_tag)
445
    {
445
    {
446
        /* Matched comment. */
446
        /* Matched comment. */
447
        if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*')
447
        if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*')
448
            return '';
448
            return '';
449
       
449
       
450
        /* Split tag into two three parts: command, command modifiers and the arguments. */
450
        /* Split tag into two three parts: command, command modifiers and the arguments. */
451
        if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
451
        if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
452
                . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
452
                . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
453
                      (?:\s+(.*))?$
453
                      (?:\s+(.*))?$
454
                    ~xs', $template_tag, $match)) {
454
                    ~xs', $template_tag, $match)) {
455
            $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
455
            $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
456
        }
456
        }
457
       
457
       
458
        $tag_command = $match[1];
458
        $tag_command = $match[1];
459
        $tag_modifier = isset($match[2]) ? $match[2] : null;
459
        $tag_modifier = isset($match[2]) ? $match[2] : null;
460
        $tag_args = isset($match[3]) ? $match[3] : null;
460
        $tag_args = isset($match[3]) ? $match[3] : null;
461
461
462
        if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
462
        if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
463
            /* tag name is a variable or object */
463
            /* tag name is a variable or object */
464
            $_return = $this->_parse_var_props($tag_command . $tag_modifier);
464
            $_return = $this->_parse_var_props($tag_command . $tag_modifier);
465
            return "<?php echo $_return; ?>" . $this->_additional_newline;
465
            return "<?php echo $_return; ?>" . $this->_additional_newline;
466
        }
466
        }
467
467
468
        /* If the tag name is a registered object, we process it. */
468
        /* If the tag name is a registered object, we process it. */
469
        if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
469
        if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
470
            return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
470
            return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
471
        }
471
        }
472
472
473
        switch ($tag_command) {
473
        switch ($tag_command) {
474
            case 'include':
474
            case 'include':
475
                return $this->_compile_include_tag($tag_args);
475
                return $this->_compile_include_tag($tag_args);
476
476
477
            case 'include_php':
477
            case 'include_php':
478
                return $this->_compile_include_php_tag($tag_args);
478
                return $this->_compile_include_php_tag($tag_args);
479
479
480
            case 'if':
480
            case 'if':
481
                $this->_push_tag('if');
481
                $this->_push_tag('if');
482
                return $this->_compile_if_tag($tag_args);
482
                return $this->_compile_if_tag($tag_args);
483
483
484
            case 'else':
484
            case 'else':
485
                list($_open_tag) = end($this->_tag_stack);
485
                list($_open_tag) = end($this->_tag_stack);
486
                if ($_open_tag != 'if' && $_open_tag != 'elseif')
486
                if ($_open_tag != 'if' && $_open_tag != 'elseif')
487
                    $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
487
                    $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
488
                else
488
                else
489
                    $this->_push_tag('else');
489
                    $this->_push_tag('else');
490
                return '<?php else: ?>';
490
                return '<?php else: ?>';
491
491
492
            case 'elseif':
492
            case 'elseif':
493
                list($_open_tag) = end($this->_tag_stack);
493
                list($_open_tag) = end($this->_tag_stack);
494
                if ($_open_tag != 'if' && $_open_tag != 'elseif')
494
                if ($_open_tag != 'if' && $_open_tag != 'elseif')
495
                    $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
495
                    $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
496
                if ($_open_tag == 'if')
496
                if ($_open_tag == 'if')
497
                    $this->_push_tag('elseif');
497
                    $this->_push_tag('elseif');
498
                return $this->_compile_if_tag($tag_args, true);
498
                return $this->_compile_if_tag($tag_args, true);
499
499
500
            case '/if':
500
            case '/if':
501
                $this->_pop_tag('if');
501
                $this->_pop_tag('if');
502
                return '<?php endif; ?>';
502
                return '<?php endif; ?>';
503
503
504
            case 'capture':
504
            case 'capture':
505
                return $this->_compile_capture_tag(true, $tag_args);
505
                return $this->_compile_capture_tag(true, $tag_args);
506
506
507
            case '/capture':
507
            case '/capture':
508
                return $this->_compile_capture_tag(false);
508
                return $this->_compile_capture_tag(false);
509
509
510
            case 'ldelim':
510
            case 'ldelim':
511
                return $this->left_delimiter;
511
                return $this->left_delimiter;
512
512
513
            case 'rdelim':
513
            case 'rdelim':
514
                return $this->right_delimiter;
514
                return $this->right_delimiter;
515
515
516
            case 'section':
516
            case 'section':
517
                $this->_push_tag('section');
517
                $this->_push_tag('section');
518
                return $this->_compile_section_start($tag_args);
518
                return $this->_compile_section_start($tag_args);
519
519
520
            case 'sectionelse':
520
            case 'sectionelse':
521
                $this->_push_tag('sectionelse');
521
                $this->_push_tag('sectionelse');
522
                return "<?php endfor; else: ?>";
522
                return "<?php endfor; else: ?>";
523
                break;
523
                break;
524
524
525
            case '/section':
525
            case '/section':
526
                $_open_tag = $this->_pop_tag('section');
526
                $_open_tag = $this->_pop_tag('section');
527
                if ($_open_tag == 'sectionelse')
527
                if ($_open_tag == 'sectionelse')
528
                    return "<?php endif; ?>";
528
                    return "<?php endif; ?>";
529
                else
529
                else
530
                    return "<?php endfor; endif; ?>";
530
                    return "<?php endfor; endif; ?>";
531
531
532
            case 'foreach':
532
            case 'foreach':
533
                $this->_push_tag('foreach');
533
                $this->_push_tag('foreach');
534
                return $this->_compile_foreach_start($tag_args);
534
                return $this->_compile_foreach_start($tag_args);
535
                break;
535
                break;
536
536
537
            case 'foreachelse':
537
            case 'foreachelse':
538
                $this->_push_tag('foreachelse');
538
                $this->_push_tag('foreachelse');
539
                return "<?php endforeach; else: ?>";
539
                return "<?php endforeach; else: ?>";
540
540
541
            case '/foreach':
541
            case '/foreach':
542
                $_open_tag = $this->_pop_tag('foreach');
542
                $_open_tag = $this->_pop_tag('foreach');
543
                if ($_open_tag == 'foreachelse')
543
                if ($_open_tag == 'foreachelse')
544
                    return "<?php endif; unset(\$_from); ?>";
544
                    return "<?php endif; unset(\$_from); ?>";
545
                else
545
                else
546
                    return "<?php endforeach; endif; unset(\$_from); ?>";
546
                    return "<?php endforeach; endif; unset(\$_from); ?>";
547
                break;
547
                break;
548
548
549
            case 'strip':
549
            case 'strip':
550
            case '/strip':
550
            case '/strip':
551
                if (substr($tag_command, 0, 1)=='/') {
551
                if (substr($tag_command, 0, 1)=='/') {
552
                    $this->_pop_tag('strip');
552
                    $this->_pop_tag('strip');
553
                    if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
553
                    if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
554
                        $this->_additional_newline = "\n";
554
                        $this->_additional_newline = "\n";
555
                        return '{' . $tag_command . '}';
555
                        return '{' . $tag_command . '}';
556
                    }
556
                    }
557
                } else {
557
                } else {
558
                    $this->_push_tag('strip');
558
                    $this->_push_tag('strip');
559
                    if ($this->_strip_depth++==0) { /* outermost opening {strip} */
559
                    if ($this->_strip_depth++==0) { /* outermost opening {strip} */
560
                        $this->_additional_newline = "";
560
                        $this->_additional_newline = "";
561
                        return '{' . $tag_command . '}';
561
                        return '{' . $tag_command . '}';
562
                    }
562
                    }
563
                }
563
                }
564
                return '';
564
                return '';
565
565
566
            case 'php':
566
            case 'php':
567
                /* handle folded tags replaced by {php} */
567
                /* handle folded tags replaced by {php} */
568
                list(, $block) = each($this->_folded_blocks);
568
                list(, $block) = each($this->_folded_blocks);
569
                $this->_current_line_no += substr_count($block[0], "\n");
569
                $this->_current_line_no += substr_count($block[0], "\n");
570
                /* the number of matched elements in the regexp in _compile_file()
570
                /* the number of matched elements in the regexp in _compile_file()
571
                   determins the type of folded tag that was found */
571
                   determins the type of folded tag that was found */
572
                switch (count($block)) {
572
                switch (count($block)) {
573
                    case 2: /* comment */
573
                    case 2: /* comment */
574
                        return '';
574
                        return '';
575
575
576
                    case 3: /* literal */
576
                    case 3: /* literal */
577
                        return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
577
                        return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
578
578
579
                    case 4: /* php */
579
                    case 4: /* php */
580
                        if ($this->security && !$this->security_settings['PHP_TAGS']) {
580
                        if ($this->security && !$this->security_settings['PHP_TAGS']) {
581
                            $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
581
                            $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
582
                            return;
582
                            return;
583
                        }
583
                        }
584
                        return '<?php ' . $block[3] .' ?>';
584
                        return '<?php ' . $block[3] .' ?>';
585
                }
585
                }
586
                break;
586
                break;
587
587
588
            case 'insert':
588
            case 'insert':
589
                return $this->_compile_insert_tag($tag_args);
589
                return $this->_compile_insert_tag($tag_args);
590
590
591
            default:
591
            default:
592
                if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
592
                if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
593
                    return $output;
593
                    return $output;
594
                } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
594
                } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
595
                    return $output;
595
                    return $output;
596
                } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
596
                } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
597
                    return $output;                    
597
                    return $output;                    
598
                } else {
598
                } else {
599
                    $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
599
                    $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
600
                }
600
                }
601
601
602
        }
602
        }
603
    }
603
    }
604
604
605
605
606
    /**
606
    /**
607
     * compile the custom compiler tag
607
     * compile the custom compiler tag
608
     *
608
     *
609
     * sets $output to the compiled custom compiler tag
609
     * sets $output to the compiled custom compiler tag
610
     * @param string $tag_command
610
     * @param string $tag_command
611
     * @param string $tag_args
611
     * @param string $tag_args
612
     * @param string $output
612
     * @param string $output
613
     * @return boolean
613
     * @return boolean
614
     */
614
     */
615
    function _compile_compiler_tag($tag_command, $tag_args, &$output)
615
    function _compile_compiler_tag($tag_command, $tag_args, &$output)
616
    {
616
    {
617
        $found = false;
617
        $found = false;
618
        $have_function = true;
618
        $have_function = true;
619
619
620
        /*
620
        /*
621
         * First we check if the compiler function has already been registered
621
         * First we check if the compiler function has already been registered
622
         * or loaded from a plugin file.
622
         * or loaded from a plugin file.
623
         */
623
         */
624
        if (isset($this->_plugins['compiler'][$tag_command])) {
624
        if (isset($this->_plugins['compiler'][$tag_command])) {
625
            $found = true;
625
            $found = true;
626
            $plugin_func = $this->_plugins['compiler'][$tag_command][0];
626
            $plugin_func = $this->_plugins['compiler'][$tag_command][0];
627
            if (!is_callable($plugin_func)) {
627
            if (!is_callable($plugin_func)) {
628
                $message = "compiler function '$tag_command' is not implemented";
628
                $message = "compiler function '$tag_command' is not implemented";
629
                $have_function = false;
629
                $have_function = false;
630
            }
630
            }
631
        }
631
        }
632
        /*
632
        /*
633
         * Otherwise we need to load plugin file and look for the function
633
         * Otherwise we need to load plugin file and look for the function
634
         * inside it.
634
         * inside it.
635
         */
635
         */
636
        else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
636
        else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
637
            $found = true;
637
            $found = true;
638
638
639
            include_once $plugin_file;
639
            include_once $plugin_file;
640
640
641
            $plugin_func = 'smarty_compiler_' . $tag_command;
641
            $plugin_func = 'smarty_compiler_' . $tag_command;
642
            if (!is_callable($plugin_func)) {
642
            if (!is_callable($plugin_func)) {
643
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
643
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
644
                $have_function = false;
644
                $have_function = false;
645
            } else {
645
            } else {
646
                $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
646
                $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
647
            }
647
            }
648
        }
648
        }
649
649
650
        /*
650
        /*
651
         * True return value means that we either found a plugin or a
651
         * True return value means that we either found a plugin or a
652
         * dynamically registered function. False means that we didn't and the
652
         * dynamically registered function. False means that we didn't and the
653
         * compiler should now emit code to load custom function plugin for this
653
         * compiler should now emit code to load custom function plugin for this
654
         * tag.
654
         * tag.
655
         */
655
         */
656
        if ($found) {
656
        if ($found) {
657
            if ($have_function) {
657
            if ($have_function) {
658
                $output = call_user_func_array($plugin_func, array($tag_args, &$this));
658
                $output = call_user_func_array($plugin_func, array($tag_args, &$this));
659
                if($output != '') {
659
                if($output != '') {
660
                $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
660
                $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
661
                                   . $output
661
                                   . $output
662
                                   . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
662
                                   . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
663
                }
663
                }
664
            } else {
664
            } else {
665
                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
665
                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
666
            }
666
            }
667
            return true;
667
            return true;
668
        } else {
668
        } else {
669
            return false;
669
            return false;
670
        }
670
        }
671
    }
671
    }
672
672
673
673
674
    /**
674
    /**
675
     * compile block function tag
675
     * compile block function tag
676
     *
676
     *
677
     * sets $output to compiled block function tag
677
     * sets $output to compiled block function tag
678
     * @param string $tag_command
678
     * @param string $tag_command
679
     * @param string $tag_args
679
     * @param string $tag_args
680
     * @param string $tag_modifier
680
     * @param string $tag_modifier
681
     * @param string $output
681
     * @param string $output
682
     * @return boolean
682
     * @return boolean
683
     */
683
     */
684
    function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
684
    function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
685
    {
685
    {
686
        if (substr($tag_command, 0, 1) == '/') {
686
        if (substr($tag_command, 0, 1) == '/') {
687
            $start_tag = false;
687
            $start_tag = false;
688
            $tag_command = substr($tag_command, 1);
688
            $tag_command = substr($tag_command, 1);
689
        } else
689
        } else
690
            $start_tag = true;
690
            $start_tag = true;
691
691
692
        $found = false;
692
        $found = false;
693
        $have_function = true;
693
        $have_function = true;
694
694
695
        /*
695
        /*
696
         * First we check if the block function has already been registered
696
         * First we check if the block function has already been registered
697
         * or loaded from a plugin file.
697
         * or loaded from a plugin file.
698
         */
698
         */
699
        if (isset($this->_plugins['block'][$tag_command])) {
699
        if (isset($this->_plugins['block'][$tag_command])) {
700
            $found = true;
700
            $found = true;
701
            $plugin_func = $this->_plugins['block'][$tag_command][0];
701
            $plugin_func = $this->_plugins['block'][$tag_command][0];
702
            if (!is_callable($plugin_func)) {
702
            if (!is_callable($plugin_func)) {
703
                $message = "block function '$tag_command' is not implemented";
703
                $message = "block function '$tag_command' is not implemented";
704
                $have_function = false;
704
                $have_function = false;
705
            }
705
            }
706
        }
706
        }
707
        /*
707
        /*
708
         * Otherwise we need to load plugin file and look for the function
708
         * Otherwise we need to load plugin file and look for the function
709
         * inside it.
709
         * inside it.
710
         */
710
         */
711
        else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
711
        else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
712
            $found = true;
712
            $found = true;
713
713
714
            include_once $plugin_file;
714
            include_once $plugin_file;
715
715
716
            $plugin_func = 'smarty_block_' . $tag_command;
716
            $plugin_func = 'smarty_block_' . $tag_command;
717
            if (!function_exists($plugin_func)) {
717
            if (!function_exists($plugin_func)) {
718
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
718
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
719
                $have_function = false;
719
                $have_function = false;
720
            } else {
720
            } else {
721
                $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
721
                $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
722
722
723
            }
723
            }
724
        }
724
        }
725
725
726
        if (!$found) {
726
        if (!$found) {
727
            return false;
727
            return false;
728
        } else if (!$have_function) {
728
        } else if (!$have_function) {
729
            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
729
            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
730
            return true;
730
            return true;
731
        }
731
        }
732
732
733
        /*
733
        /*
734
         * Even though we've located the plugin function, compilation
734
         * Even though we've located the plugin function, compilation
735
         * happens only once, so the plugin will still need to be loaded
735
         * happens only once, so the plugin will still need to be loaded
736
         * at runtime for future requests.
736
         * at runtime for future requests.
737
         */
737
         */
738
        $this->_add_plugin('block', $tag_command);
738
        $this->_add_plugin('block', $tag_command);
739
739
740
        if ($start_tag)
740
        if ($start_tag)
741
            $this->_push_tag($tag_command);
741
            $this->_push_tag($tag_command);
742
        else
742
        else
743
            $this->_pop_tag($tag_command);
743
            $this->_pop_tag($tag_command);
744
744
745
        if ($start_tag) {
745
        if ($start_tag) {
746
            $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
746
            $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
747
            $attrs = $this->_parse_attrs($tag_args);
747
            $attrs = $this->_parse_attrs($tag_args);
748
            $_cache_attrs='';
748
            $_cache_attrs='';
749
            $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs);
749
            $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs);
750
            $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
750
            $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
751
            $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);';
751
            $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);';
752
            $output .= 'while ($_block_repeat) { ob_start(); ?>';
752
            $output .= 'while ($_block_repeat) { ob_start(); ?>';
753
        } else {
753
        } else {
754
            $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
754
            $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
755
            $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)';
755
            $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)';
756
            if ($tag_modifier != '') {
756
            if ($tag_modifier != '') {
757
                $this->_parse_modifiers($_out_tag_text, $tag_modifier);
757
                $this->_parse_modifiers($_out_tag_text, $tag_modifier);
758
            }
758
            }
759
            $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } ';
759
            $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } ';
760
            $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
760
            $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
761
        }
761
        }
762
762
763
        return true;
763
        return true;
764
    }
764
    }
765
765
766
766
767
    /**
767
    /**
768
     * compile custom function tag
768
     * compile custom function tag
769
     *
769
     *
770
     * @param string $tag_command
770
     * @param string $tag_command
771
     * @param string $tag_args
771
     * @param string $tag_args
772
     * @param string $tag_modifier
772
     * @param string $tag_modifier
773
     * @return string
773
     * @return string
774
     */
774
     */
775
    function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
775
    function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
776
    {
776
    {
777
        $found = false;
777
        $found = false;
778
        $have_function = true;
778
        $have_function = true;
779
779
780
        /*
780
        /*
781
         * First we check if the custom function has already been registered
781
         * First we check if the custom function has already been registered
782
         * or loaded from a plugin file.
782
         * or loaded from a plugin file.
783
         */
783
         */
784
        if (isset($this->_plugins['function'][$tag_command])) {
784
        if (isset($this->_plugins['function'][$tag_command])) {
785
            $found = true;
785
            $found = true;
786
            $plugin_func = $this->_plugins['function'][$tag_command][0];
786
            $plugin_func = $this->_plugins['function'][$tag_command][0];
787
            if (!is_callable($plugin_func)) {
787
            if (!is_callable($plugin_func)) {
788
                $message = "custom function '$tag_command' is not implemented";
788
                $message = "custom function '$tag_command' is not implemented";
789
                $have_function = false;
789
                $have_function = false;
790
            }
790
            }
791
        }
791
        }
792
        /*
792
        /*
793
         * Otherwise we need to load plugin file and look for the function
793
         * Otherwise we need to load plugin file and look for the function
794
         * inside it.
794
         * inside it.
795
         */
795
         */
796
        else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
796
        else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
797
            $found = true;
797
            $found = true;
798
798
799
            include_once $plugin_file;
799
            include_once $plugin_file;
800
800
801
            $plugin_func = 'smarty_function_' . $tag_command;
801
            $plugin_func = 'smarty_function_' . $tag_command;
802
            if (!function_exists($plugin_func)) {
802
            if (!function_exists($plugin_func)) {
803
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
803
                $message = "plugin function $plugin_func() not found in $plugin_file\n";
804
                $have_function = false;
804
                $have_function = false;
805
            } else {
805
            } else {
806
                $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
806
                $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
807
807
808
            }
808
            }
809
        }
809
        }
810
810
811
        if (!$found) {
811
        if (!$found) {
812
            return false;
812
            return false;
813
        } else if (!$have_function) {
813
        } else if (!$have_function) {
814
            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
814
            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
815
            return true;
815
            return true;
816
        }
816
        }
817
817
818
        /* declare plugin to be loaded on display of the template that
818
        /* declare plugin to be loaded on display of the template that
819
           we compile right now */
819
           we compile right now */
820
        $this->_add_plugin('function', $tag_command);
820
        $this->_add_plugin('function', $tag_command);
821
821
822
        $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
822
        $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
823
        $attrs = $this->_parse_attrs($tag_args);
823
        $attrs = $this->_parse_attrs($tag_args);
824
        $_cache_attrs = '';
824
        $_cache_attrs = '';
825
        $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs);
825
        $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs);
826
826
827
        $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
827
        $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
828
        if($tag_modifier != '') {
828
        if($tag_modifier != '') {
829
            $this->_parse_modifiers($output, $tag_modifier);
829
            $this->_parse_modifiers($output, $tag_modifier);
830
        }
830
        }
831
831
832
        if($output != '') {
832
        if($output != '') {
833
            $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
833
            $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
834
                . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
834
                . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
835
        }
835
        }
836
836
837
        return true;
837
        return true;
838
    }
838
    }
839
839
840
    /**
840
    /**
841
     * compile a registered object tag
841
     * compile a registered object tag
842
     *
842
     *
843
     * @param string $tag_command
843
     * @param string $tag_command
844
     * @param array $attrs
844
     * @param array $attrs
845
     * @param string $tag_modifier
845
     * @param string $tag_modifier
846
     * @return string
846
     * @return string
847
     */
847
     */
848
    function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
848
    function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
849
    {
849
    {
850
        if (substr($tag_command, 0, 1) == '/') {
850
        if (substr($tag_command, 0, 1) == '/') {
851
            $start_tag = false;
851
            $start_tag = false;
852
            $tag_command = substr($tag_command, 1);
852
            $tag_command = substr($tag_command, 1);
853
        } else {
853
        } else {
854
            $start_tag = true;
854
            $start_tag = true;
855
        }
855
        }
856
856
857
        list($object, $obj_comp) = explode('->', $tag_command);
857
        list($object, $obj_comp) = explode('->', $tag_command);
858
858
859
        $arg_list = array();
859
        $arg_list = array();
860
        if(count($attrs)) {
860
        if(count($attrs)) {
861
            $_assign_var = false;
861
            $_assign_var = false;
862
            foreach ($attrs as $arg_name => $arg_value) {
862
            foreach ($attrs as $arg_name => $arg_value) {
863
                if($arg_name == 'assign') {
863
                if($arg_name == 'assign') {
864
                    $_assign_var = $arg_value;
864
                    $_assign_var = $arg_value;
865
                    unset($attrs['assign']);
865
                    unset($attrs['assign']);
866
                    continue;
866
                    continue;
867
                }
867
                }
868
                if (is_bool($arg_value))
868
                if (is_bool($arg_value))
869
                    $arg_value = $arg_value ? 'true' : 'false';
869
                    $arg_value = $arg_value ? 'true' : 'false';
870
                $arg_list[] = "'$arg_name' => $arg_value";
870
                $arg_list[] = "'$arg_name' => $arg_value";
871
            }
871
            }
872
        }
872
        }
873
873
874
        if($this->_reg_objects[$object][2]) {
874
        if($this->_reg_objects[$object][2]) {
875
            // smarty object argument format
875
            // smarty object argument format
876
            $args = "array(".implode(',', (array)$arg_list)."), \$this";
876
            $args = "array(".implode(',', (array)$arg_list)."), \$this";
877
        } else {
877
        } else {
878
            // traditional argument format
878
            // traditional argument format
879
            $args = implode(',', array_values($attrs));
879
            $args = implode(',', array_values($attrs));
880
            if (empty($args)) {
880
            if (empty($args)) {
881
                $args = '';
881
                $args = '';
882
            }
882
            }
883
        }
883
        }
884
884
885
        $prefix = '';
885
        $prefix = '';
886
        $postfix = '';
886
        $postfix = '';
887
        $newline = '';
887
        $newline = '';
888
        if(!is_object($this->_reg_objects[$object][0])) {
888
        if(!is_object($this->_reg_objects[$object][0])) {
889
            $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
889
            $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
890
        } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
890
        } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
891
            $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
891
            $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
892
        } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
892
        } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
893
            // method
893
            // method
894
            if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
894
            if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
895
                // block method
895
                // block method
896
                if ($start_tag) {
896
                if ($start_tag) {
897
                    $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
897
                    $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
898
                    $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); ";
898
                    $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); ";
899
                    $prefix .= "while (\$_block_repeat) { ob_start();";
899
                    $prefix .= "while (\$_block_repeat) { ob_start();";
900
                    $return = null;
900
                    $return = null;
901
                    $postfix = '';
901
                    $postfix = '';
902
                } else {
902
                } else {
903
                    $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;";
903
                    $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;";
904
                    $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)";
904
                    $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)";
905
                    $postfix = "} array_pop(\$this->_tag_stack);";
905
                    $postfix = "} array_pop(\$this->_tag_stack);";
906
                }
906
                }
907
            } else {
907
            } else {
908
                // non-block method
908
                // non-block method
909
                $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
909
                $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
910
            }
910
            }
911
        } else {
911
        } else {
912
            // property
912
            // property
913
            $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
913
            $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
914
        }
914
        }
915
915
916
        if($return != null) {
916
        if($return != null) {
917
            if($tag_modifier != '') {
917
            if($tag_modifier != '') {
918
                $this->_parse_modifiers($return, $tag_modifier);
918
                $this->_parse_modifiers($return, $tag_modifier);
919
            }
919
            }
920
920
921
            if(!empty($_assign_var)) {
921
            if(!empty($_assign_var)) {
922
                $output = "\$this->assign('" . $this->_dequote($_assign_var) ."',  $return);";
922
                $output = "\$this->assign('" . $this->_dequote($_assign_var) ."',  $return);";
923
            } else {
923
            } else {
924
                $output = 'echo ' . $return . ';';
924
                $output = 'echo ' . $return . ';';
925
                $newline = $this->_additional_newline;
925
                $newline = $this->_additional_newline;
926
            }
926
            }
927
        } else {
927
        } else {
928
            $output = '';
928
            $output = '';
929
        }
929
        }
930
930
931
        return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
931
        return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
932
    }
932
    }
933
933
934
    /**
934
    /**
935
     * Compile {insert ...} tag
935
     * Compile {insert ...} tag
936
     *
936
     *
937
     * @param string $tag_args
937
     * @param string $tag_args
938
     * @return string
938
     * @return string
939
     */
939
     */
940
    function _compile_insert_tag($tag_args)
940
    function _compile_insert_tag($tag_args)
941
    {
941
    {
942
        $attrs = $this->_parse_attrs($tag_args);
942
        $attrs = $this->_parse_attrs($tag_args);
943
        $name = $this->_dequote($attrs['name']);
943
        $name = $this->_dequote($attrs['name']);
944
944
945
        if (empty($name)) {
945
        if (empty($name)) {
946
            return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
946
            return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
947
        }
947
        }
948
       
948
       
949
        if (!preg_match('~^\w+$~', $name)) {
949
        if (!preg_match('~^\w+$~', $name)) {
950
            return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__);
950
            return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__);
951
        }
951
        }
952
952
953
        if (!empty($attrs['script'])) {
953
        if (!empty($attrs['script'])) {
954
            $delayed_loading = true;
954
            $delayed_loading = true;
955
        } else {
955
        } else {
956
            $delayed_loading = false;
956
            $delayed_loading = false;
957
        }
957
        }
958
958
959
        foreach ($attrs as $arg_name => $arg_value) {
959
        foreach ($attrs as $arg_name => $arg_value) {
960
            if (is_bool($arg_value))
960
            if (is_bool($arg_value))
961
                $arg_value = $arg_value ? 'true' : 'false';
961
                $arg_value = $arg_value ? 'true' : 'false';
962
            $arg_list[] = "'$arg_name' => $arg_value";
962
            $arg_list[] = "'$arg_name' => $arg_value";
963
        }
963
        }
964
964
965
        $this->_add_plugin('insert', $name, $delayed_loading);
965
        $this->_add_plugin('insert', $name, $delayed_loading);
966
966
967
        $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
967
        $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
968
968
969
        return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
969
        return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
970
    }
970
    }
971
971
972
    /**
972
    /**
973
     * Compile {include ...} tag
973
     * Compile {include ...} tag
974
     *
974
     *
975
     * @param string $tag_args
975
     * @param string $tag_args
976
     * @return string
976
     * @return string
977
     */
977
     */
978
    function _compile_include_tag($tag_args)
978
    function _compile_include_tag($tag_args)
979
    {
979
    {
980
        $attrs = $this->_parse_attrs($tag_args);
980
        $attrs = $this->_parse_attrs($tag_args);
981
        $arg_list = array();
981
        $arg_list = array();
982
982
983
        if (empty($attrs['file'])) {
983
        if (empty($attrs['file'])) {
984
            $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
984
            $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
985
        }
985
        }
986
986
987
        foreach ($attrs as $arg_name => $arg_value) {
987
        foreach ($attrs as $arg_name => $arg_value) {
988
            if ($arg_name == 'file') {
988
            if ($arg_name == 'file') {
989
                $include_file = $arg_value;
989
                $include_file = $arg_value;
990
                continue;
990
                continue;
991
            } else if ($arg_name == 'assign') {
991
            } else if ($arg_name == 'assign') {
992
                $assign_var = $arg_value;
992
                $assign_var = $arg_value;
993
                continue;
993
                continue;
994
            }
994
            }
995
            if (is_bool($arg_value))
995
            if (is_bool($arg_value))
996
                $arg_value = $arg_value ? 'true' : 'false';
996
                $arg_value = $arg_value ? 'true' : 'false';
997
            $arg_list[] = "'$arg_name' => $arg_value";
997
            $arg_list[] = "'$arg_name' => $arg_value";
998
        }
998
        }
999
999
1000
        $output = '<?php ';
1000
        $output = '<?php ';
1001
1001
1002
        if (isset($assign_var)) {
1002
        if (isset($assign_var)) {
1003
            $output .= "ob_start();\n";
1003
            $output .= "ob_start();\n";
1004
        }
1004
        }
1005
1005
1006
        $output .=
1006
        $output .=
1007
            "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
1007
            "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
1008
1008
1009
1009
1010
        $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
1010
        $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
1011
        $output .= "\$this->_smarty_include($_params);\n" .
1011
        $output .= "\$this->_smarty_include($_params);\n" .
1012
        "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
1012
        "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
1013
        "unset(\$_smarty_tpl_vars);\n";
1013
        "unset(\$_smarty_tpl_vars);\n";
1014
1014
1015
        if (isset($assign_var)) {
1015
        if (isset($assign_var)) {
1016
            $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
1016
            $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
1017
        }
1017
        }
1018
1018
1019
        $output .= ' ?>';
1019
        $output .= ' ?>';
1020
1020
1021
        return $output;
1021
        return $output;
1022
1022
1023
    }
1023
    }
1024
1024
1025
    /**
1025
    /**
1026
     * Compile {include ...} tag
1026
     * Compile {include ...} tag
1027
     *
1027
     *
1028
     * @param string $tag_args
1028
     * @param string $tag_args
1029
     * @return string
1029
     * @return string
1030
     */
1030
     */
1031
    function _compile_include_php_tag($tag_args)
1031
    function _compile_include_php_tag($tag_args)
1032
    {
1032
    {
1033
        $attrs = $this->_parse_attrs($tag_args);
1033
        $attrs = $this->_parse_attrs($tag_args);
1034
1034
1035
        if (empty($attrs['file'])) {
1035
        if (empty($attrs['file'])) {
1036
            $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
1036
            $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
1037
        }
1037
        }
1038
1038
1039
        $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
1039
        $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
1040
        $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
1040
        $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
1041
1041
1042
        $arg_list = array();
1042
        $arg_list = array();
1043
        foreach($attrs as $arg_name => $arg_value) {
1043
        foreach($attrs as $arg_name => $arg_value) {
1044
            if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
1044
            if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
1045
                if(is_bool($arg_value))
1045
                if(is_bool($arg_value))
1046
                    $arg_value = $arg_value ? 'true' : 'false';
1046
                    $arg_value = $arg_value ? 'true' : 'false';
1047
                $arg_list[] = "'$arg_name' => $arg_value";
1047
                $arg_list[] = "'$arg_name' => $arg_value";
1048
            }
1048
            }
1049
        }
1049
        }
1050
1050
1051
        $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
1051
        $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
1052
1052
1053
        return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
1053
        return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
1054
    }
1054
    }
1055
1055
1056
1056
1057
    /**
1057
    /**
1058
     * Compile {section ...} tag
1058
     * Compile {section ...} tag
1059
     *
1059
     *
1060
     * @param string $tag_args
1060
     * @param string $tag_args
1061
     * @return string
1061
     * @return string
1062
     */
1062
     */
1063
    function _compile_section_start($tag_args)
1063
    function _compile_section_start($tag_args)
1064
    {
1064
    {
1065
        $attrs = $this->_parse_attrs($tag_args);
1065
        $attrs = $this->_parse_attrs($tag_args);
1066
        $arg_list = array();
1066
        $arg_list = array();
1067
1067
1068
        $output = '<?php ';
1068
        $output = '<?php ';
1069
        $section_name = $attrs['name'];
1069
        $section_name = $attrs['name'];
1070
        if (empty($section_name)) {
1070
        if (empty($section_name)) {
1071
            $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
1071
            $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
1072
        }
1072
        }
1073
1073
1074
        $output .= "unset(\$this->_sections[$section_name]);\n";
1074
        $output .= "unset(\$this->_sections[$section_name]);\n";
1075
        $section_props = "\$this->_sections[$section_name]";
1075
        $section_props = "\$this->_sections[$section_name]";
1076
1076
1077
        foreach ($attrs as $attr_name => $attr_value) {
1077
        foreach ($attrs as $attr_name => $attr_value) {
1078
            switch ($attr_name) {
1078
            switch ($attr_name) {
1079
                case 'loop':
1079
                case 'loop':
1080
                    $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
1080
                    $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
1081
                    break;
1081
                    break;
1082
1082
1083
                case 'show':
1083
                case 'show':
1084
                    if (is_bool($attr_value))
1084
                    if (is_bool($attr_value))
1085
                        $show_attr_value = $attr_value ? 'true' : 'false';
1085
                        $show_attr_value = $attr_value ? 'true' : 'false';
1086
                    else
1086
                    else
1087
                        $show_attr_value = "(bool)$attr_value";
1087
                        $show_attr_value = "(bool)$attr_value";
1088
                    $output .= "{$section_props}['show'] = $show_attr_value;\n";
1088
                    $output .= "{$section_props}['show'] = $show_attr_value;\n";
1089
                    break;
1089
                    break;
1090
1090
1091
                case 'name':
1091
                case 'name':
1092
                    $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
1092
                    $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
1093
                    break;
1093
                    break;
1094
1094
1095
                case 'max':
1095
                case 'max':
1096
                case 'start':
1096
                case 'start':
1097
                    $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
1097
                    $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
1098
                    break;
1098
                    break;
1099
1099
1100
                case 'step':
1100
                case 'step':
1101
                    $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
1101
                    $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
1102
                    break;
1102
                    break;
1103
1103
1104
                default:
1104
                default:
1105
                    $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
1105
                    $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
1106
                    break;
1106
                    break;
1107
            }
1107
            }
1108
        }
1108
        }
1109
1109
1110
        if (!isset($attrs['show']))
1110
        if (!isset($attrs['show']))
1111
            $output .= "{$section_props}['show'] = true;\n";
1111
            $output .= "{$section_props}['show'] = true;\n";
1112
1112
1113
        if (!isset($attrs['loop']))
1113
        if (!isset($attrs['loop']))
1114
            $output .= "{$section_props}['loop'] = 1;\n";
1114
            $output .= "{$section_props}['loop'] = 1;\n";
1115
1115
1116
        if (!isset($attrs['max']))
1116
        if (!isset($attrs['max']))
1117
            $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
1117
            $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
1118
        else
1118
        else
1119
            $output .= "if ({$section_props}['max'] < 0)\n" .
1119
            $output .= "if ({$section_props}['max'] < 0)\n" .
1120
                       "    {$section_props}['max'] = {$section_props}['loop'];\n";
1120
                       "    {$section_props}['max'] = {$section_props}['loop'];\n";
1121
1121
1122
        if (!isset($attrs['step']))
1122
        if (!isset($attrs['step']))
1123
            $output .= "{$section_props}['step'] = 1;\n";
1123
            $output .= "{$section_props}['step'] = 1;\n";
1124
1124
1125
        if (!isset($attrs['start']))
1125
        if (!isset($attrs['start']))
1126
            $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
1126
            $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
1127
        else {
1127
        else {
1128
            $output .= "if ({$section_props}['start'] < 0)\n" .
1128
            $output .= "if ({$section_props}['start'] < 0)\n" .
1129
                       "    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
1129
                       "    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
1130
                       "else\n" .
1130
                       "else\n" .
1131
                       "    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
1131
                       "    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
1132
        }
1132
        }
1133
1133
1134
        $output .= "if ({$section_props}['show']) {\n";
1134
        $output .= "if ({$section_props}['show']) {\n";
1135
        if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
1135
        if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
1136
            $output .= "    {$section_props}['total'] = {$section_props}['loop'];\n";
1136
            $output .= "    {$section_props}['total'] = {$section_props}['loop'];\n";
1137
        } else {
1137
        } else {
1138
            $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";
1138
            $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";
1139
        }
1139
        }
1140
        $output .= "    if ({$section_props}['total'] == 0)\n" .
1140
        $output .= "    if ({$section_props}['total'] == 0)\n" .
1141
                   "        {$section_props}['show'] = false;\n" .
1141
                   "        {$section_props}['show'] = false;\n" .
1142
                   "} else\n" .
1142
                   "} else\n" .
1143
                   "    {$section_props}['total'] = 0;\n";
1143
                   "    {$section_props}['total'] = 0;\n";
1144
1144
1145
        $output .= "if ({$section_props}['show']):\n";
1145
        $output .= "if ({$section_props}['show']):\n";
1146
        $output .= "
1146
        $output .= "
1147
            for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
1147
            for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
1148
                 {$section_props}['iteration'] <= {$section_props}['total'];
1148
                 {$section_props}['iteration'] <= {$section_props}['total'];
1149
                 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
1149
                 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
1150
        $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
1150
        $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
1151
        $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
1151
        $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
1152
        $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
1152
        $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
1153
        $output .= "{$section_props}['first']      = ({$section_props}['iteration'] == 1);\n";
1153
        $output .= "{$section_props}['first']      = ({$section_props}['iteration'] == 1);\n";
1154
        $output .= "{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\n";
1154
        $output .= "{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\n";
1155
1155
1156
        $output .= "?>";
1156
        $output .= "?>";
1157
1157
1158
        return $output;
1158
        return $output;
1159
    }
1159
    }
1160
1160
1161
1161
1162
    /**
1162
    /**
1163
     * Compile {foreach ...} tag.
1163
     * Compile {foreach ...} tag.
1164
     *
1164
     *
1165
     * @param string $tag_args
1165
     * @param string $tag_args
1166
     * @return string
1166
     * @return string
1167
     */
1167
     */
1168
    function _compile_foreach_start($tag_args)
1168
    function _compile_foreach_start($tag_args)
1169
    {
1169
    {
1170
        $attrs = $this->_parse_attrs($tag_args);
1170
        $attrs = $this->_parse_attrs($tag_args);
1171
        $arg_list = array();
1171
        $arg_list = array();
1172
1172
1173
        if (empty($attrs['from'])) {
1173
        if (empty($attrs['from'])) {
1174
            return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
1174
            return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
1175
        }
1175
        }
1176
        $from = $attrs['from'];
1176
        $from = $attrs['from'];
1177
1177
1178
        if (empty($attrs['item'])) {
1178
        if (empty($attrs['item'])) {
1179
            return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
1179
            return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
1180
        }
1180
        }
1181
        $item = $this->_dequote($attrs['item']);
1181
        $item = $this->_dequote($attrs['item']);
1182
        if (!preg_match('~^\w+$~', $item)) {
1182
        if (!preg_match('~^\w+$~', $item)) {
1183
            return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1183
            return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1184
        }
1184
        }
1185
1185
1186
        if (isset($attrs['key'])) {
1186
        if (isset($attrs['key'])) {
1187
            $key  = $this->_dequote($attrs['key']);
1187
            $key  = $this->_dequote($attrs['key']);
1188
            if (!preg_match('~^\w+$~', $key)) {
1188
            if (!preg_match('~^\w+$~', $key)) {
1189
                return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1189
                return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
1190
            }
1190
            }
1191
            $key_part = "\$this->_tpl_vars['$key'] => ";
1191
            $key_part = "\$this->_tpl_vars['$key'] => ";
1192
        } else {
1192
        } else {
1193
            $key = null;
1193
            $key = null;
1194
            $key_part = '';
1194
            $key_part = '';
1195
        }
1195
        }
1196
1196
1197
        if (isset($attrs['name'])) {
1197
        if (isset($attrs['name'])) {
1198
            $name = $attrs['name'];
1198
            $name = $attrs['name'];
1199
        } else {
1199
        } else {
1200
            $name = null;
1200
            $name = null;
1201
        }
1201
        }
1202
1202
1203
        $output = '<?php ';
1203
        $output = '<?php ';
1204
        $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
1204
        $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
1205
        if (isset($name)) {
1205
        if (isset($name)) {
1206
            $foreach_props = "\$this->_foreach[$name]";
1206
            $foreach_props = "\$this->_foreach[$name]";
1207
            $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
1207
            $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
1208
            $output .= "if ({$foreach_props}['total'] > 0):\n";
1208
            $output .= "if ({$foreach_props}['total'] > 0):\n";
1209
            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1209
            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1210
            $output .= "        {$foreach_props}['iteration']++;\n";
1210
            $output .= "        {$foreach_props}['iteration']++;\n";
1211
        } else {
1211
        } else {
1212
            $output .= "if (count(\$_from)):\n";
1212
            $output .= "if (count(\$_from)):\n";
1213
            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1213
            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1214
        }
1214
        }
1215
        $output .= '?>';
1215
        $output .= '?>';
1216
1216
1217
        return $output;
1217
        return $output;
1218
    }
1218
    }
1219
1219
1220
1220
1221
    /**
1221
    /**
1222
     * Compile {capture} .. {/capture} tags
1222
     * Compile {capture} .. {/capture} tags
1223
     *
1223
     *
1224
     * @param boolean $start true if this is the {capture} tag
1224
     * @param boolean $start true if this is the {capture} tag
1225
     * @param string $tag_args
1225
     * @param string $tag_args
1226
     * @return string
1226
     * @return string
1227
     */
1227
     */
1228
1228
1229
    function _compile_capture_tag($start, $tag_args = '')
1229
    function _compile_capture_tag($start, $tag_args = '')
1230
    {
1230
    {
1231
        $attrs = $this->_parse_attrs($tag_args);
1231
        $attrs = $this->_parse_attrs($tag_args);
1232
1232
1233
        if ($start) {
1233
        if ($start) {
1234
            $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'";
1234
            $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'";
1235
            $assign = isset($attrs['assign']) ? $attrs['assign'] : null;
1235
            $assign = isset($attrs['assign']) ? $attrs['assign'] : null;
1236
            $append = isset($attrs['append']) ? $attrs['append'] : null;
1236
            $append = isset($attrs['append']) ? $attrs['append'] : null;
1237
           
1237
           
1238
            $output = "<?php ob_start(); ?>";
1238
            $output = "<?php ob_start(); ?>";
1239
            $this->_capture_stack[] = array($buffer, $assign, $append);
1239
            $this->_capture_stack[] = array($buffer, $assign, $append);
1240
        } else {
1240
        } else {
1241
            list($buffer, $assign, $append) = array_pop($this->_capture_stack);
1241
            list($buffer, $assign, $append) = array_pop($this->_capture_stack);
1242
            $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
1242
            $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
1243
            if (isset($assign)) {
1243
            if (isset($assign)) {
1244
                $output .= " \$this->assign($assign, ob_get_contents());";
1244
                $output .= " \$this->assign($assign, ob_get_contents());";
1245
            }
1245
            }
1246
            if (isset($append)) {
1246
            if (isset($append)) {
1247
                $output .= " \$this->append($append, ob_get_contents());";
1247
                $output .= " \$this->append($append, ob_get_contents());";
1248
            }
1248
            }
1249
            $output .= "ob_end_clean(); ?>";
1249
            $output .= "ob_end_clean(); ?>";
1250
        }
1250
        }
1251
1251
1252
        return $output;
1252
        return $output;
1253
    }
1253
    }
1254
1254
1255
    /**
1255
    /**
1256
     * Compile {if ...} tag
1256
     * Compile {if ...} tag
1257
     *
1257
     *
1258
     * @param string $tag_args
1258
     * @param string $tag_args
1259
     * @param boolean $elseif if true, uses elseif instead of if
1259
     * @param boolean $elseif if true, uses elseif instead of if
1260
     * @return string
1260
     * @return string
1261
     */
1261
     */
1262
    function _compile_if_tag($tag_args, $elseif = false)
1262
    function _compile_if_tag($tag_args, $elseif = false)
1263
    {
1263
    {
1264
1264
1265
        /* Tokenize args for 'if' tag. */
1265
        /* Tokenize args for 'if' tag. */
1266
        preg_match_all('~(?>
1266
        preg_match_all('~(?>
1267
                ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
1267
                ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
1268
                ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string
1268
                ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string
1269
                \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@    | # valid non-word token
1269
                \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@    | # valid non-word token
1270
                \b\w+\b                                                        | # valid word token
1270
                \b\w+\b                                                        | # valid word token
1271
                \S+                                                           # anything else
1271
                \S+                                                           # anything else
1272
                )~x', $tag_args, $match);
1272
                )~x', $tag_args, $match);
1273
1273
1274
        $tokens = $match[0];
1274
        $tokens = $match[0];
1275
1275
1276
        if(empty($tokens)) {
1276
        if(empty($tokens)) {
1277
            $_error_msg = $elseif ? "'elseif'" : "'if'";
1277
            $_error_msg = $elseif ? "'elseif'" : "'if'";
1278
            $_error_msg .= ' statement requires arguments';
1278
            $_error_msg .= ' statement requires arguments';
1279
            $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__);
1279
            $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__);
1280
        }
1280
        }
1281
           
1281
           
1282
               
1282
               
1283
        // make sure we have balanced parenthesis
1283
        // make sure we have balanced parenthesis
1284
        $token_count = array_count_values($tokens);
1284
        $token_count = array_count_values($tokens);
1285
        if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
1285
        if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
1286
            $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
1286
            $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
1287
        }
1287
        }
1288
1288
1289
        $is_arg_stack = array();
1289
        $is_arg_stack = array();
1290
1290
1291
        for ($i = 0; $i < count($tokens); $i++) {
1291
        for ($i = 0; $i < count($tokens); $i++) {
1292
1292
1293
            $token = &$tokens[$i];
1293
            $token = &$tokens[$i];
1294
1294
1295
            switch (strtolower($token)) {
1295
            switch (strtolower($token)) {
1296
                case '!':
1296
                case '!':
1297
                case '%':
1297
                case '%':
1298
                case '!==':
1298
                case '!==':
1299
                case '==':
1299
                case '==':
1300
                case '===':
1300
                case '===':
1301
                case '>':
1301
                case '>':
1302
                case '<':
1302
                case '<':
1303
                case '!=':
1303
                case '!=':
1304
                case '<>':
1304
                case '<>':
1305
                case '<<':
1305
                case '<<':
1306
                case '>>':
1306
                case '>>':
1307
                case '<=':
1307
                case '<=':
1308
                case '>=':
1308
                case '>=':
1309
                case '&&':
1309
                case '&&':
1310
                case '||':
1310
                case '||':
1311
                case '|':
1311
                case '|':
1312
                case '^':
1312
                case '^':
1313
                case '&':
1313
                case '&':
1314
                case '~':
1314
                case '~':
1315
                case ')':
1315
                case ')':
1316
                case ',':
1316
                case ',':
1317
                case '+':
1317
                case '+':
1318
                case '-':
1318
                case '-':
1319
                case '*':
1319
                case '*':
1320
                case '/':
1320
                case '/':
1321
                case '@':
1321
                case '@':
1322
                    break;
1322
                    break;
1323
1323
1324
                case 'eq':
1324
                case 'eq':
1325
                    $token = '==';
1325
                    $token = '==';
1326
                    break;
1326
                    break;
1327
1327
1328
                case 'ne':
1328
                case 'ne':
1329
                case 'neq':
1329
                case 'neq':
1330
                    $token = '!=';
1330
                    $token = '!=';
1331
                    break;
1331
                    break;
1332
1332
1333
                case 'lt':
1333
                case 'lt':
1334
                    $token = '<';
1334
                    $token = '<';
1335
                    break;
1335
                    break;
1336
1336
1337
                case 'le':
1337
                case 'le':
1338
                case 'lte':
1338
                case 'lte':
1339
                    $token = '<=';
1339
                    $token = '<=';
1340
                    break;
1340
                    break;
1341
1341
1342
                case 'gt':
1342
                case 'gt':
1343
                    $token = '>';
1343
                    $token = '>';
1344
                    break;
1344
                    break;
1345
1345
1346
                case 'ge':
1346
                case 'ge':
1347
                case 'gte':
1347
                case 'gte':
1348
                    $token = '>=';
1348
                    $token = '>=';
1349
                    break;
1349
                    break;
1350
1350
1351
                case 'and':
1351
                case 'and':
1352
                    $token = '&&';
1352
                    $token = '&&';
1353
                    break;
1353
                    break;
1354
1354
1355
                case 'or':
1355
                case 'or':
1356
                    $token = '||';
1356
                    $token = '||';
1357
                    break;
1357
                    break;
1358
1358
1359
                case 'not':
1359
                case 'not':
1360
                    $token = '!';
1360
                    $token = '!';
1361
                    break;
1361
                    break;
1362
1362
1363
                case 'mod':
1363
                case 'mod':
1364
                    $token = '%';
1364
                    $token = '%';
1365
                    break;
1365
                    break;
1366
1366
1367
                case '(':
1367
                case '(':
1368
                    array_push($is_arg_stack, $i);
1368
                    array_push($is_arg_stack, $i);
1369
                    break;
1369
                    break;
1370
1370
1371
                case 'is':
1371
                case 'is':
1372
                    /* If last token was a ')', we operate on the parenthesized
1372
                    /* If last token was a ')', we operate on the parenthesized
1373
                       expression. The start of the expression is on the stack.
1373
                       expression. The start of the expression is on the stack.
1374
                       Otherwise, we operate on the last encountered token. */
1374
                       Otherwise, we operate on the last encountered token. */
1375
                    if ($tokens[$i-1] == ')') {
1375
                    if ($tokens[$i-1] == ')') {
1376
                        $is_arg_start = array_pop($is_arg_stack);
1376
                        $is_arg_start = array_pop($is_arg_stack);
1377
                        if ($is_arg_start != 0) {
1377
                        if ($is_arg_start != 0) {
1378
                            if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) {
1378
                            if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) {
1379
                                $is_arg_start--;
1379
                                $is_arg_start--;
1380
                            }
1380
                            }
1381
                        }
1381
                        }
1382
                    } else
1382
                    } else
1383
                        $is_arg_start = $i-1;
1383
                        $is_arg_start = $i-1;
1384
                    /* Construct the argument for 'is' expression, so it knows
1384
                    /* Construct the argument for 'is' expression, so it knows
1385
                       what to operate on. */
1385
                       what to operate on. */
1386
                    $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
1386
                    $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
1387
1387
1388
                    /* Pass all tokens from next one until the end to the
1388
                    /* Pass all tokens from next one until the end to the
1389
                       'is' expression parsing function. The function will
1389
                       'is' expression parsing function. The function will
1390
                       return modified tokens, where the first one is the result
1390
                       return modified tokens, where the first one is the result
1391
                       of the 'is' expression and the rest are the tokens it
1391
                       of the 'is' expression and the rest are the tokens it
1392
                       didn't touch. */
1392
                       didn't touch. */
1393
                    $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
1393
                    $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
1394
1394
1395
                    /* Replace the old tokens with the new ones. */
1395
                    /* Replace the old tokens with the new ones. */
1396
                    array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
1396
                    array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
1397
1397
1398
                    /* Adjust argument start so that it won't change from the
1398
                    /* Adjust argument start so that it won't change from the
1399
                       current position for the next iteration. */
1399
                       current position for the next iteration. */
1400
                    $i = $is_arg_start;
1400
                    $i = $is_arg_start;
1401
                    break;
1401
                    break;
1402
1402
1403
                default:
1403
                default:
1404
                    if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
1404
                    if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
1405
                            // function call
1405
                            // function call
1406
                            if($this->security &&
1406
                            if($this->security &&
1407
                               !in_array($token, $this->security_settings['IF_FUNCS'])) {
1407
                               !in_array($token, $this->security_settings['IF_FUNCS'])) {
1408
                                $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
1408
                                $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
1409
                            }
1409
                            }
1410
                    } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {
1410
                    } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {
1411
                        // variable function call
1411
                        // variable function call
1412
                        $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);                      
1412
                        $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);                      
1413
                    } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
1413
                    } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
1414
                        // object or variable
1414
                        // object or variable
1415
                        $token = $this->_parse_var_props($token);
1415
                        $token = $this->_parse_var_props($token);
1416
                    } elseif(is_numeric($token)) {
1416
                    } elseif(is_numeric($token)) {
1417
                        // number, skip it
1417
                        // number, skip it
1418
                    } else {
1418
                    } else {
1419
                        $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
1419
                        $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
1420
                    }
1420
                    }
1421
                    break;
1421
                    break;
1422
            }
1422
            }
1423
        }
1423
        }
1424
1424
1425
        if ($elseif)
1425
        if ($elseif)
1426
            return '<?php elseif ('.implode(' ', $tokens).'): ?>';
1426
            return '<?php elseif ('.implode(' ', $tokens).'): ?>';
1427
        else
1427
        else
1428
            return '<?php if ('.implode(' ', $tokens).'): ?>';
1428
            return '<?php if ('.implode(' ', $tokens).'): ?>';
1429
    }
1429
    }
1430
1430
1431
1431
1432
    function _compile_arg_list($type, $name, $attrs, &$cache_code) {
1432
    function _compile_arg_list($type, $name, $attrs, &$cache_code) {
1433
        $arg_list = array();
1433
        $arg_list = array();
1434
1434
1435
        if (isset($type) && isset($name)
1435
        if (isset($type) && isset($name)
1436
            && isset($this->_plugins[$type])
1436
            && isset($this->_plugins[$type])
1437
            && isset($this->_plugins[$type][$name])
1437
            && isset($this->_plugins[$type][$name])
1438
            && empty($this->_plugins[$type][$name][4])
1438
            && empty($this->_plugins[$type][$name][4])
1439
            && is_array($this->_plugins[$type][$name][5])
1439
            && is_array($this->_plugins[$type][$name][5])
1440
            ) {
1440
            ) {
1441
            /* we have a list of parameters that should be cached */
1441
            /* we have a list of parameters that should be cached */
1442
            $_cache_attrs = $this->_plugins[$type][$name][5];
1442
            $_cache_attrs = $this->_plugins[$type][$name][5];
1443
            $_count = $this->_cache_attrs_count++;
1443
            $_count = $this->_cache_attrs_count++;
1444
            $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
1444
            $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
1445
1445
1446
        } else {
1446
        } else {
1447
            /* no parameters are cached */
1447
            /* no parameters are cached */
1448
            $_cache_attrs = null;
1448
            $_cache_attrs = null;
1449
        }
1449
        }
1450
1450
1451
        foreach ($attrs as $arg_name => $arg_value) {
1451
        foreach ($attrs as $arg_name => $arg_value) {
1452
            if (is_bool($arg_value))
1452
            if (is_bool($arg_value))
1453
                $arg_value = $arg_value ? 'true' : 'false';
1453
                $arg_value = $arg_value ? 'true' : 'false';
1454
            if (is_null($arg_value))
1454
            if (is_null($arg_value))
1455
                $arg_value = 'null';
1455
                $arg_value = 'null';
1456
            if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
1456
            if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
1457
                $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
1457
                $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
1458
            } else {
1458
            } else {
1459
                $arg_list[] = "'$arg_name' => $arg_value";
1459
                $arg_list[] = "'$arg_name' => $arg_value";
1460
            }
1460
            }
1461
        }
1461
        }
1462
        return $arg_list;
1462
        return $arg_list;
1463
    }
1463
    }
1464
1464
1465
    /**
1465
    /**
1466
     * Parse is expression
1466
     * Parse is expression
1467
     *
1467
     *
1468
     * @param string $is_arg
1468
     * @param string $is_arg
1469
     * @param array $tokens
1469
     * @param array $tokens
1470
     * @return array
1470
     * @return array
1471
     */
1471
     */
1472
    function _parse_is_expr($is_arg, $tokens)
1472
    function _parse_is_expr($is_arg, $tokens)
1473
    {
1473
    {
1474
        $expr_end = 0;
1474
        $expr_end = 0;
1475
        $negate_expr = false;
1475
        $negate_expr = false;
1476
1476
1477
        if (($first_token = array_shift($tokens)) == 'not') {
1477
        if (($first_token = array_shift($tokens)) == 'not') {
1478
            $negate_expr = true;
1478
            $negate_expr = true;
1479
            $expr_type = array_shift($tokens);
1479
            $expr_type = array_shift($tokens);
1480
        } else
1480
        } else
1481
            $expr_type = $first_token;
1481
            $expr_type = $first_token;
1482
1482
1483
        switch ($expr_type) {
1483
        switch ($expr_type) {
1484
            case 'even':
1484
            case 'even':
1485
                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1485
                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1486
                    $expr_end++;
1486
                    $expr_end++;
1487
                    $expr_arg = $tokens[$expr_end++];
1487
                    $expr_arg = $tokens[$expr_end++];
1488
                    $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1488
                    $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1489
                } else
1489
                } else
1490
                    $expr = "!(1 & $is_arg)";
1490
                    $expr = "!(1 & $is_arg)";
1491
                break;
1491
                break;
1492
1492
1493
            case 'odd':
1493
            case 'odd':
1494
                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1494
                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1495
                    $expr_end++;
1495
                    $expr_end++;
1496
                    $expr_arg = $tokens[$expr_end++];
1496
                    $expr_arg = $tokens[$expr_end++];
1497
                    $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1497
                    $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1498
                } else
1498
                } else
1499
                    $expr = "(1 & $is_arg)";
1499
                    $expr = "(1 & $is_arg)";
1500
                break;
1500
                break;
1501
1501
1502
            case 'div':
1502
            case 'div':
1503
                if (@$tokens[$expr_end] == 'by') {
1503
                if (@$tokens[$expr_end] == 'by') {
1504
                    $expr_end++;
1504
                    $expr_end++;
1505
                    $expr_arg = $tokens[$expr_end++];
1505
                    $expr_arg = $tokens[$expr_end++];
1506
                    $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
1506
                    $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
1507
                } else {
1507
                } else {
1508
                    $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
1508
                    $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
1509
                }
1509
                }
1510
                break;
1510
                break;
1511
1511
1512
            default:
1512
            default:
1513
                $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
1513
                $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
1514
                break;
1514
                break;
1515
        }
1515
        }
1516
1516
1517
        if ($negate_expr) {
1517
        if ($negate_expr) {
1518
            $expr = "!($expr)";
1518
            $expr = "!($expr)";
1519
        }
1519
        }
1520
1520
1521
        array_splice($tokens, 0, $expr_end, $expr);
1521
        array_splice($tokens, 0, $expr_end, $expr);
1522
1522
1523
        return $tokens;
1523
        return $tokens;
1524
    }
1524
    }
1525
1525
1526
1526
1527
    /**
1527
    /**
1528
     * Parse attribute string
1528
     * Parse attribute string
1529
     *
1529
     *
1530
     * @param string $tag_args
1530
     * @param string $tag_args
1531
     * @return array
1531
     * @return array
1532
     */
1532
     */
1533
    function _parse_attrs($tag_args)
1533
    function _parse_attrs($tag_args)
1534
    {
1534
    {
1535
1535
1536
        /* Tokenize tag attributes. */
1536
        /* Tokenize tag attributes. */
1537
        preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
1537
        preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
1538
                         )+ |
1538
                         )+ |
1539
                         [=]
1539
                         [=]
1540
                        ~x', $tag_args, $match);
1540
                        ~x', $tag_args, $match);
1541
        $tokens       = $match[0];
1541
        $tokens       = $match[0];
1542
1542
1543
        $attrs = array();
1543
        $attrs = array();
1544
        /* Parse state:
1544
        /* Parse state:
1545
            0 - expecting attribute name
1545
            0 - expecting attribute name
1546
            1 - expecting '='
1546
            1 - expecting '='
1547
            2 - expecting attribute value (not '=') */
1547
            2 - expecting attribute value (not '=') */
1548
        $state = 0;
1548
        $state = 0;
1549
1549
1550
        foreach ($tokens as $token) {
1550
        foreach ($tokens as $token) {
1551
            switch ($state) {
1551
            switch ($state) {
1552
                case 0:
1552
                case 0:
1553
                    /* If the token is a valid identifier, we set attribute name
1553
                    /* If the token is a valid identifier, we set attribute name
1554
                       and go to state 1. */
1554
                       and go to state 1. */
1555
                    if (preg_match('~^\w+$~', $token)) {
1555
                    if (preg_match('~^\w+$~', $token)) {
1556
                        $attr_name = $token;
1556
                        $attr_name = $token;
1557
                        $state = 1;
1557
                        $state = 1;
1558
                    } else
1558
                    } else
1559
                        $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
1559
                        $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
1560
                    break;
1560
                    break;
1561
1561
1562
                case 1:
1562
                case 1:
1563
                    /* If the token is '=', then we go to state 2. */
1563
                    /* If the token is '=', then we go to state 2. */
1564
                    if ($token == '=') {
1564
                    if ($token == '=') {
1565
                        $state = 2;
1565
                        $state = 2;
1566
                    } else
1566
                    } else
1567
                        $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1567
                        $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1568
                    break;
1568
                    break;
1569
1569
1570
                case 2:
1570
                case 2:
1571
                    /* If token is not '=', we set the attribute value and go to
1571
                    /* If token is not '=', we set the attribute value and go to
1572
                       state 0. */
1572
                       state 0. */
1573
                    if ($token != '=') {
1573
                    if ($token != '=') {
1574
                        /* We booleanize the token if it's a non-quoted possible
1574
                        /* We booleanize the token if it's a non-quoted possible
1575
                           boolean value. */
1575
                           boolean value. */
1576
                        if (preg_match('~^(on|yes|true)$~', $token)) {
1576
                        if (preg_match('~^(on|yes|true)$~', $token)) {
1577
                            $token = 'true';
1577
                            $token = 'true';
1578
                        } else if (preg_match('~^(off|no|false)$~', $token)) {
1578
                        } else if (preg_match('~^(off|no|false)$~', $token)) {
1579
                            $token = 'false';
1579
                            $token = 'false';
1580
                        } else if ($token == 'null') {
1580
                        } else if ($token == 'null') {
1581
                            $token = 'null';
1581
                            $token = 'null';
1582
                        } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
1582
                        } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
1583
                            /* treat integer literally */
1583
                            /* treat integer literally */
1584
                        } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
1584
                        } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
1585
                            /* treat as a string, double-quote it escaping quotes */
1585
                            /* treat as a string, double-quote it escaping quotes */
1586
                            $token = '"'.addslashes($token).'"';
1586
                            $token = '"'.addslashes($token).'"';
1587
                        }
1587
                        }
1588
1588
1589
                        $attrs[$attr_name] = $token;
1589
                        $attrs[$attr_name] = $token;
1590
                        $state = 0;
1590
                        $state = 0;
1591
                    } else
1591
                    } else
1592
                        $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
1592
                        $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
1593
                    break;
1593
                    break;
1594
            }
1594
            }
1595
            $last_token = $token;
1595
            $last_token = $token;
1596
        }
1596
        }
1597
1597
1598
        if($state != 0) {
1598
        if($state != 0) {
1599
            if($state == 1) {
1599
            if($state == 1) {
1600
                $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1600
                $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1601
            } else {
1601
            } else {
1602
                $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
1602
                $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
1603
            }
1603
            }
1604
        }
1604
        }
1605
1605
1606
        $this->_parse_vars_props($attrs);
1606
        $this->_parse_vars_props($attrs);
1607
1607
1608
        return $attrs;
1608
        return $attrs;
1609
    }
1609
    }
1610
1610
1611
    /**
1611
    /**
1612
     * compile multiple variables and section properties tokens into
1612
     * compile multiple variables and section properties tokens into
1613
     * PHP code
1613
     * PHP code
1614
     *
1614
     *
1615
     * @param array $tokens
1615
     * @param array $tokens
1616
     */
1616
     */
1617
    function _parse_vars_props(&$tokens)
1617
    function _parse_vars_props(&$tokens)
1618
    {
1618
    {
1619
        foreach($tokens as $key => $val) {
1619
        foreach($tokens as $key => $val) {
1620
            $tokens[$key] = $this->_parse_var_props($val);
1620
            $tokens[$key] = $this->_parse_var_props($val);
1621
        }
1621
        }
1622
    }
1622
    }
1623
1623
1624
    /**
1624
    /**
1625
     * compile single variable and section properties token into
1625
     * compile single variable and section properties token into
1626
     * PHP code
1626
     * PHP code
1627
     *
1627
     *
1628
     * @param string $val
1628
     * @param string $val
1629
     * @param string $tag_attrs
1629
     * @param string $tag_attrs
1630
     * @return string
1630
     * @return string
1631
     */
1631
     */
1632
    function _parse_var_props($val)
1632
    function _parse_var_props($val)
1633
    {
1633
    {
1634
        $val = trim($val);
1634
        $val = trim($val);
1635
1635
1636
        if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
1636
        if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
1637
            // $ variable or object
1637
            // $ variable or object
1638
            $return = $this->_parse_var($match[1]);
1638
            $return = $this->_parse_var($match[1]);
1639
            $modifiers = $match[2];
1639
            $modifiers = $match[2];
1640
            if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
1640
            if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
1641
                $_default_mod_string = implode('|',(array)$this->default_modifiers);
1641
                $_default_mod_string = implode('|',(array)$this->default_modifiers);
1642
                $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
1642
                $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
1643
            }
1643
            }
1644
            $this->_parse_modifiers($return, $modifiers);
1644
            $this->_parse_modifiers($return, $modifiers);
1645
            return $return;
1645
            return $return;
1646
        } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1646
        } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1647
                // double quoted text
1647
                // double quoted text
1648
                preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1648
                preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1649
                $return = $this->_expand_quoted_text($match[1]);
1649
                $return = $this->_expand_quoted_text($match[1]);
1650
                if($match[2] != '') {
1650
                if($match[2] != '') {
1651
                    $this->_parse_modifiers($return, $match[2]);
1651
                    $this->_parse_modifiers($return, $match[2]);
1652
                }
1652
                }
1653
                return $return;
1653
                return $return;
1654
            }
1654
            }
1655
        elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1655
        elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1656
                // numerical constant
1656
                // numerical constant
1657
                preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1657
                preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1658
                if($match[2] != '') {
1658
                if($match[2] != '') {
1659
                    $this->_parse_modifiers($match[1], $match[2]);
1659
                    $this->_parse_modifiers($match[1], $match[2]);
1660
                    return $match[1];
1660
                    return $match[1];
1661
                }
1661
                }
1662
            }
1662
            }
1663
        elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1663
        elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1664
                // single quoted text
1664
                // single quoted text
1665
                preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1665
                preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
1666
                if($match[2] != '') {
1666
                if($match[2] != '') {
1667
                    $this->_parse_modifiers($match[1], $match[2]);
1667
                    $this->_parse_modifiers($match[1], $match[2]);
1668
                    return $match[1];
1668
                    return $match[1];
1669
                }
1669
                }
1670
            }
1670
            }
1671
        elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1671
        elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1672
                // config var
1672
                // config var
1673
                return $this->_parse_conf_var($val);
1673
                return $this->_parse_conf_var($val);
1674
            }
1674
            }
1675
        elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1675
        elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
1676
                // section var
1676
                // section var
1677
                return $this->_parse_section_prop($val);
1677
                return $this->_parse_section_prop($val);
1678
            }
1678
            }
1679
        elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
1679
        elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
1680
            // literal string
1680
            // literal string
1681
            return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"');
1681
            return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"');
1682
        }
1682
        }
1683
        return $val;
1683
        return $val;
1684
    }
1684
    }
1685
1685
1686
    /**
1686
    /**
1687
     * expand quoted text with embedded variables
1687
     * expand quoted text with embedded variables
1688
     *
1688
     *
1689
     * @param string $var_expr
1689
     * @param string $var_expr
1690
     * @return string
1690
     * @return string
1691
     */
1691
     */
1692
    function _expand_quoted_text($var_expr)
1692
    function _expand_quoted_text($var_expr)
1693
    {
1693
    {
1694
        // if contains unescaped $, expand it
1694
        // if contains unescaped $, expand it
1695
        if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
1695
        if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
1696
            $_match = $_match[0];
1696
            $_match = $_match[0];
1697
            $_replace = array();
1697
            $_replace = array();
1698
            foreach($_match as $_var) {
1698
            foreach($_match as $_var) {
1699
                $_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."';
1699
                $_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."';
1700
            }
1700
            }
1701
            $var_expr = strtr($var_expr, $_replace);
1701
            $var_expr = strtr($var_expr, $_replace);
1702
            $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
1702
            $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
1703
        } else {
1703
        } else {
1704
            $_return = $var_expr;
1704
            $_return = $var_expr;
1705
        }
1705
        }
1706
        // replace double quoted literal string with single quotes
1706
        // replace double quoted literal string with single quotes
1707
        $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
1707
        $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
1708
        // escape dollar sign if not printing a var
1708
        // escape dollar sign if not printing a var
1709
        $_return = preg_replace('~\$(\W)~',"\\\\\$\\1",$_return);
1709
        $_return = preg_replace('~\$(\W)~',"\\\\\$\\1",$_return);
1710
        return $_return;
1710
        return $_return;
1711
    }
1711
    }
1712
1712
1713
    /**
1713
    /**
1714
     * parse variable expression into PHP code
1714
     * parse variable expression into PHP code
1715
     *
1715
     *
1716
     * @param string $var_expr
1716
     * @param string $var_expr
1717
     * @param string $output
1717
     * @param string $output
1718
     * @return string
1718
     * @return string
1719
     */
1719
     */
1720
    function _parse_var($var_expr)
1720
    function _parse_var($var_expr)
1721
    {
1721
    {
1722
        $_has_math = false;
1722
        $_has_math = false;
1723
        $_has_php4_method_chaining = false;
1723
        $_has_php4_method_chaining = false;
1724
        $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
1724
        $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
1725
1725
1726
        if(count($_math_vars) > 1) {
1726
        if(count($_math_vars) > 1) {
1727
            $_first_var = "";
1727
            $_first_var = "";
1728
            $_complete_var = "";
1728
            $_complete_var = "";
1729
            $_output = "";
1729
            $_output = "";
1730
            // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
1730
            // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
1731
            foreach($_math_vars as $_k => $_math_var) {
1731
            foreach($_math_vars as $_k => $_math_var) {
1732
                $_math_var = $_math_vars[$_k];
1732
                $_math_var = $_math_vars[$_k];
1733
1733
1734
                if(!empty($_math_var) || is_numeric($_math_var)) {
1734
                if(!empty($_math_var) || is_numeric($_math_var)) {
1735
                    // hit a math operator, so process the stuff which came before it
1735
                    // hit a math operator, so process the stuff which came before it
1736
                    if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
1736
                    if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
1737
                        $_has_math = true;
1737
                        $_has_math = true;
1738
                        if(!empty($_complete_var) || is_numeric($_complete_var)) {
1738
                        if(!empty($_complete_var) || is_numeric($_complete_var)) {
1739
                            $_output .= $this->_parse_var($_complete_var);
1739
                            $_output .= $this->_parse_var($_complete_var);
1740
                        }
1740
                        }
1741
1741
1742
                        // just output the math operator to php
1742
                        // just output the math operator to php
1743
                        $_output .= $_math_var;
1743
                        $_output .= $_math_var;
1744
1744
1745
                        if(empty($_first_var))
1745
                        if(empty($_first_var))
1746
                            $_first_var = $_complete_var;
1746
                            $_first_var = $_complete_var;
1747
1747
1748
                        $_complete_var = "";
1748
                        $_complete_var = "";
1749
                    } else {
1749
                    } else {
1750
                        $_complete_var .= $_math_var;
1750
                        $_complete_var .= $_math_var;
1751
                    }
1751
                    }
1752
                }
1752
                }
1753
            }
1753
            }
1754
            if($_has_math) {
1754
            if($_has_math) {
1755
                if(!empty($_complete_var) || is_numeric($_complete_var))
1755
                if(!empty($_complete_var) || is_numeric($_complete_var))
1756
                    $_output .= $this->_parse_var($_complete_var);
1756
                    $_output .= $this->_parse_var($_complete_var);
1757
1757
1758
                // get the modifiers working (only the last var from math + modifier is left)
1758
                // get the modifiers working (only the last var from math + modifier is left)
1759
                $var_expr = $_complete_var;
1759
                $var_expr = $_complete_var;
1760
            }
1760
            }
1761
        }
1761
        }
1762
1762
1763
        // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
1763
        // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
1764
        if(is_numeric(substr($var_expr, 0, 1)))
1764
        if(is_numeric(substr($var_expr, 0, 1)))
1765
            $_var_ref = $var_expr;
1765
            $_var_ref = $var_expr;
1766
        else
1766
        else
1767
            $_var_ref = substr($var_expr, 1);
1767
            $_var_ref = substr($var_expr, 1);
1768
       
1768
       
1769
        if(!$_has_math) {
1769
        if(!$_has_math) {
1770
           
1770
           
1771
            // get [foo] and .foo and ->foo and (...) pieces
1771
            // get [foo] and .foo and ->foo and (...) pieces
1772
            preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
1772
            preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
1773
                       
1773
                       
1774
            $_indexes = $match[0];
1774
            $_indexes = $match[0];
1775
            $_var_name = array_shift($_indexes);
1775
            $_var_name = array_shift($_indexes);
1776
1776
1777
            /* Handle $smarty.* variable references as a special case. */
1777
            /* Handle $smarty.* variable references as a special case. */
1778
            if ($_var_name == 'smarty') {
1778
            if ($_var_name == 'smarty') {
1779
                /*
1779
                /*
1780
                 * If the reference could be compiled, use the compiled output;
1780
                 * If the reference could be compiled, use the compiled output;
1781
                 * otherwise, fall back on the $smarty variable generated at
1781
                 * otherwise, fall back on the $smarty variable generated at
1782
                 * run-time.
1782
                 * run-time.
1783
                 */
1783
                 */
1784
                if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
1784
                if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
1785
                    $_output = $smarty_ref;
1785
                    $_output = $smarty_ref;
1786
                } else {
1786
                } else {
1787
                    $_var_name = substr(array_shift($_indexes), 1);
1787
                    $_var_name = substr(array_shift($_indexes), 1);
1788
                    $_output = "\$this->_smarty_vars['$_var_name']";
1788
                    $_output = "\$this->_smarty_vars['$_var_name']";
1789
                }
1789
                }
1790
            } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) {
1790
            } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) {
1791
                // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
1791
                // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
1792
                if(count($_indexes) > 0)
1792
                if(count($_indexes) > 0)
1793
                {
1793
                {
1794
                    $_var_name .= implode("", $_indexes);
1794
                    $_var_name .= implode("", $_indexes);
1795
                    $_indexes = array();
1795
                    $_indexes = array();
1796
                }
1796
                }
1797
                $_output = $_var_name;
1797
                $_output = $_var_name;
1798
            } else {
1798
            } else {
1799
                $_output = "\$this->_tpl_vars['$_var_name']";
1799
                $_output = "\$this->_tpl_vars['$_var_name']";
1800
            }
1800
            }
1801
1801
1802
            foreach ($_indexes as $_index) {
1802
            foreach ($_indexes as $_index) {
1803
                if (substr($_index, 0, 1) == '[') {
1803
                if (substr($_index, 0, 1) == '[') {
1804
                    $_index = substr($_index, 1, -1);
1804
                    $_index = substr($_index, 1, -1);
1805
                    if (is_numeric($_index)) {
1805
                    if (is_numeric($_index)) {
1806
                        $_output .= "[$_index]";
1806
                        $_output .= "[$_index]";
1807
                    } elseif (substr($_index, 0, 1) == '$') {
1807
                    } elseif (substr($_index, 0, 1) == '$') {
1808
                        if (strpos($_index, '.') !== false) {
1808
                        if (strpos($_index, '.') !== false) {
1809
                            $_output .= '[' . $this->_parse_var($_index) . ']';
1809
                            $_output .= '[' . $this->_parse_var($_index) . ']';
1810
                        } else {
1810
                        } else {
1811
                            $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
1811
                            $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
1812
                        }
1812
                        }
1813
                    } else {
1813
                    } else {
1814
                        $_var_parts = explode('.', $_index);
1814
                        $_var_parts = explode('.', $_index);
1815
                        $_var_section = $_var_parts[0];
1815
                        $_var_section = $_var_parts[0];
1816
                        $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
1816
                        $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
1817
                        $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
1817
                        $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
1818
                    }
1818
                    }
1819
                } else if (substr($_index, 0, 1) == '.') {
1819
                } else if (substr($_index, 0, 1) == '.') {
1820
                    if (substr($_index, 1, 1) == '$')
1820
                    if (substr($_index, 1, 1) == '$')
1821
                        $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
1821
                        $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
1822
                    else
1822
                    else
1823
                        $_output .= "['" . substr($_index, 1) . "']";
1823
                        $_output .= "['" . substr($_index, 1) . "']";
1824
                } else if (substr($_index,0,2) == '->') {
1824
                } else if (substr($_index,0,2) == '->') {
1825
                    if(substr($_index,2,2) == '__') {
1825
                    if(substr($_index,2,2) == '__') {
1826
                        $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1826
                        $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1827
                    } elseif($this->security && substr($_index, 2, 1) == '_') {
1827
                    } elseif($this->security && substr($_index, 2, 1) == '_') {
1828
                        $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1828
                        $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1829
                    } elseif (substr($_index, 2, 1) == '$') {
1829
                    } elseif (substr($_index, 2, 1) == '$') {
1830
                        if ($this->security) {
1830
                        if ($this->security) {
1831
                            $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1831
                            $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1832
                        } else {
1832
                        } else {
1833
                            $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
1833
                            $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
1834
                        }
1834
                        }
1835
                    } else {
1835
                    } else {
1836
                       if ($this->_phpversion < 5) {
1836
                       if ($this->_phpversion < 5) {
1837
                         $_has_php4_method_chaining = true;
1837
                         $_has_php4_method_chaining = true;
1838
                         $_output .= "; \$_foo = \$_foo";
1838
                         $_output .= "; \$_foo = \$_foo";
1839
                       }
1839
                       }
1840
                        $_output .= $_index;
1840
                        $_output .= $_index;
1841
                    }
1841
                    }
1842
                } elseif (substr($_index, 0, 1) == '(') {
1842
                } elseif (substr($_index, 0, 1) == '(') {
1843
                    $_index = $this->_parse_parenth_args($_index);
1843
                    $_index = $this->_parse_parenth_args($_index);
1844
                    $_output .= $_index;
1844
                    $_output .= $_index;
1845
                } else {
1845
                } else {
1846
                    $_output .= $_index;
1846
                    $_output .= $_index;
1847
                }
1847
                }
1848
            }
1848
            }
1849
        }
1849
        }
1850
1850
1851
        if ($_has_php4_method_chaining) {
1851
        if ($_has_php4_method_chaining) {
1852
           $_tmp = str_replace("'","\'",'$_foo = '.$_output.'; return $_foo;');
1852
           $_tmp = str_replace("'","\'",'$_foo = '.$_output.'; return $_foo;');
1853
           return "eval('".$_tmp."')";
1853
           return "eval('".$_tmp."')";
1854
        } else {
1854
        } else {
1855
           return $_output;
1855
           return $_output;
1856
        }
1856
        }
1857
    }
1857
    }
1858
1858
1859
    /**
1859
    /**
1860
     * parse arguments in function call parenthesis
1860
     * parse arguments in function call parenthesis
1861
     *
1861
     *
1862
     * @param string $parenth_args
1862
     * @param string $parenth_args
1863
     * @return string
1863
     * @return string
1864
     */
1864
     */
1865
    function _parse_parenth_args($parenth_args)
1865
    function _parse_parenth_args($parenth_args)
1866
    {
1866
    {
1867
        preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
1867
        preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
1868
        $orig_vals = $match = $match[0];
1868
        $orig_vals = $match = $match[0];
1869
        $this->_parse_vars_props($match);
1869
        $this->_parse_vars_props($match);
1870
        $replace = array();
1870
        $replace = array();
1871
        for ($i = 0, $count = count($match); $i < $count; $i++) {
1871
        for ($i = 0, $count = count($match); $i < $count; $i++) {
1872
            $replace[$orig_vals[$i]] = $match[$i];
1872
            $replace[$orig_vals[$i]] = $match[$i];
1873
        }
1873
        }
1874
        return strtr($parenth_args, $replace);
1874
        return strtr($parenth_args, $replace);
1875
    }
1875
    }
1876
1876
1877
    /**
1877
    /**
1878
     * parse configuration variable expression into PHP code
1878
     * parse configuration variable expression into PHP code
1879
     *
1879
     *
1880
     * @param string $conf_var_expr
1880
     * @param string $conf_var_expr
1881
     */
1881
     */
1882
    function _parse_conf_var($conf_var_expr)
1882
    function _parse_conf_var($conf_var_expr)
1883
    {
1883
    {
1884
        $parts = explode('|', $conf_var_expr, 2);
1884
        $parts = explode('|', $conf_var_expr, 2);
1885
        $var_ref = $parts[0];
1885
        $var_ref = $parts[0];
1886
        $modifiers = isset($parts[1]) ? $parts[1] : '';
1886
        $modifiers = isset($parts[1]) ? $parts[1] : '';
1887
1887
1888
        $var_name = substr($var_ref, 1, -1);
1888
        $var_name = substr($var_ref, 1, -1);
1889
1889
1890
        $output = "\$this->_config[0]['vars']['$var_name']";
1890
        $output = "\$this->_config[0]['vars']['$var_name']";
1891
1891
1892
        $this->_parse_modifiers($output, $modifiers);
1892
        $this->_parse_modifiers($output, $modifiers);
1893
1893
1894
        return $output;
1894
        return $output;
1895
    }
1895
    }
1896
1896
1897
    /**
1897
    /**
1898
     * parse section property expression into PHP code
1898
     * parse section property expression into PHP code
1899
     *
1899
     *
1900
     * @param string $section_prop_expr
1900
     * @param string $section_prop_expr
1901
     * @return string
1901
     * @return string
1902
     */
1902
     */
1903
    function _parse_section_prop($section_prop_expr)
1903
    function _parse_section_prop($section_prop_expr)
1904
    {
1904
    {
1905
        $parts = explode('|', $section_prop_expr, 2);
1905
        $parts = explode('|', $section_prop_expr, 2);
1906
        $var_ref = $parts[0];
1906
        $var_ref = $parts[0];
1907
        $modifiers = isset($parts[1]) ? $parts[1] : '';
1907
        $modifiers = isset($parts[1]) ? $parts[1] : '';
1908
1908
1909
        preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
1909
        preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
1910
        $section_name = $match[1];
1910
        $section_name = $match[1];
1911
        $prop_name = $match[2];
1911
        $prop_name = $match[2];
1912
1912
1913
        $output = "\$this->_sections['$section_name']['$prop_name']";
1913
        $output = "\$this->_sections['$section_name']['$prop_name']";
1914
1914
1915
        $this->_parse_modifiers($output, $modifiers);
1915
        $this->_parse_modifiers($output, $modifiers);
1916
1916
1917
        return $output;
1917
        return $output;
1918
    }
1918
    }
1919
1919
1920
1920
1921
    /**
1921
    /**
1922
     * parse modifier chain into PHP code
1922
     * parse modifier chain into PHP code
1923
     *
1923
     *
1924
     * sets $output to parsed modified chain
1924
     * sets $output to parsed modified chain
1925
     * @param string $output
1925
     * @param string $output
1926
     * @param string $modifier_string
1926
     * @param string $modifier_string
1927
     */
1927
     */
1928
    function _parse_modifiers(&$output, $modifier_string)
1928
    function _parse_modifiers(&$output, $modifier_string)
1929
    {
1929
    {
1930
        preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
1930
        preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
1931
        list(, $_modifiers, $modifier_arg_strings) = $_match;
1931
        list(, $_modifiers, $modifier_arg_strings) = $_match;
1932
1932
1933
        for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
1933
        for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
1934
            $_modifier_name = $_modifiers[$_i];
1934
            $_modifier_name = $_modifiers[$_i];
1935
1935
1936
            if($_modifier_name == 'smarty') {
1936
            if($_modifier_name == 'smarty') {
1937
                // skip smarty modifier
1937
                // skip smarty modifier
1938
                continue;
1938
                continue;
1939
            }
1939
            }
1940
1940
1941
            preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);
1941
            preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);
1942
            $_modifier_args = $_match[1];
1942
            $_modifier_args = $_match[1];
1943
1943
1944
            if (substr($_modifier_name, 0, 1) == '@') {
1944
            if (substr($_modifier_name, 0, 1) == '@') {
1945
                $_map_array = false;
1945
                $_map_array = false;
1946
                $_modifier_name = substr($_modifier_name, 1);
1946
                $_modifier_name = substr($_modifier_name, 1);
1947
            } else {
1947
            } else {
1948
                $_map_array = true;
1948
                $_map_array = true;
1949
            }
1949
            }
1950
1950
1951
            if (empty($this->_plugins['modifier'][$_modifier_name])
1951
            if (empty($this->_plugins['modifier'][$_modifier_name])
1952
                && !$this->_get_plugin_filepath('modifier', $_modifier_name)
1952
                && !$this->_get_plugin_filepath('modifier', $_modifier_name)
1953
                && function_exists($_modifier_name)) {
1953
                && function_exists($_modifier_name)) {
1954
                if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
1954
                if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
1955
                    $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
1955
                    $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
1956
                } else {
1956
                } else {
1957
                    $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);
1957
                    $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);
1958
                }
1958
                }
1959
            }
1959
            }
1960
            $this->_add_plugin('modifier', $_modifier_name);
1960
            $this->_add_plugin('modifier', $_modifier_name);
1961
1961
1962
            $this->_parse_vars_props($_modifier_args);
1962
            $this->_parse_vars_props($_modifier_args);
1963
1963
1964
            if($_modifier_name == 'default') {
1964
            if($_modifier_name == 'default') {
1965
                // supress notifications of default modifier vars and args
1965
                // supress notifications of default modifier vars and args
1966
                if(substr($output, 0, 1) == '$') {
1966
                if(substr($output, 0, 1) == '$') {
1967
                    $output = '@' . $output;
1967
                    $output = '@' . $output;
1968
                }
1968
                }
1969
                if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') {
1969
                if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') {
1970
                    $_modifier_args[0] = '@' . $_modifier_args[0];
1970
                    $_modifier_args[0] = '@' . $_modifier_args[0];
1971
                }
1971
                }
1972
            }
1972
            }
1973
            if (count($_modifier_args) > 0)
1973
            if (count($_modifier_args) > 0)
1974
                $_modifier_args = ', '.implode(', ', $_modifier_args);
1974
                $_modifier_args = ', '.implode(', ', $_modifier_args);
1975
            else
1975
            else
1976
                $_modifier_args = '';
1976
                $_modifier_args = '';
1977
1977
1978
            if ($_map_array) {
1978
            if ($_map_array) {
1979
                $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))";
1979
                $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))";
1980
1980
1981
            } else {
1981
            } else {
1982
1982
1983
                $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
1983
                $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
1984
1984
1985
            }
1985
            }
1986
        }
1986
        }
1987
    }
1987
    }
1988
1988
1989
1989
1990
    /**
1990
    /**
1991
     * add plugin
1991
     * add plugin
1992
     *
1992
     *
1993
     * @param string $type
1993
     * @param string $type
1994
     * @param string $name
1994
     * @param string $name
1995
     * @param boolean? $delayed_loading
1995
     * @param boolean? $delayed_loading
1996
     */
1996
     */
1997
    function _add_plugin($type, $name, $delayed_loading = null)
1997
    function _add_plugin($type, $name, $delayed_loading = null)
1998
    {
1998
    {
1999
        if (!isset($this->_plugin_info[$type])) {
1999
        if (!isset($this->_plugin_info[$type])) {
2000
            $this->_plugin_info[$type] = array();
2000
            $this->_plugin_info[$type] = array();
2001
        }
2001
        }
2002
        if (!isset($this->_plugin_info[$type][$name])) {
2002
        if (!isset($this->_plugin_info[$type][$name])) {
2003
            $this->_plugin_info[$type][$name] = array($this->_current_file,
2003
            $this->_plugin_info[$type][$name] = array($this->_current_file,
2004
                                                      $this->_current_line_no,
2004
                                                      $this->_current_line_no,
2005
                                                      $delayed_loading);
2005
                                                      $delayed_loading);
2006
        }
2006
        }
2007
    }
2007
    }
2008
2008
2009
2009
2010
    /**
2010
    /**
2011
     * Compiles references of type $smarty.foo
2011
     * Compiles references of type $smarty.foo
2012
     *
2012
     *
2013
     * @param string $indexes
2013
     * @param string $indexes
2014
     * @return string
2014
     * @return string
2015
     */
2015
     */
2016
    function _compile_smarty_ref(&$indexes)
2016
    function _compile_smarty_ref(&$indexes)
2017
    {
2017
    {
2018
        /* Extract the reference name. */
2018
        /* Extract the reference name. */
2019
        $_ref = substr($indexes[0], 1);
2019
        $_ref = substr($indexes[0], 1);
2020
        foreach($indexes as $_index_no=>$_index) {
2020
        foreach($indexes as $_index_no=>$_index) {
2021
            if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
2021
            if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
2022
                $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
2022
                $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
2023
            }
2023
            }
2024
        }
2024
        }
2025
2025
2026
        switch ($_ref) {
2026
        switch ($_ref) {
2027
            case 'now':
2027
            case 'now':
2028
                $compiled_ref = 'time()';
2028
                $compiled_ref = 'time()';
2029
                $_max_index = 1;
2029
                $_max_index = 1;
2030
                break;
2030
                break;
2031
2031
2032
            case 'foreach':
2032
            case 'foreach':
2033
                array_shift($indexes);
2033
                array_shift($indexes);
2034
                $_var = $this->_parse_var_props(substr($indexes[0], 1));
2034
                $_var = $this->_parse_var_props(substr($indexes[0], 1));
2035
                $_propname = substr($indexes[1], 1);
2035
                $_propname = substr($indexes[1], 1);
2036
                $_max_index = 1;
2036
                $_max_index = 1;
2037
                switch ($_propname) {
2037
                switch ($_propname) {
2038
                    case 'index':
2038
                    case 'index':
2039
                        array_shift($indexes);
2039
                        array_shift($indexes);
2040
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
2040
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
2041
                        break;
2041
                        break;
2042
                       
2042
                       
2043
                    case 'first':
2043
                    case 'first':
2044
                        array_shift($indexes);
2044
                        array_shift($indexes);
2045
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
2045
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
2046
                        break;
2046
                        break;
2047
2047
2048
                    case 'last':
2048
                    case 'last':
2049
                        array_shift($indexes);
2049
                        array_shift($indexes);
2050
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
2050
                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
2051
                        break;
2051
                        break;
2052
                       
2052
                       
2053
                    case 'show':
2053
                    case 'show':
2054
                        array_shift($indexes);
2054
                        array_shift($indexes);
2055
                        $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
2055
                        $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
2056
                        break;
2056
                        break;
2057
                       
2057
                       
2058
                    default:
2058
                    default:
2059
                        unset($_max_index);
2059
                        unset($_max_index);
2060
                        $compiled_ref = "\$this->_foreach[$_var]";
2060
                        $compiled_ref = "\$this->_foreach[$_var]";
2061
                }
2061
                }
2062
                break;
2062
                break;
2063
2063
2064
            case 'section':
2064
            case 'section':
2065
                array_shift($indexes);
2065
                array_shift($indexes);
2066
                $_var = $this->_parse_var_props(substr($indexes[0], 1));
2066
                $_var = $this->_parse_var_props(substr($indexes[0], 1));
2067
                $compiled_ref = "\$this->_sections[$_var]";
2067
                $compiled_ref = "\$this->_sections[$_var]";
2068
                break;
2068
                break;
2069
2069
2070
            case 'get':
2070
            case 'get':
2071
                $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
2071
                $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
2072
                break;
2072
                break;
2073
2073
2074
            case 'post':
2074
            case 'post':
2075
                $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
2075
                $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
2076
                break;
2076
                break;
2077
2077
2078
            case 'cookies':
2078
            case 'cookies':
2079
                $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
2079
                $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
2080
                break;
2080
                break;
2081
2081
2082
            case 'env':
2082
            case 'env':
2083
                $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
2083
                $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
2084
                break;
2084
                break;
2085
2085
2086
            case 'server':
2086
            case 'server':
2087
                $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
2087
                $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
2088
                break;
2088
                break;
2089
2089
2090
            case 'session':
2090
            case 'session':
2091
                $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
2091
                $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
2092
                break;
2092
                break;
2093
2093
2094
            /*
2094
            /*
2095
             * These cases are handled either at run-time or elsewhere in the
2095
             * These cases are handled either at run-time or elsewhere in the
2096
             * compiler.
2096
             * compiler.
2097
             */
2097
             */
2098
            case 'request':
2098
            case 'request':
2099
                if ($this->request_use_auto_globals) {
2099
                if ($this->request_use_auto_globals) {
2100
                    $compiled_ref = '$_REQUEST';
2100
                    $compiled_ref = '$_REQUEST';
2101
                    break;
2101
                    break;
2102
                } else {
2102
                } else {
2103
                    $this->_init_smarty_vars = true;
2103
                    $this->_init_smarty_vars = true;
2104
                }
2104
                }
2105
                return null;
2105
                return null;
2106
2106
2107
            case 'capture':
2107
            case 'capture':
2108
                return null;
2108
                return null;
2109
2109
2110
            case 'template':
2110
            case 'template':
2111
                $compiled_ref = "'$this->_current_file'";
2111
                $compiled_ref = "'$this->_current_file'";
2112
                $_max_index = 1;
2112
                $_max_index = 1;
2113
                break;
2113
                break;
2114
2114
2115
            case 'version':
2115
            case 'version':
2116
                $compiled_ref = "'$this->_version'";
2116
                $compiled_ref = "'$this->_version'";
2117
                $_max_index = 1;
2117
                $_max_index = 1;
2118
                break;
2118
                break;
2119
2119
2120
            case 'const':
2120
            case 'const':
2121
                if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
2121
                if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
2122
                    $this->_syntax_error("(secure mode) constants not permitted",
2122
                    $this->_syntax_error("(secure mode) constants not permitted",
2123
                                         E_USER_WARNING, __FILE__, __LINE__);
2123
                                         E_USER_WARNING, __FILE__, __LINE__);
2124
                    return;
2124
                    return;
2125
                }
2125
                }
2126
                array_shift($indexes);
2126
                array_shift($indexes);
2127
                if (preg_match('!^\.\w+$!', $indexes[0])) {
2127
                if (preg_match('!^\.\w+$!', $indexes[0])) {
2128
                    $compiled_ref = '@' . substr($indexes[0], 1);
2128
                    $compiled_ref = '@' . substr($indexes[0], 1);
2129
                } else {
2129
                } else {
2130
                    $_val = $this->_parse_var_props(substr($indexes[0], 1));
2130
                    $_val = $this->_parse_var_props(substr($indexes[0], 1));
2131
                    $compiled_ref = '@constant(' . $_val . ')';
2131
                    $compiled_ref = '@constant(' . $_val . ')';
2132
                }
2132
                }
2133
                $_max_index = 1;
2133
                $_max_index = 1;
2134
                break;
2134
                break;
2135
2135
2136
            case 'config':
2136
            case 'config':
2137
                $compiled_ref = "\$this->_config[0]['vars']";
2137
                $compiled_ref = "\$this->_config[0]['vars']";
2138
                $_max_index = 3;
2138
                $_max_index = 3;
2139
                break;
2139
                break;
2140
2140
2141
            case 'ldelim':
2141
            case 'ldelim':
2142
                $compiled_ref = "'$this->left_delimiter'";
2142
                $compiled_ref = "'$this->left_delimiter'";
2143
                break;
2143
                break;
2144
2144
2145
            case 'rdelim':
2145
            case 'rdelim':
2146
                $compiled_ref = "'$this->right_delimiter'";
2146
                $compiled_ref = "'$this->right_delimiter'";
2147
                break;
2147
                break;
2148
               
2148
               
2149
            default:
2149
            default:
2150
                $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
2150
                $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
2151
                break;
2151
                break;
2152
        }
2152
        }
2153
2153
2154
        if (isset($_max_index) && count($indexes) > $_max_index) {
2154
        if (isset($_max_index) && count($indexes) > $_max_index) {
2155
            $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
2155
            $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
2156
        }
2156
        }
2157
2157
2158
        array_shift($indexes);
2158
        array_shift($indexes);
2159
        return $compiled_ref;
2159
        return $compiled_ref;
2160
    }
2160
    }
2161
2161
2162
    /**
2162
    /**
2163
     * compiles call to plugin of type $type with name $name
2163
     * compiles call to plugin of type $type with name $name
2164
     * returns a string containing the function-name or method call
2164
     * returns a string containing the function-name or method call
2165
     * without the paramter-list that would have follow to make the
2165
     * without the paramter-list that would have follow to make the
2166
     * call valid php-syntax
2166
     * call valid php-syntax
2167
     *
2167
     *
2168
     * @param string $type
2168
     * @param string $type
2169
     * @param string $name
2169
     * @param string $name
2170
     * @return string
2170
     * @return string
2171
     */
2171
     */
2172
    function _compile_plugin_call($type, $name) {
2172
    function _compile_plugin_call($type, $name) {
2173
        if (isset($this->_plugins[$type][$name])) {
2173
        if (isset($this->_plugins[$type][$name])) {
2174
            /* plugin loaded */
2174
            /* plugin loaded */
2175
            if (is_array($this->_plugins[$type][$name][0])) {
2175
            if (is_array($this->_plugins[$type][$name][0])) {
2176
                return ((is_object($this->_plugins[$type][$name][0][0])) ?
2176
                return ((is_object($this->_plugins[$type][$name][0][0])) ?
2177
                        "\$this->_plugins['$type']['$name'][0][0]->"    /* method callback */
2177
                        "\$this->_plugins['$type']['$name'][0][0]->"    /* method callback */
2178
                        : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */
2178
                        : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */
2179
                       ). $this->_plugins[$type][$name][0][1];
2179
                       ). $this->_plugins[$type][$name][0][1];
2180
2180
2181
            } else {
2181
            } else {
2182
                /* function callback */
2182
                /* function callback */
2183
                return $this->_plugins[$type][$name][0];
2183
                return $this->_plugins[$type][$name][0];
2184
2184
2185
            }
2185
            }
2186
        } else {
2186
        } else {
2187
            /* plugin not loaded -> auto-loadable-plugin */
2187
            /* plugin not loaded -> auto-loadable-plugin */
2188
            return 'smarty_'.$type.'_'.$name;
2188
            return 'smarty_'.$type.'_'.$name;
2189
2189
2190
        }
2190
        }
2191
    }
2191
    }
2192
2192
2193
    /**
2193
    /**
2194
     * load pre- and post-filters
2194
     * load pre- and post-filters
2195
     */
2195
     */
2196
    function _load_filters()
2196
    function _load_filters()
2197
    {
2197
    {
2198
        if (count($this->_plugins['prefilter']) > 0) {
2198
        if (count($this->_plugins['prefilter']) > 0) {
2199
            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
2199
            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
2200
                if ($prefilter === false) {
2200
                if ($prefilter === false) {
2201
                    unset($this->_plugins['prefilter'][$filter_name]);
2201
                    unset($this->_plugins['prefilter'][$filter_name]);
2202
                    $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
2202
                    $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
2203
                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2203
                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2204
                    smarty_core_load_plugins($_params, $this);
2204
                    smarty_core_load_plugins($_params, $this);
2205
                }
2205
                }
2206
            }
2206
            }
2207
        }
2207
        }
2208
        if (count($this->_plugins['postfilter']) > 0) {
2208
        if (count($this->_plugins['postfilter']) > 0) {
2209
            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
2209
            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
2210
                if ($postfilter === false) {
2210
                if ($postfilter === false) {
2211
                    unset($this->_plugins['postfilter'][$filter_name]);
2211
                    unset($this->_plugins['postfilter'][$filter_name]);
2212
                    $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
2212
                    $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
2213
                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2213
                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
2214
                    smarty_core_load_plugins($_params, $this);
2214
                    smarty_core_load_plugins($_params, $this);
2215
                }
2215
                }
2216
            }
2216
            }
2217
        }
2217
        }
2218
    }
2218
    }
2219
2219
2220
2220
2221
    /**
2221
    /**
2222
     * Quote subpattern references
2222
     * Quote subpattern references
2223
     *
2223
     *
2224
     * @param string $string
2224
     * @param string $string
2225
     * @return string
2225
     * @return string
2226
     */
2226
     */
2227
    function _quote_replace($string)
2227
    function _quote_replace($string)
2228
    {
2228
    {
2229
        return strtr($string, array('\\' => '\\\\', '$' => '\\$'));
2229
        return strtr($string, array('\\' => '\\\\', '$' => '\\$'));
2230
    }
2230
    }
2231
2231
2232
    /**
2232
    /**
2233
     * display Smarty syntax error
2233
     * display Smarty syntax error
2234
     *
2234
     *
2235
     * @param string $error_msg
2235
     * @param string $error_msg
2236
     * @param integer $error_type
2236
     * @param integer $error_type
2237
     * @param string $file
2237
     * @param string $file
2238
     * @param integer $line
2238
     * @param integer $line
2239
     */
2239
     */
2240
    function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
2240
    function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
2241
    {
2241
    {
2242
        $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
2242
        $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
2243
    }
2243
    }
2244
2244
2245
2245
2246
    /**
2246
    /**
2247
     * check if the compilation changes from cacheable to
2247
     * check if the compilation changes from cacheable to
2248
     * non-cacheable state with the beginning of the current
2248
     * non-cacheable state with the beginning of the current
2249
     * plugin. return php-code to reflect the transition.
2249
     * plugin. return php-code to reflect the transition.
2250
     * @return string
2250
     * @return string
2251
     */
2251
     */
2252
    function _push_cacheable_state($type, $name) {
2252
    function _push_cacheable_state($type, $name) {
2253
        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2253
        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2254
        if ($_cacheable
2254
        if ($_cacheable
2255
            || 0<$this->_cacheable_state++) return '';
2255
            || 0<$this->_cacheable_state++) return '';
2256
        if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
2256
        if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
2257
        $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:'
2257
        $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:'
2258
            . $this->_cache_serial . '#' . $this->_nocache_count
2258
            . $this->_cache_serial . '#' . $this->_nocache_count
2259
            . '}\'; endif;';
2259
            . '}\'; endif;';
2260
        return $_ret;
2260
        return $_ret;
2261
    }
2261
    }
2262
2262
2263
2263
2264
    /**
2264
    /**
2265
     * check if the compilation changes from non-cacheable to
2265
     * check if the compilation changes from non-cacheable to
2266
     * cacheable state with the end of the current plugin return
2266
     * cacheable state with the end of the current plugin return
2267
     * php-code to reflect the transition.
2267
     * php-code to reflect the transition.
2268
     * @return string
2268
     * @return string
2269
     */
2269
     */
2270
    function _pop_cacheable_state($type, $name) {
2270
    function _pop_cacheable_state($type, $name) {
2271
        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2271
        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2272
        if ($_cacheable
2272
        if ($_cacheable
2273
            || --$this->_cacheable_state>0) return '';
2273
            || --$this->_cacheable_state>0) return '';
2274
        return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:'
2274
        return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:'
2275
            . $this->_cache_serial . '#' . ($this->_nocache_count++)
2275
            . $this->_cache_serial . '#' . ($this->_nocache_count++)
2276
            . '}\'; endif;';
2276
            . '}\'; endif;';
2277
    }
2277
    }
2278
2278
2279
2279
2280
    /**
2280
    /**
2281
     * push opening tag-name, file-name and line-number on the tag-stack
2281
     * push opening tag-name, file-name and line-number on the tag-stack
2282
     * @param string the opening tag's name
2282
     * @param string the opening tag's name
2283
     */
2283
     */
2284
    function _push_tag($open_tag)
2284
    function _push_tag($open_tag)
2285
    {
2285
    {
2286
        array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
2286
        array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
2287
    }
2287
    }
2288
2288
2289
    /**
2289
    /**
2290
     * pop closing tag-name
2290
     * pop closing tag-name
2291
     * raise an error if this stack-top doesn't match with the closing tag
2291
     * raise an error if this stack-top doesn't match with the closing tag
2292
     * @param string the closing tag's name
2292
     * @param string the closing tag's name
2293
     * @return string the opening tag's name
2293
     * @return string the opening tag's name
2294
     */
2294
     */
2295
    function _pop_tag($close_tag)
2295
    function _pop_tag($close_tag)
2296
    {
2296
    {
2297
        $message = '';
2297
        $message = '';
2298
        if (count($this->_tag_stack)>0) {
2298
        if (count($this->_tag_stack)>0) {
2299
            list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
2299
            list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
2300
            if ($close_tag == $_open_tag) {
2300
            if ($close_tag == $_open_tag) {
2301
                return $_open_tag;
2301
                return $_open_tag;
2302
            }
2302
            }
2303
            if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
2303
            if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
2304
                return $this->_pop_tag($close_tag);
2304
                return $this->_pop_tag($close_tag);
2305
            }
2305
            }
2306
            if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
2306
            if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
2307
                $this->_pop_tag($close_tag);
2307
                $this->_pop_tag($close_tag);
2308
                return $_open_tag;
2308
                return $_open_tag;
2309
            }
2309
            }
2310
            if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
2310
            if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
2311
                $this->_pop_tag($close_tag);
2311
                $this->_pop_tag($close_tag);
2312
                return $_open_tag;
2312
                return $_open_tag;
2313
            }
2313
            }
2314
            if ($_open_tag == 'else' || $_open_tag == 'elseif') {
2314
            if ($_open_tag == 'else' || $_open_tag == 'elseif') {
2315
                $_open_tag = 'if';
2315
                $_open_tag = 'if';
2316
            } elseif ($_open_tag == 'sectionelse') {
2316
            } elseif ($_open_tag == 'sectionelse') {
2317
                $_open_tag = 'section';
2317
                $_open_tag = 'section';
2318
            } elseif ($_open_tag == 'foreachelse') {
2318
            } elseif ($_open_tag == 'foreachelse') {
2319
                $_open_tag = 'foreach';
2319
                $_open_tag = 'foreach';
2320
            }
2320
            }
2321
            $message = " expected {/$_open_tag} (opened line $_line_no).";
2321
            $message = " expected {/$_open_tag} (opened line $_line_no).";
2322
        }
2322
        }
2323
        $this->_syntax_error("mismatched tag {/$close_tag}.$message",
2323
        $this->_syntax_error("mismatched tag {/$close_tag}.$message",
2324
                             E_USER_ERROR, __FILE__, __LINE__);
2324
                             E_USER_ERROR, __FILE__, __LINE__);
2325
    }
2325
    }
2326
2326
2327
}
2327
}
2328
2328
2329
/**
2329
/**
2330
 * compare to values by their string length
2330
 * compare to values by their string length
2331
 *
2331
 *
2332
 * @access private
2332
 * @access private
2333
 * @param string $a
2333
 * @param string $a
2334
 * @param string $b
2334
 * @param string $b
2335
 * @return 0|-1|1
2335
 * @return 0|-1|1
2336
 */
2336
 */
2337
function _smarty_sort_length($a, $b)
2337
function _smarty_sort_length($a, $b)
2338
{
2338
{
2339
    if($a == $b)
2339
    if($a == $b)
2340
        return 0;
2340
        return 0;
2341
2341
2342
    if(strlen($a) == strlen($b))
2342
    if(strlen($a) == strlen($b))
2343
        return ($a > $b) ? -1 : 1;
2343
        return ($a > $b) ? -1 : 1;
2344
2344
2345
    return (strlen($a) > strlen($b)) ? -1 : 1;
2345
    return (strlen($a) > strlen($b)) ? -1 : 1;
2346
}
2346
}
2347
2347
2348
2348
2349
/* vim: set et: */
2349
/* vim: set et: */
2350
2350
2351
?>
2351
?>
2352
 
2352