/[cvs]/nfo/php/libs/net.php.smarty/Smarty_Compiler.class.php
ViewVC logotype

Diff of /nfo/php/libs/net.php.smarty/Smarty_Compiler.class.php

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by joko, Thu Dec 19 16:40:20 2002 UTC revision 1.3 by joko, Wed Jun 16 21:58:11 2004 UTC
# Line 1  Line 1 
1  <?php  <?php
2    
3  /*  /**
4   * Project:     Smarty: the PHP compiling template engine   * Project:     Smarty: the PHP compiling template engine
5   * File:        Smarty_Compiler.class.php   * File:        Smarty_Compiler.class.php
  * Author:      Monte Ohrt <monte@ispi.net>  
  *              Andrei Zmievski <andrei@php.net>  
  *  
  * Version:     2.3.1  
  * Copyright:   2001,2002 ispi of Lincoln, Inc.  
6   *   *
7   * This library is free software; you can redistribute it and/or   * This library is free software; you can redistribute it and/or
8   * modify it under the terms of the GNU Lesser General Public   * modify it under the terms of the GNU Lesser General Public
# Line 23  Line 18 
18   * License along with this library; if not, write to the Free Software   * 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   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   *   *
21   * You may contact the authors of Smarty by e-mail at:   * @link http://smarty.php.net/
22   * monte@ispi.net   * @author Monte Ohrt <monte@ispi.net>
23   * andrei@php.net   * @author Andrei Zmievski <andrei@php.net>
24   *   * @version 2.6.3
25   * Or, write to:   * @copyright 2001-2004 ispi of Lincoln, Inc.
26   * Monte Ohrt   * @package Smarty
  * Director of Technology, ispi  
  * 237 S. 70th suite 220  
  * Lincoln, NE 68510  
  *  
  * The latest version of Smarty can be obtained from:  
  * http://www.phpinsider.com/  
  *  
27   */   */
28    
29    /* $Id$ */
30    
31    /**
32     * Template compiling class
33     * @package Smarty
34     */
35  class Smarty_Compiler extends Smarty {  class Smarty_Compiler extends Smarty {
36    
37      // internal vars      // internal vars
38      var $_sectionelse_stack     =   array();    // keeps track of whether section had 'else' part      /**#@+
39      var $_foreachelse_stack     =   array();    // keeps track of whether foreach had 'else' part       * @access private
40      var $_literal_blocks        =   array();    // keeps literal template blocks       */
41      var $_php_blocks            =   array();    // keeps php code blocks      var $_folded_blocks         =   array();    // keeps folded template blocks
42      var $_current_file          =   null;       // the current template being compiled      var $_current_file          =   null;       // the current template being compiled
43      var $_current_line_no       =   1;          // line number for error messages      var $_current_line_no       =   1;          // line number for error messages
44      var $_capture_stack         =   array();    // keeps track of nested capture buffers      var $_capture_stack         =   array();    // keeps track of nested capture buffers
45      var $_plugin_info           =   array();    // keeps track of plugins to load      var $_plugin_info           =   array();    // keeps track of plugins to load
46      var $_init_smarty_vars      =   false;      var $_init_smarty_vars      =   false;
47        var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');
48        var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor
49  /*======================================================================*\      var $_si_qstr_regexp        =   null;
50      Function:   _compile_file()      var $_qstr_regexp           =   null;
51      Input:      compile a template file      var $_func_regexp           =   null;
52  \*======================================================================*/      var $_var_bracket_regexp    =   null;
53      function _compile_file($tpl_file, $template_source, &$template_compiled)      var $_dvar_guts_regexp      =   null;
54        var $_dvar_regexp           =   null;
55        var $_cvar_regexp           =   null;
56        var $_svar_regexp           =   null;
57        var $_avar_regexp           =   null;
58        var $_mod_regexp            =   null;
59        var $_var_regexp            =   null;
60        var $_parenth_param_regexp  =   null;
61        var $_func_call_regexp      =   null;
62        var $_obj_ext_regexp        =   null;
63        var $_obj_start_regexp      =   null;
64        var $_obj_params_regexp     =   null;
65        var $_obj_call_regexp       =   null;
66        var $_cacheable_state       =   0;
67        var $_cache_attrs_count     =   0;
68        var $_nocache_count         =   0;
69        var $_cache_serial          =   null;
70        var $_cache_include         =   null;
71    
72        var $_strip_depth           =   0;
73        var $_additional_newline    =   "\n";
74    
75        /**#@-*/
76        /**
77         * The class constructor.
78         */
79        function Smarty_Compiler()
80        {
81            // matches double quoted strings:
82            // "foobar"
83            // "foo\"bar"
84            $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
85    
86            // matches single quoted strings:
87            // 'foobar'
88            // 'foo\'bar'
89            $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
90    
91            // matches single or double quoted strings
92            $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
93    
94            // matches bracket portion of vars
95            // [0]
96            // [foo]
97            // [$bar]
98            $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
99    
100            // matches numerical constants
101            // 30
102            // -12
103            // 13.22
104            $this->_num_const_regexp = '\-?\d+(?:\.\d+)?';
105    
106            // matches $ vars (not objects):
107            // $foo
108            // $foo.bar
109            // $foo.bar.foobar
110            // $foo[0]
111            // $foo[$bar]
112            // $foo[5][blah]
113            // $foo[5].bar[$foobar][4]
114            $this->_dvar_math_regexp = '[\+\-\*\/\%]';
115            $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
116            $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
117                    . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
118            $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
119    
120            // matches config vars:
121            // #foo#
122            // #foobar123_foo#
123            $this->_cvar_regexp = '\#\w+\#';
124    
125            // matches section vars:
126            // %foo.bar%
127            $this->_svar_regexp = '\%\w+\.\w+\%';
128    
129            // matches all valid variables (no quotes, no modifiers)
130            $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
131               . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
132    
133            // matches valid variable syntax:
134            // $foo
135            // $foo
136            // #foo#
137            // #foo#
138            // "text"
139            // "text"
140            $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_num_const_regexp . '|' . $this->_qstr_regexp . ')';
141    
142            // matches valid object call (no objects allowed in parameters):
143            // $foo->bar
144            // $foo->bar()
145            // $foo->bar("text")
146            // $foo->bar($foo, $bar, "text")
147            // $foo->bar($foo, "foo")
148            // $foo->bar->foo()
149            // $foo->bar->foo->bar()
150            $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
151            $this->_obj_params_regexp = '\((?:\w+|'
152                    . $this->_var_regexp . '(?:\s*,\s*(?:(?:\w+|'
153                    . $this->_var_regexp . ')))*)?\)';
154            $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
155            $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?)';
156    
157            // matches valid modifier syntax:
158            // |foo
159            // |@foo
160            // |foo:"bar"
161            // |foo:$bar
162            // |foo:"bar":$foobar
163            // |foo|bar
164            // |foo:$foo->bar
165            $this->_mod_regexp = '(?:\|@?\w+(?::(?>-?\w+|'
166               . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
167    
168            // matches valid function name:
169            // foo123
170            // _foo_bar
171            $this->_func_regexp = '[a-zA-Z_]\w*';
172    
173            // matches valid registered object:
174            // foo->bar
175            $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
176    
177            // matches valid parameter values:
178            // true
179            // $foo
180            // $foo|bar
181            // #foo#
182            // #foo#|bar
183            // "text"
184            // "text"|bar
185            // $foo->bar
186            $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
187               . $this->_var_regexp  . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
188    
189            // matches valid parenthesised function parameters:
190            //
191            // "text"
192            //    $foo, $bar, "text"
193            // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
194            $this->_parenth_param_regexp = '(?:\((?:\w+|'
195                    . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
196                    . $this->_param_regexp . ')))*)?\))';
197    
198            // matches valid function call:
199            // foo()
200            // foo_bar($foo)
201            // _foo_bar($foo,"bar")
202            // foo123($foo,$foo->bar(),"foo")
203            $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
204               . $this->_parenth_param_regexp . '))';
205        }
206    
207        /**
208         * compile a resource
209         *
210         * sets $compiled_content to the compiled source
211         * @param string $resource_name
212         * @param string $source_content
213         * @param string $compiled_content
214         * @return true
215         */
216        function _compile_file($resource_name, $source_content, &$compiled_content)
217      {      {
218    
219          if ($this->security) {          if ($this->security) {
220              // do not allow php syntax to be executed unless specified              // do not allow php syntax to be executed unless specified
221              if ($this->php_handling == SMARTY_PHP_ALLOW &&              if ($this->php_handling == SMARTY_PHP_ALLOW &&
# Line 68  class Smarty_Compiler extends Smarty { Line 226  class Smarty_Compiler extends Smarty {
226    
227          $this->_load_filters();          $this->_load_filters();
228    
229          $this->_current_file = $tpl_file;          $this->_current_file = $resource_name;
230          $this->_current_line_no = 1;          $this->_current_line_no = 1;
231          $ldq = preg_quote($this->left_delimiter, '!');          $ldq = preg_quote($this->left_delimiter, '!');
232          $rdq = preg_quote($this->right_delimiter, '!');          $rdq = preg_quote($this->right_delimiter, '!');
# Line 77  class Smarty_Compiler extends Smarty { Line 235  class Smarty_Compiler extends Smarty {
235          if (count($this->_plugins['prefilter']) > 0) {          if (count($this->_plugins['prefilter']) > 0) {
236              foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {              foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
237                  if ($prefilter === false) continue;                  if ($prefilter === false) continue;
238                  if ($prefilter[3] || function_exists($prefilter[0])) {                  if ($prefilter[3] || is_callable($prefilter[0])) {
239                      $template_source = $prefilter[0]($template_source, $this);                      $source_content = call_user_func_array($prefilter[0],
240                                                                array($source_content, &$this));
241                      $this->_plugins['prefilter'][$filter_name][3] = true;                      $this->_plugins['prefilter'][$filter_name][3] = true;
242                  } else {                  } else {
243                      $this->_trigger_plugin_error("Smarty plugin error: prefilter '$filter_name' is not implemented");                      $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
244                  }                  }
245              }              }
246          }          }
247    
248          /* Annihilate the comments. */          /* fetch all special blocks */
249          $template_source = preg_replace("!({$ldq})\*(.*?)\*({$rdq})!se",          $search = "!{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s";
                                         "'\\1*'.str_repeat(\"\n\", substr_count('\\2', \"\n\")) .'*\\3'",  
                                         $template_source);  
   
         /* Pull out the literal blocks. */  
         preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_source, $match);  
         $this->_literal_blocks = $match[1];  
         $template_source = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",  
                                         $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source);  
250    
251          /* Pull out the php code blocks. */          preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);
252          preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $template_source, $match);          $this->_folded_blocks = $match;
253          $this->_php_blocks = $match[1];          reset($this->_folded_blocks);
254          $template_source = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s",  
255                                          $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source);          /* replace special blocks by "{php}" */
256            $source_content = preg_replace($search.'e', "'"
257                                           . $this->_quote_replace($this->left_delimiter) . 'php'
258                                           . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
259                                           . $this->_quote_replace($this->right_delimiter)
260                                           . "'"
261                                           , $source_content);
262    
263          /* Gather all template tags. */          /* Gather all template tags. */
264          preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_source, $match);          preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $source_content, $_match);
265          $template_tags = $match[1];          $template_tags = $_match[1];
266          /* Split content by template tags to obtain non-template content. */          /* Split content by template tags to obtain non-template content. */
267          $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_source);          $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $source_content);
268    
269          /* loop through text blocks */          /* loop through text blocks */
270          for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {          for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
271              /* match anything within <? ?> */              /* match anything resembling php tags */
272              if (preg_match_all('!(<\?[^?]*?\?>|<script\s+language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $text_blocks[$curr_tb], $sp_match)) {              if (preg_match_all('!(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)!is', $text_blocks[$curr_tb], $sp_match)) {
273                  /* found at least one match, loop through each one */                  /* replace tags with placeholders to prevent recursive replacements */
274                  for ($curr_sp = 0, $for_max2 = count($sp_match[0]); $curr_sp < $for_max2; $curr_sp++) {                  $sp_match[1] = array_unique($sp_match[1]);
275                      if (preg_match('!^(<\?(php\s|\s|=\s)|<script\s*language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $sp_match[0][$curr_sp])) {                  usort($sp_match[1], '_smarty_sort_length');
276                          /* php tag */                  for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
277                          if ($this->php_handling == SMARTY_PHP_PASSTHRU) {                      $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
278                              /* echo php contents */                  }
279                              $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);                  /* process each one */
280                         } else if ($this->php_handling == SMARTY_PHP_QUOTE) {                  for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
281                              /* quote php tags */                      if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
282                              $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], htmlspecialchars($sp_match[0][$curr_sp]), $text_blocks[$curr_tb]);                          /* echo php contents */
283                          } else if ($this->php_handling == SMARTY_PHP_REMOVE) {                          $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
284                              /* remove php tags */                      } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
285                              if (substr($sp_match[0][$curr_sp], 0, 2) == '<?')                          /* quote php tags */
286                                  $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '', $text_blocks[$curr_tb]);                          $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
287                              else                      } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
288                                  /* attempt to remove everything between <script ...> and </script> */                          /* remove php tags */
289                                  $text_blocks[$curr_tb] = preg_replace('!'.preg_quote($sp_match[0][$curr_sp], '!').'.*?</script\s*>!is', '', $text_blocks[$curr_tb]);                          $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
290                          }                      } else {
291                      } else                          /* SMARTY_PHP_ALLOW, but echo non php starting tags */
292                          /* echo the non-php tags */                          $sp_match[1][$curr_sp] = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
293                          $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);                          $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
294                        }
295                  }                  }
296              }              }
297          }          }
# Line 145  class Smarty_Compiler extends Smarty { Line 303  class Smarty_Compiler extends Smarty {
303              $compiled_tags[] = $this->_compile_tag($template_tags[$i]);              $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
304              $this->_current_line_no += substr_count($template_tags[$i], "\n");              $this->_current_line_no += substr_count($template_tags[$i], "\n");
305          }          }
306            if (count($this->_tag_stack)>0) {
307                list($_open_tag, $_line_no) = end($this->_tag_stack);
308                $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
309                return;
310            }
311    
312          $template_compiled = '';          $compiled_content = '';
313    
314          /* Interleave the compiled contents and text blocks to get the final result. */          /* Interleave the compiled contents and text blocks to get the final result. */
315          for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {          for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
316              $template_compiled .= $text_blocks[$i].$compiled_tags[$i];              if ($compiled_tags[$i] == '') {
317                    // tag result empty, remove first newline from following text block
318                    $text_blocks[$i+1] = preg_replace('!^(\r\n|\r|\n)!', '', $text_blocks[$i+1]);
319                }
320                $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
321          }          }
322          $template_compiled .= $text_blocks[$i];          $compiled_content .= $text_blocks[$i];
323    
324          /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */          /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
325          if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $template_compiled, $match)) {          if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $compiled_content, $_match)) {
326              $strip_tags = $match[0];              $strip_tags = $_match[0];
327              $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);              $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
328              $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);              $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
329              for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)              for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)
330                  $template_compiled = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",                  $compiled_content = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
331                                                    $this->quote_replace($strip_tags_modified[$i]),                                                    $this->_quote_replace($strip_tags_modified[$i]),
332                                                    $template_compiled, 1);                                                    $compiled_content, 1);
333          }          }
334    
335          // remove \n from the end of the file, if any          // remove \n from the end of the file, if any
336          if ($template_compiled{strlen($template_compiled) - 1} == "\n" ) {          if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
337              $template_compiled = substr($template_compiled, 0, -1);              $compiled_content = substr($compiled_content, 0, -1);
338            }
339    
340            if (!empty($this->_cache_serial)) {
341                $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
342          }          }
343    
344            // remove unnecessary close/open tags
345            $compiled_content = preg_replace('!\?>\n?<\?php!', '', $compiled_content);
346    
347          // run compiled template through postfilter functions          // run compiled template through postfilter functions
348          if (count($this->_plugins['postfilter']) > 0) {          if (count($this->_plugins['postfilter']) > 0) {
349              foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {              foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
350                  if ($postfilter === false) continue;                  if ($postfilter === false) continue;
351                  if ($postfilter[3] || function_exists($postfilter[0])) {                  if ($postfilter[3] || is_callable($postfilter[0])) {
352                      $template_compiled = $postfilter[0]($template_compiled, $this);                      $compiled_content = call_user_func_array($postfilter[0],
353                                                                  array($compiled_content, &$this));
354                      $this->_plugins['postfilter'][$filter_name][3] = true;                      $this->_plugins['postfilter'][$filter_name][3] = true;
355                  } else {                  } else {
356                      $this->_trigger_plugin_error("Smarty plugin error: postfilter '$filter_name' is not implemented");                      $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
357                  }                  }
358              }              }
359          }          }
360    
361          // put header at the top of the compiled template          // put header at the top of the compiled template
362          $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";          $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
363          $template_header .= "         compiled from ".$tpl_file." */ ?>\n";          $template_header .= "         compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
364    
365          /* Emit code to load needed plugins. */          /* Emit code to load needed plugins. */
366            $this->_plugins_code = '';
367          if (count($this->_plugin_info)) {          if (count($this->_plugin_info)) {
368              $plugins_code = '<?php $this->_load_plugins(array(';              $_plugins_params = "array('plugins' => array(";
369              foreach ($this->_plugin_info as $plugin_type => $plugins) {              foreach ($this->_plugin_info as $plugin_type => $plugins) {
370                  foreach ($plugins as $plugin_name => $plugin_info) {                  foreach ($plugins as $plugin_name => $plugin_info) {
371                      $plugins_code .= "\narray('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], ";                      $_plugins_params .= "array('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], ";
372                      $plugins_code .= $plugin_info[2] ? 'true),' : 'false),';                      $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
373                  }                  }
374              }              }
375              $plugins_code .= ")); ?>";              $_plugins_params .= '))';
376                $plugins_code = "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
377              $template_header .= $plugins_code;              $template_header .= $plugins_code;
378              $this->_plugin_info = array();              $this->_plugin_info = array();
379                $this->_plugins_code = $plugins_code;
380          }          }
381    
382          if ($this->_init_smarty_vars) {          if ($this->_init_smarty_vars) {
383              $template_header .= "<?php \$this->_assign_smarty_interface(); ?>\n";              $template_header .= "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
384              $this->_init_smarty_vars = false;              $this->_init_smarty_vars = false;
385          }          }
386    
387          $template_compiled = $template_header . $template_compiled;          $compiled_content = $template_header . $compiled_content;
   
388          return true;          return true;
389      }      }
390    
391        /**
392  /*======================================================================*\       * Compile a template tag
393      Function: _compile_tag       *
394      Purpose:  Compile a template tag       * @param string $template_tag
395  \*======================================================================*/       * @return string
396         */
397      function _compile_tag($template_tag)      function _compile_tag($template_tag)
398      {      {
399          /* Matched comment. */          /* Matched comment. */
400          if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')          if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
401              return '';              return '';
402    
403          $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';          /* Split tag into two three parts: command, command modifiers and the arguments. */
404            if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp
405                    . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
406                          (?:\s+(.*))?$
407                        /xs', $template_tag, $match)) {
408                $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
409            }
410    
         /* Split tag into two parts: command and the arguments. */  
         preg_match('/^(  
                        (?: ' . $qstr_regexp . ' | (?>[^"\'\s]+))+  
                       )  
                       (?:\s+(.*))?  
                     /xs', $template_tag, $match);  
411          $tag_command = $match[1];          $tag_command = $match[1];
412          $tag_args = isset($match[2]) ? $match[2] : '';          $tag_modifier = isset($match[2]) ? $match[2] : null;
413            $tag_args = isset($match[3]) ? $match[3] : null;
414    
415            if (preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$!', $tag_command)) {
416                /* tag name is a variable or object */
417                $_return = $this->_parse_var_props($tag_command . $tag_modifier, $this->_parse_attrs($tag_args));
418                if(isset($_tag_attrs['assign'])) {
419                    return "<?php \$this->assign('" . $this->_dequote($_tag_attrs['assign']) . "', $_return ); ?>\n";
420                } else {
421                    return "<?php echo $_return; ?>" . $this->_additional_newline;
422                }
423            }
424    
425          /* If the tag name matches a variable or section property definition,          /* If the tag name is a registered object, we process it. */
426             we simply process it. */          if (preg_match('!^\/?' . $this->_reg_obj_regexp . '$!', $tag_command)) {
427          if (preg_match('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) ||   // if a variable              return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
             preg_match('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)     ||  // or a configuration variable  
             preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) {    // or a section property  
             settype($tag_command, 'array');  
             $this->_parse_vars_props($tag_command);  
             return "<?php echo $tag_command[0]; ?>\n";  
428          }          }
429    
430          switch ($tag_command) {          switch ($tag_command) {
# Line 251  class Smarty_Compiler extends Smarty { Line 435  class Smarty_Compiler extends Smarty {
435                  return $this->_compile_include_php_tag($tag_args);                  return $this->_compile_include_php_tag($tag_args);
436    
437              case 'if':              case 'if':
438                    $this->_push_tag('if');
439                  return $this->_compile_if_tag($tag_args);                  return $this->_compile_if_tag($tag_args);
440    
441              case 'else':              case 'else':
442                    list($_open_tag) = end($this->_tag_stack);
443                    if ($_open_tag != 'if' && $_open_tag != 'elseif')
444                        $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
445                    else
446                        $this->_push_tag('else');
447                  return '<?php else: ?>';                  return '<?php else: ?>';
448    
449              case 'elseif':              case 'elseif':
450                    list($_open_tag) = end($this->_tag_stack);
451                    if ($_open_tag != 'if' && $_open_tag != 'elseif')
452                        $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
453                    if ($_open_tag == 'if')
454                        $this->_push_tag('elseif');
455                  return $this->_compile_if_tag($tag_args, true);                  return $this->_compile_if_tag($tag_args, true);
456    
457              case '/if':              case '/if':
458                    $this->_pop_tag('if');
459                  return '<?php endif; ?>';                  return '<?php endif; ?>';
460    
461              case 'capture':              case 'capture':
# Line 275  class Smarty_Compiler extends Smarty { Line 471  class Smarty_Compiler extends Smarty {
471                  return $this->right_delimiter;                  return $this->right_delimiter;
472    
473              case 'section':              case 'section':
474                  array_push($this->_sectionelse_stack, false);                  $this->_push_tag('section');
475                  return $this->_compile_section_start($tag_args);                  return $this->_compile_section_start($tag_args);
476    
477              case 'sectionelse':              case 'sectionelse':
478                  $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;                  $this->_push_tag('sectionelse');
479                  return "<?php endfor; else: ?>";                  return "<?php endfor; else: ?>";
480                    break;
481    
482              case '/section':              case '/section':
483                  if (array_pop($this->_sectionelse_stack))                  $_open_tag = $this->_pop_tag('section');
484                    if ($_open_tag == 'sectionelse')
485                      return "<?php endif; ?>";                      return "<?php endif; ?>";
486                  else                  else
487                      return "<?php endfor; endif; ?>";                      return "<?php endfor; endif; ?>";
488    
489              case 'foreach':              case 'foreach':
490                  array_push($this->_foreachelse_stack, false);                  $this->_push_tag('foreach');
491                  return $this->_compile_foreach_start($tag_args);                  return $this->_compile_foreach_start($tag_args);
492                  break;                  break;
493    
494              case 'foreachelse':              case 'foreachelse':
495                  $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true;                  $this->_push_tag('foreachelse');
496                  return "<?php endforeach; else: ?>";                  return "<?php endforeach; unset(\$_from); else: ?>";
497    
498              case '/foreach':              case '/foreach':
499                  if (array_pop($this->_foreachelse_stack))                  $_open_tag = $this->_pop_tag('foreach');
500                    if ($_open_tag == 'foreachelse')
501                      return "<?php endif; ?>";                      return "<?php endif; ?>";
502                  else                  else
503                      return "<?php endforeach; endif; ?>";                      return "<?php endforeach; unset(\$_from); endif; ?>";
504                    break;
             case 'config_load':  
                 return $this->_compile_config_load_tag($tag_args);  
505    
506              case 'strip':              case 'strip':
507              case '/strip':              case '/strip':
508                  return $this->left_delimiter.$tag_command.$this->right_delimiter;                  if ($tag_command{0}=='/') {
509                        $this->_pop_tag('strip');
510              case 'literal':                      if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
511                  list (,$literal_block) = each($this->_literal_blocks);                          $this->_additional_newline = "\n";
512                  $this->_current_line_no += substr_count($literal_block, "\n");                          return $this->left_delimiter.$tag_command.$this->right_delimiter;
513                  return "<?php echo '".str_replace("'", "\'", str_replace("\\", "\\\\", $literal_block))."'; ?>\n";                      }
514                    } else {
515                        $this->_push_tag('strip');
516                        if ($this->_strip_depth++==0) { /* outermost opening {strip} */
517                            $this->_additional_newline = "";
518                            return $this->left_delimiter.$tag_command.$this->right_delimiter;
519                        }
520                    }
521                    return '';
522    
523              case 'php':              case 'php':
524                  if ($this->security && !$this->security_settings['PHP_TAGS']) {                  /* handle folded tags replaced by {php} */
525                      $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING);                  list(, $block) = each($this->_folded_blocks);
526                      return;                  $this->_current_line_no += substr_count($block[0], "\n");
527                  }                  /* the number of matched elements in the regexp in _compile_file()
528                  list (,$php_block) = each($this->_php_blocks);                     determins the type of folded tag that was found */
529                  $this->_current_line_no += substr_count($php_block, "\n");                  switch (count($block)) {
530                  return '<?php '.$php_block.' ?>';                      case 2: /* comment */
531                            return '';
532    
533                        case 3: /* literal */
534                            return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
535    
536                        case 4: /* php */
537                            if ($this->security && !$this->security_settings['PHP_TAGS']) {
538                                $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
539                                return;
540                            }
541                            return '<?php ' . $block[3] .' ?>';
542                    }
543                    break;
544    
545              case 'insert':              case 'insert':
546                  return $this->_compile_insert_tag($tag_args);                  return $this->_compile_insert_tag($tag_args);
# Line 330  class Smarty_Compiler extends Smarty { Line 548  class Smarty_Compiler extends Smarty {
548              default:              default:
549                  if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {                  if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
550                      return $output;                      return $output;
551                  } else if ($this->_compile_block_tag($tag_command, $tag_args, $output)) {                  } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
552                      return $output;                      return $output;
553                    } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
554                        return $output;                    
555                  } else {                  } else {
556                      return $this->_compile_custom_tag($tag_command, $tag_args);                      $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
557                  }                  }
558    
559          }          }
560      }      }
561    
562    
563  /*======================================================================*\      /**
564      Function: _compile_compiler_tag       * compile the custom compiler tag
565      Purpose:  compile the custom compiler tag       *
566  \*======================================================================*/       * sets $output to the compiled custom compiler tag
567         * @param string $tag_command
568         * @param string $tag_args
569         * @param string $output
570         * @return boolean
571         */
572      function _compile_compiler_tag($tag_command, $tag_args, &$output)      function _compile_compiler_tag($tag_command, $tag_args, &$output)
573      {      {
574          $found = false;          $found = false;
# Line 355  class Smarty_Compiler extends Smarty { Line 581  class Smarty_Compiler extends Smarty {
581          if (isset($this->_plugins['compiler'][$tag_command])) {          if (isset($this->_plugins['compiler'][$tag_command])) {
582              $found = true;              $found = true;
583              $plugin_func = $this->_plugins['compiler'][$tag_command][0];              $plugin_func = $this->_plugins['compiler'][$tag_command][0];
584              if (!function_exists($plugin_func)) {              if (!is_callable($plugin_func)) {
585                  $message = "compiler function '$tag_command' is not implemented";                  $message = "compiler function '$tag_command' is not implemented";
586                  $have_function = false;                  $have_function = false;
587              }              }
# Line 370  class Smarty_Compiler extends Smarty { Line 596  class Smarty_Compiler extends Smarty {
596              include_once $plugin_file;              include_once $plugin_file;
597    
598              $plugin_func = 'smarty_compiler_' . $tag_command;              $plugin_func = 'smarty_compiler_' . $tag_command;
599              if (!function_exists($plugin_func)) {              if (!is_callable($plugin_func)) {
600                  $message = "plugin function $plugin_func() not found in $plugin_file\n";                  $message = "plugin function $plugin_func() not found in $plugin_file\n";
601                  $have_function = false;                  $have_function = false;
602              } else {              } else {
603                  $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null);                  $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
604              }              }
605          }          }
606    
# Line 386  class Smarty_Compiler extends Smarty { Line 612  class Smarty_Compiler extends Smarty {
612           */           */
613          if ($found) {          if ($found) {
614              if ($have_function) {              if ($have_function) {
615                  $output = '<?php ' . $plugin_func($tag_args, $this) . ' ?>';                  $output = call_user_func_array($plugin_func, array($tag_args, &$this));
616                    if($output != '') {
617                    $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
618                                       . $output
619                                       . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
620                    }
621              } else {              } else {
622                  $this->_syntax_error($message, E_USER_WARNING);                  $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
623              }              }
624              return true;              return true;
625          } else {          } else {
# Line 397  class Smarty_Compiler extends Smarty { Line 628  class Smarty_Compiler extends Smarty {
628      }      }
629    
630    
631  /*======================================================================*\      /**
632      Function: _compile_block_tag       * compile block function tag
633      Purpose:  compile block function tag       *
634  \*======================================================================*/       * sets $output to compiled block function tag
635      function _compile_block_tag($tag_command, $tag_args, &$output)       * @param string $tag_command
636         * @param string $tag_args
637         * @param string $tag_modifier
638         * @param string $output
639         * @return boolean
640         */
641        function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
642      {      {
643          if ($tag_command{0} == '/') {          if ($tag_command{0} == '/') {
644              $start_tag = false;              $start_tag = false;
# Line 419  class Smarty_Compiler extends Smarty { Line 656  class Smarty_Compiler extends Smarty {
656          if (isset($this->_plugins['block'][$tag_command])) {          if (isset($this->_plugins['block'][$tag_command])) {
657              $found = true;              $found = true;
658              $plugin_func = $this->_plugins['block'][$tag_command][0];              $plugin_func = $this->_plugins['block'][$tag_command][0];
659              if (!function_exists($plugin_func)) {              if (!is_callable($plugin_func)) {
660                  $message = "block function '$tag_command' is not implemented";                  $message = "block function '$tag_command' is not implemented";
661                  $have_function = false;                  $have_function = false;
662              }              }
# Line 438  class Smarty_Compiler extends Smarty { Line 675  class Smarty_Compiler extends Smarty {
675                  $message = "plugin function $plugin_func() not found in $plugin_file\n";                  $message = "plugin function $plugin_func() not found in $plugin_file\n";
676                  $have_function = false;                  $have_function = false;
677              } else {              } else {
678                  $this->_plugins['block'][$tag_command] = array($plugin_func, null, null);                  $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
679    
680              }              }
681          }          }
682    
683          if (!$found) {          if (!$found) {
684              return false;              return false;
685          } else if (!$have_function) {          } else if (!$have_function) {
686              $this->_syntax_error($message, E_USER_WARNING);              $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
687              return true;              return true;
688          }          }
689    
# Line 456  class Smarty_Compiler extends Smarty { Line 694  class Smarty_Compiler extends Smarty {
694           */           */
695          $this->_add_plugin('block', $tag_command);          $this->_add_plugin('block', $tag_command);
696    
697            if ($start_tag)
698                $this->_push_tag($tag_command);
699            else
700                $this->_pop_tag($tag_command);
701    
702          if ($start_tag) {          if ($start_tag) {
703              $arg_list = array();              $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
704              $attrs = $this->_parse_attrs($tag_args);              $attrs = $this->_parse_attrs($tag_args);
705              foreach ($attrs as $arg_name => $arg_value) {              $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs='');
706                  if (is_bool($arg_value))              $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
707                      $arg_value = $arg_value ? 'true' : 'false';              $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);';
708                  $arg_list[] = "'$arg_name' => $arg_value";              $output .= 'while ($_block_repeat) { ob_start(); ?>';
             }  
   
             $output = "<?php \$this->_tag_stack[] = array('$tag_command', array(".implode(',', (array)$arg_list).")); \$this->_plugins['block']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), null, \$this); ob_start(); ?>";  
709          } else {          } else {
710              $output = "<?php \$this->_block_content = ob_get_contents(); ob_end_clean(); \$this->_plugins['block']['$tag_command'][0](\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_block_content, \$this); array_pop(\$this->_tag_stack); ?>";              $output = '<?php $this->_block_content = ob_get_contents(); ob_end_clean(); ';
711                $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $this->_block_content, $this, $_block_repeat=false)';
712                if ($tag_modifier != '') {
713                    $this->_parse_modifiers($_out_tag_text, $tag_modifier);
714                }
715                $output .= 'echo '.$_out_tag_text.'; } ';
716                $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
717          }          }
718    
719          return true;          return true;
720      }      }
721    
722    
723  /*======================================================================*\      /**
724      Function: _compile_custom_tag       * compile custom function tag
725      Purpose:  compile custom function tag       *
726  \*======================================================================*/       * @param string $tag_command
727      function _compile_custom_tag($tag_command, $tag_args)       * @param string $tag_args
728         * @param string $tag_modifier
729         * @return string
730         */
731        function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
732      {      {
733            $found = false;
734            $have_function = true;
735    
736            /*
737             * First we check if the custom function has already been registered
738             * or loaded from a plugin file.
739             */
740            if (isset($this->_plugins['function'][$tag_command])) {
741                $found = true;
742                $plugin_func = $this->_plugins['function'][$tag_command][0];
743                if (!is_callable($plugin_func)) {
744                    $message = "custom function '$tag_command' is not implemented";
745                    $have_function = false;
746                }
747            }
748            /*
749             * Otherwise we need to load plugin file and look for the function
750             * inside it.
751             */
752            else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
753                $found = true;
754    
755                include_once $plugin_file;
756    
757                $plugin_func = 'smarty_function_' . $tag_command;
758                if (!function_exists($plugin_func)) {
759                    $message = "plugin function $plugin_func() not found in $plugin_file\n";
760                    $have_function = false;
761                } else {
762                    $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
763    
764                }
765            }
766    
767            if (!$found) {
768                return false;
769            } else if (!$have_function) {
770                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
771                return true;
772            }
773    
774            /* declare plugin to be loaded on display of the template that
775               we compile right now */
776          $this->_add_plugin('function', $tag_command);          $this->_add_plugin('function', $tag_command);
777    
778          $arg_list = array();          $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
779          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
780          foreach ($attrs as $arg_name => $arg_value) {          $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs='');
781              if (is_bool($arg_value))  
782                  $arg_value = $arg_value ? 'true' : 'false';          $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
783              $arg_list[] = "'$arg_name' => $arg_value";          if($tag_modifier != '') {
784                $this->_parse_modifiers($output, $tag_modifier);
785          }          }
786    
787          return "<?php \$this->_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); if(\$this->_extract) { extract(\$this->_tpl_vars); \$this->_extract=false; } ?>";          if($output != '') {
788                $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
789                    . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
790            }
791    
792            return true;
793      }      }
794    
795        /**
796         * compile a registered object tag
797         *
798         * @param string $tag_command
799         * @param array $attrs
800         * @param string $tag_modifier
801         * @return string
802         */
803        function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
804        {
805            if ($tag_command{0} == '/') {
806                $start_tag = false;
807                $tag_command = substr($tag_command, 1);
808            } else {
809                $start_tag = true;
810            }
811    
812            list($object, $obj_comp) = explode('->', $tag_command);
813    
814            $arg_list = array();
815            if(count($attrs)) {
816                $_assign_var = false;
817                foreach ($attrs as $arg_name => $arg_value) {
818                    if($arg_name == 'assign') {
819                        $_assign_var = $arg_value;
820                        unset($attrs['assign']);
821                        continue;
822                    }
823                    if (is_bool($arg_value))
824                        $arg_value = $arg_value ? 'true' : 'false';
825                    $arg_list[] = "'$arg_name' => $arg_value";
826                }
827            }
828    
829            if($this->_reg_objects[$object][2]) {
830                // smarty object argument format
831                $args = "array(".implode(',', (array)$arg_list)."), \$this";
832            } else {
833                // traditional argument format
834                $args = implode(',', array_values($attrs));
835                if (empty($args)) {
836                    $args = 'null';
837                }
838            }
839    
840            $prefix = '';
841            $postfix = '';
842            $newline = '';
843            if(!is_object($this->_reg_objects[$object][0])) {
844                $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
845            } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
846                $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
847            } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
848                // method
849                if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
850                    // block method
851                    if ($start_tag) {
852                        $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
853                        $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); ";
854                        $prefix .= "while (\$_block_repeat) { ob_start();";
855                        $return = null;
856                        $postfix = '';
857                } else {
858                        $prefix = "\$this->_obj_block_content = ob_get_contents(); ob_end_clean(); ";
859                        $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_obj_block_content, \$this, \$_block_repeat=false)";
860                        $postfix = "} array_pop(\$this->_tag_stack);";
861                    }
862                } else {
863                    // non-block method
864                    $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
865                }
866            } else {
867                // property
868                $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
869            }
870    
871            if($return != null) {
872                if($tag_modifier != '') {
873                    $this->_parse_modifiers($return, $tag_modifier);
874                }
875    
876  /*======================================================================*\              if(!empty($_assign_var)) {
877      Function: _compile_insert_tag                  $output = "\$this->assign('" . $this->_dequote($_assign_var) ."',  $return);";
878      Purpose:  Compile {insert ...} tag              } else {
879  \*======================================================================*/                  $output = 'echo ' . $return . ';';
880                    $newline = $this->_additional_newline;
881                }
882            } else {
883                $output = '';
884            }
885    
886            return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
887        }
888    
889        /**
890         * Compile {insert ...} tag
891         *
892         * @param string $tag_args
893         * @return string
894         */
895      function _compile_insert_tag($tag_args)      function _compile_insert_tag($tag_args)
896      {      {
897          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
898          $name = $this->_dequote($attrs['name']);          $name = $this->_dequote($attrs['name']);
899    
900          if (empty($name)) {          if (empty($name)) {
901              $this->_syntax_error("missing insert name");              $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
902          }          }
903    
904          if (!empty($attrs['script'])) {          if (!empty($attrs['script'])) {
905              $delayed_loading = true;              $delayed_loading = true;
906            } else {
907                $delayed_loading = false;
908          }          }
909    
910          foreach ($attrs as $arg_name => $arg_value) {          foreach ($attrs as $arg_name => $arg_value) {
# Line 519  class Smarty_Compiler extends Smarty { Line 915  class Smarty_Compiler extends Smarty {
915    
916          $this->_add_plugin('insert', $name, $delayed_loading);          $this->_add_plugin('insert', $name, $delayed_loading);
917    
918          return "<?php echo \$this->_run_insert_handler(array(".implode(', ', (array)$arg_list).")); ?>\n";          $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
     }  
   
919    
920  /*======================================================================*\          return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
     Function: _compile_config_load_tag  
     Purpose:  Compile {config_load ...} tag  
 \*======================================================================*/  
     function _compile_config_load_tag($tag_args)  
     {  
         $attrs = $this->_parse_attrs($tag_args);  
   
         if (empty($attrs['file'])) {  
             $this->_syntax_error("missing 'file' attribute in config_load tag");  
         }  
   
         if (empty($attrs['section'])) {  
             $attrs['section'] = 'null';  
         }  
   
         $scope = @$this->_dequote($attrs['scope']);  
         if (!empty($scope)) {  
             if ($scope != 'local' &&  
                 $scope != 'parent' &&  
                 $scope != 'global') {  
                 $this->_syntax_error("invalid 'scope' attribute value");  
             }  
         } else {  
             if (!empty($attrs['global']) && $attrs['global'])  
                 $scope = 'parent';  
             else  
                 $scope = 'local';  
         }  
   
         $output  = '<?php $this->_config_load(' . $attrs['file'] . ', ' . $attrs['section'] . ", '$scope'); ?>";  
   
         return $output;  
921      }      }
922    
923        /**
924  /*======================================================================*\       * Compile {include ...} tag
925      Function: _compile_include_tag       *
926      Purpose:  Compile {include ...} tag       * @param string $tag_args
927  \*======================================================================*/       * @return string
928         */
929      function _compile_include_tag($tag_args)      function _compile_include_tag($tag_args)
930      {      {
931          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
932          $arg_list = array();          $arg_list = array();
933    
934          if (empty($attrs['file'])) {          if (empty($attrs['file'])) {
935              $this->_syntax_error("missing 'file' attribute in include tag");              $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
936          }          }
937    
938          foreach ($attrs as $arg_name => $arg_value) {          foreach ($attrs as $arg_name => $arg_value) {
# Line 588  class Smarty_Compiler extends Smarty { Line 951  class Smarty_Compiler extends Smarty {
951          $output = '<?php ';          $output = '<?php ';
952    
953          if (isset($assign_var)) {          if (isset($assign_var)) {
954                          $output .= "ob_start();\n";              $output .= "ob_start();\n";
955          }          }
956    
957          $output .=            $output .=
958              "\$_smarty_tpl_vars = \$this->_tpl_vars;\n" .              "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
959              "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."));\n" .  
960              "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .  
961              "unset(\$_smarty_tpl_vars);\n";          $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
962            $output .= "\$this->_smarty_include($_params);\n" .
963            "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
964            "unset(\$_smarty_tpl_vars);\n";
965    
966          if (isset($assign_var)) {          if (isset($assign_var)) {
967                          $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";              $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
968          }          }
969    
970          $output .= ' ?>';          $output .= ' ?>';
971    
972                  return $output;          return $output;
973    
974      }      }
975    
976  /*======================================================================*\      /**
977      Function: _compile_include_php_tag       * Compile {include ...} tag
978      Purpose:  Compile {include ...} tag       *
979  \*======================================================================*/       * @param string $tag_args
980         * @return string
981         */
982      function _compile_include_php_tag($tag_args)      function _compile_include_php_tag($tag_args)
983      {      {
984          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
985    
986          if (empty($attrs['file'])) {          if (empty($attrs['file'])) {
987              $this->_syntax_error("missing 'file' attribute in include_php tag");              $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
988          }          }
989    
990          $assign_var = $this->_dequote($attrs['assign']);          $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
991            $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
992    
993                  $once_var = ( $attrs['once'] === false ) ? 'false' : 'true';          $arg_list = array();
994                                            foreach($attrs as $arg_name => $arg_value) {
995                  return "<?php \$this->_smarty_include_php($attrs[file], '$assign_var', $once_var); ?>";              if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
996                    if(is_bool($arg_value))
997                        $arg_value = $arg_value ? 'true' : 'false';
998                    $arg_list[] = "'$arg_name' => $arg_value";
999                }
1000            }
1001    
1002            $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
1003    
1004            return "<?php require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
1005      }      }
           
1006    
1007  /*======================================================================*\  
1008      Function: _compile_section_start      /**
1009      Purpose:  Compile {section ...} tag       * Compile {section ...} tag
1010  \*======================================================================*/       *
1011         * @param string $tag_args
1012         * @return string
1013         */
1014      function _compile_section_start($tag_args)      function _compile_section_start($tag_args)
1015      {      {
1016          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
1017          $arg_list = array();          $arg_list = array();
1018    
1019          $output = "<?php ";          $output = '<?php ';
1020          $section_name = $attrs['name'];          $section_name = $attrs['name'];
1021          if (empty($section_name)) {          if (empty($section_name)) {
1022              $this->_syntax_error("missing section name");              $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
1023          }          }
1024    
1025          $output .= "if (isset(\$this->_sections[$section_name])) unset(\$this->_sections[$section_name]);\n";          $output .= "unset(\$this->_sections[$section_name]);\n";
1026          $section_props = "\$this->_sections[$section_name]";          $section_props = "\$this->_sections[$section_name]";
1027    
1028          foreach ($attrs as $attr_name => $attr_value) {          foreach ($attrs as $attr_name => $attr_value) {
1029              switch ($attr_name) {              switch ($attr_name) {
1030                  case 'loop':                  case 'loop':
1031                      $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : max(0, (int)$attr_value);\n";                      $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
1032                      break;                      break;
1033    
1034                  case 'show':                  case 'show':
# Line 673  class Smarty_Compiler extends Smarty { Line 1053  class Smarty_Compiler extends Smarty {
1053                      break;                      break;
1054    
1055                  default:                  default:
1056                      $this->_syntax_error("unknown section attribute - '$attr_name'");                      $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
1057                      break;                      break;
1058              }              }
1059          }          }
# Line 729  class Smarty_Compiler extends Smarty { Line 1109  class Smarty_Compiler extends Smarty {
1109          return $output;          return $output;
1110      }      }
1111    
1112        
1113  /*======================================================================*\      /**
1114      Function: _compile_foreach_start       * Compile {foreach ...} tag.
1115      Purpose:  Compile {foreach ...} tag       *
1116  \*======================================================================*/       * @param string $tag_args
1117         * @return string
1118         */
1119      function _compile_foreach_start($tag_args)      function _compile_foreach_start($tag_args)
1120      {      {
1121          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
1122          $arg_list = array();          $arg_list = array();
1123    
1124          if (empty($attrs['from'])) {          if (empty($attrs['from'])) {
1125              $this->_syntax_error("missing 'from' attribute");              $this->_syntax_error("missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
1126          }          }
1127    
1128          if (empty($attrs['item'])) {          if (empty($attrs['item'])) {
1129              $this->_syntax_error("missing 'item' attribute");              $this->_syntax_error("missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
1130          }          }
1131    
1132          $from = $attrs['from'];          $from = $attrs['from'];
# Line 774  class Smarty_Compiler extends Smarty { Line 1156  class Smarty_Compiler extends Smarty {
1156          }          }
1157    
1158          if (isset($name)) {          if (isset($name)) {
1159              $output .= "{$foreach_props}['total'] = count((array)$from);\n";              $output .= "{$foreach_props}['total'] = count(\$_from = (array)$from);\n";
1160              $output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";              $output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";
1161              $output .= "if ({$foreach_props}['show']):\n";              $output .= "if ({$foreach_props}['show']):\n";
1162              $output .= "{$foreach_props}['iteration'] = 0;\n";              $output .= "{$foreach_props}['iteration'] = 0;\n";
1163              $output .= "    foreach ((array)$from as $key_part\$this->_tpl_vars['$item']):\n";              $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1164              $output .= "        {$foreach_props}['iteration']++;\n";              $output .= "        {$foreach_props}['iteration']++;\n";
1165              $output .= "        {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";              $output .= "        {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";
1166              $output .= "        {$foreach_props}['last']  = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";              $output .= "        {$foreach_props}['last']  = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
1167          } else {          } else {
1168              $output .= "if (count((array)$from)):\n";              $output .= "if (count(\$_from = (array)$from)):\n";
1169              $output .= "    foreach ((array)$from as $key_part\$this->_tpl_vars['$item']):\n";              $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
1170          }          }
1171          $output .= '?>';          $output .= '?>';
1172    
# Line 792  class Smarty_Compiler extends Smarty { Line 1174  class Smarty_Compiler extends Smarty {
1174      }      }
1175    
1176    
1177  /*======================================================================*\      /**
1178      Function: _compile_capture_tag       * Compile {capture} .. {/capture} tags
1179      Purpose:  Compile {capture} .. {/capture} tags       *
1180  \*======================================================================*/       * @param boolean $start true if this is the {capture} tag
1181         * @param string $tag_args
1182         * @return string
1183         */
1184    
1185      function _compile_capture_tag($start, $tag_args = '')      function _compile_capture_tag($start, $tag_args = '')
1186      {      {
1187          $attrs = $this->_parse_attrs($tag_args);          $attrs = $this->_parse_attrs($tag_args);
# Line 806  class Smarty_Compiler extends Smarty { Line 1192  class Smarty_Compiler extends Smarty {
1192              else              else
1193                  $buffer = "'default'";                  $buffer = "'default'";
1194    
1195                if (isset($attrs['assign']))
1196                    $assign = $attrs['assign'];
1197                else
1198                    $assign = null;
1199              $output = "<?php ob_start(); ?>";              $output = "<?php ob_start(); ?>";
1200              $this->_capture_stack[] = $buffer;              $this->_capture_stack[] = array($buffer, $assign);
1201          } else {          } else {
1202              $buffer = array_pop($this->_capture_stack);              list($buffer, $assign) = array_pop($this->_capture_stack);
1203              $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ob_end_clean(); ?>";              $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
1204                if (isset($assign)) {
1205                    $output .= " \$this->assign($assign, ob_get_contents());";
1206                }
1207                $output .= "ob_end_clean(); ?>";
1208          }          }
1209    
1210          return $output;          return $output;
1211      }      }
1212    
1213        /**
1214  /*======================================================================*\       * Compile {if ...} tag
1215      Function: _compile_if_tag       *
1216      Purpose:  Compile {if ...} tag       * @param string $tag_args
1217  \*======================================================================*/       * @param boolean $elseif if true, uses elseif instead of if
1218         * @return string
1219         */
1220      function _compile_if_tag($tag_args, $elseif = false)      function _compile_if_tag($tag_args, $elseif = false)
1221      {      {
1222    
1223          /* Tokenize args for 'if' tag. */          /* Tokenize args for 'if' tag. */
1224          preg_match_all('/(?:          preg_match_all('/(?>
1225                           "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         | # match all double quoted strings allowing escaped double quotes                  ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
1226                           \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     | # match all single quoted strings allowing escaped single quotes                  ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string
1227                           [(),]                                  | # match parentheses and commas                  \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@    | # valid non-word token
1228                           [^\s(),]+                                # match any other token that is not any of the above                  \b\w+\b                                                        | # valid word token
1229                          )/x', $tag_args, $match);                  \S+                                                           # anything else
1230                    )/x', $tag_args, $match);
1231    
1232          $tokens = $match[0];          $tokens = $match[0];
1233    
1234          $this->_parse_vars_props($tokens);          // make sure we have balanced parenthesis
1235            $token_count = array_count_values($tokens);
1236            if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
1237                $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
1238            }
1239    
1240          $is_arg_stack = array();          $is_arg_stack = array();
1241    
1242          for ($i = 0, $for_max = count($tokens); $i < $for_max; $i++) {          for ($i = 0; $i < count($tokens); $i++) {
1243    
1244              $token = &$tokens[$i];              $token = &$tokens[$i];
1245              switch ($token) {  
1246                switch (strtolower($token)) {
1247                    case '!':
1248                    case '%':
1249                    case '!==':
1250                    case '==':
1251                    case '===':
1252                    case '>':
1253                    case '<':
1254                    case '!=':
1255                    case '<>':
1256                    case '<<':
1257                    case '>>':
1258                    case '<=':
1259                    case '>=':
1260                    case '&&':
1261                    case '||':
1262                    case '|':
1263                    case '^':
1264                    case '&':
1265                    case '~':
1266                    case ')':
1267                    case ',':
1268                    case '+':
1269                    case '-':
1270                    case '*':
1271                    case '/':
1272                    case '@':
1273                        break;
1274    
1275                  case 'eq':                  case 'eq':
1276                      $token = '==';                      $token = '==';
1277                      break;                      break;
# Line 915  class Smarty_Compiler extends Smarty { Line 1347  class Smarty_Compiler extends Smarty {
1347                      break;                      break;
1348    
1349                  default:                  default:
1350                      if($this->security &&                      if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) {
1351                         $i+1 < count($tokens) &&                              // function call
1352                         $tokens[$i+1] == '(' &&                              if($this->security &&
1353                         preg_match('!^[a-zA-Z_]\w+$!', $tokens[$i]) &&                                 !in_array($token, $this->security_settings['IF_FUNCS'])) {
1354                         !in_array($tokens[$i], $this->security_settings['IF_FUNCS'])) {                                  $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
1355                          $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement");                              }
1356                        } elseif(preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$!', $token)) {
1357                            // object or variable
1358                            $token = $this->_parse_var_props($token);
1359                        } elseif(is_numeric($token)) {
1360                            // number, skip it
1361                        } else {
1362                            $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
1363                      }                      }
1364                      break;                      break;
1365              }              }
# Line 933  class Smarty_Compiler extends Smarty { Line 1372  class Smarty_Compiler extends Smarty {
1372      }      }
1373    
1374    
1375  /*======================================================================*\      function _compile_arg_list($type, $name, $attrs, &$cache_code) {
1376      Function: _parse_is_expr          $arg_list = array();
1377      Purpose:  Parse is expression  
1378  \*======================================================================*/          if (isset($type) && isset($name)
1379                && isset($this->_plugins[$type])
1380                && isset($this->_plugins[$type][$name])
1381                && empty($this->_plugins[$type][$name][4])
1382                && is_array($this->_plugins[$type][$name][5])
1383                ) {
1384                /* we have a list of parameters that should be cached */
1385                $_cache_attrs = $this->_plugins[$type][$name][5];
1386                $_count = $this->_cache_attrs_count++;
1387                $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
1388    
1389            } else {
1390                /* no parameters are cached */
1391                $_cache_attrs = null;
1392            }
1393    
1394            foreach ($attrs as $arg_name => $arg_value) {
1395                if (is_bool($arg_value))
1396                    $arg_value = $arg_value ? 'true' : 'false';
1397                if (is_null($arg_value))
1398                    $arg_value = 'null';
1399                if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
1400                    $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
1401                } else {
1402                    $arg_list[] = "'$arg_name' => $arg_value";
1403                }
1404            }
1405            return $arg_list;
1406        }
1407    
1408        /**
1409         * Parse is expression
1410         *
1411         * @param string $is_arg
1412         * @param array $tokens
1413         * @return array
1414         */
1415      function _parse_is_expr($is_arg, $tokens)      function _parse_is_expr($is_arg, $tokens)
1416      {      {
1417          $expr_end = 0;          $expr_end = 0;
# Line 950  class Smarty_Compiler extends Smarty { Line 1425  class Smarty_Compiler extends Smarty {
1425    
1426          switch ($expr_type) {          switch ($expr_type) {
1427              case 'even':              case 'even':
1428                  if (@$tokens[$expr_end] == 'by') {                  if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1429                      $expr_end++;                      $expr_end++;
1430                      $expr_arg = $tokens[$expr_end++];                      $expr_arg = $tokens[$expr_end++];
1431                      $expr = "!(($is_arg / $expr_arg) % $expr_arg)";                      $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1432                  } else                  } else
1433                      $expr = "!($is_arg % 2)";                      $expr = "!(1 & $is_arg)";
1434                  break;                  break;
1435    
1436              case 'odd':              case 'odd':
1437                  if (@$tokens[$expr_end] == 'by') {                  if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
1438                      $expr_end++;                      $expr_end++;
1439                      $expr_arg = $tokens[$expr_end++];                      $expr_arg = $tokens[$expr_end++];
1440                      $expr = "(($is_arg / $expr_arg) % $expr_arg)";                      $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
1441                  } else                  } else
1442                      $expr = "($is_arg % 2)";                      $expr = "(1 & $is_arg)";
1443                  break;                  break;
1444    
1445              case 'div':              case 'div':
1446                  if (@$tokens[$expr_end] == 'by') {                  if (@$tokens[$expr_end] == 'by') {
1447                      $expr_end++;                      $expr_end++;
1448                      $expr_arg = $tokens[$expr_end++];                      $expr_arg = $tokens[$expr_end++];
1449                      $expr = "!($is_arg % $expr_arg)";                      $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
1450                  } else {                  } else {
1451                      $this->_syntax_error("expecting 'by' after 'div'");                      $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
1452                  }                  }
1453                  break;                  break;
1454    
1455              default:              default:
1456                  $this->_syntax_error("unknown 'is' expression - '$expr_type'");                  $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
1457                  break;                  break;
1458          }          }
1459    
# Line 992  class Smarty_Compiler extends Smarty { Line 1467  class Smarty_Compiler extends Smarty {
1467      }      }
1468    
1469    
1470  /*======================================================================*\      /**
1471      Function: _parse_attrs       * Parse attribute string
1472      Purpose:  Parse attribute string       *
1473  \*======================================================================*/       * @param string $tag_args
1474      function _parse_attrs($tag_args, $quote = true)       * @return array
1475         */
1476        function _parse_attrs($tag_args)
1477      {      {
1478    
1479          /* Tokenize tag attributes. */          /* Tokenize tag attributes. */
1480          preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"       |          preg_match_all('/(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
                           \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     | (?>[^"\'=\s]+)  
1481                           )+ |                           )+ |
1482                           [=]                           [=]
1483                          /x', $tag_args, $match);                          /x', $tag_args, $match);
1484          $tokens       = $match[0];          $tokens       = $match[0];
         $var_delims   = array('$', '#', '%');  
1485    
1486          $attrs = array();          $attrs = array();
1487          /* Parse state:          /* Parse state:
# Line 1023  class Smarty_Compiler extends Smarty { Line 1499  class Smarty_Compiler extends Smarty {
1499                          $attr_name = $token;                          $attr_name = $token;
1500                          $state = 1;                          $state = 1;
1501                      } else                      } else
1502                          $this->_syntax_error("invalid attribute name - '$token'");                          $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
1503                      break;                      break;
1504    
1505                  case 1:                  case 1:
# Line 1031  class Smarty_Compiler extends Smarty { Line 1507  class Smarty_Compiler extends Smarty {
1507                      if ($token == '=') {                      if ($token == '=') {
1508                          $state = 2;                          $state = 2;
1509                      } else                      } else
1510                          $this->_syntax_error("expecting '=' after attribute name");                          $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1511                      break;                      break;
1512    
1513                  case 2:                  case 2:
# Line 1040  class Smarty_Compiler extends Smarty { Line 1516  class Smarty_Compiler extends Smarty {
1516                      if ($token != '=') {                      if ($token != '=') {
1517                          /* We booleanize the token if it's a non-quoted possible                          /* We booleanize the token if it's a non-quoted possible
1518                             boolean value. */                             boolean value. */
1519                          if (preg_match('!^(on|yes|true)$!', $token))                          if (preg_match('!^(on|yes|true)$!', $token)) {
1520                              $token = true;                              $token = 'true';
1521                          else if (preg_match('!^(off|no|false)$!', $token))                          } else if (preg_match('!^(off|no|false)$!', $token)) {
1522                              $token = false;                              $token = 'false';
1523                          /* If the token is not variable (doesn't start with                          } else if ($token == 'null') {
1524                             '$', '#', or '%') and not enclosed in single or                              $token = 'null';
1525                             double quotes we single-quote it. */                          } else if (preg_match('!^-?([0-9]+|0[xX][0-9a-fA-F]+)$!', $token)) {
1526                          else if ($quote && !in_array($token{0}, $var_delims) &&                              /* treat integer literally */
1527                                   !(($token{0} == '"' || $token{0} == "'") &&                          } else if (!preg_match('!^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
1528                                   $token{strlen($token)-1} == $token{0}))                              /* treat as a string, double-quote it escaping quotes */
1529                              $token = '"'.$token.'"';                              $token = '"'.addslashes($token).'"';
1530                            }
1531    
1532                          $attrs[$attr_name] = $token;                          $attrs[$attr_name] = $token;
1533                          $state = 0;                          $state = 0;
1534                      } else                      } else
1535                          $this->_syntax_error("'=' cannot be an attribute value");                          $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
1536                      break;                      break;
1537              }              }
1538                $last_token = $token;
1539            }
1540    
1541            if($state != 0) {
1542                if($state == 1) {
1543                    $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
1544                } else {
1545                    $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
1546                }
1547          }          }
1548    
1549          $this->_parse_vars_props($attrs);          $this->_parse_vars_props($attrs);
# Line 1065  class Smarty_Compiler extends Smarty { Line 1551  class Smarty_Compiler extends Smarty {
1551          return $attrs;          return $attrs;
1552      }      }
1553    
1554        /**
1555  /*======================================================================*\       * compile multiple variables and section properties tokens into
1556      Function: _parse_vars_props       * PHP code
1557      Purpose:  compile variables and section properties tokens into       *
1558                PHP code       * @param array $tokens
1559  \*======================================================================*/       */
1560      function _parse_vars_props(&$tokens)      function _parse_vars_props(&$tokens)
1561      {      {
1562          $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';          foreach($tokens as $key => $val) {
1563                $tokens[$key] = $this->_parse_var_props($val);
         $var_exprs = preg_grep('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' .  $qstr_regexp . '|[^|]+))*)*$!', $tokens);  
         $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);  
         $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' .  $qstr_regexp .  '|[^|]+))*)*$!', $tokens);  
   
         if (count($var_exprs)) {  
             foreach ($var_exprs as $expr_index => $var_expr) {  
                 $tokens[$expr_index] = $this->_parse_var($var_expr);  
             }  
1564          }          }
1565        }
1566    
1567          if (count($conf_var_exprs)) {      /**
1568              foreach ($conf_var_exprs as $expr_index => $var_expr) {       * compile single variable and section properties token into
1569                  $tokens[$expr_index] = $this->_parse_conf_var($var_expr);       * PHP code
1570         *
1571         * @param string $val
1572         * @param string $tag_attrs
1573         * @return string
1574         */
1575        function _parse_var_props($val)
1576        {
1577            $val = trim($val);
1578    
1579            if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$!', $val, $match)) {
1580                // $ variable or object
1581                $return = $this->_parse_var($match[1]);
1582                $modifiers = $match[2];
1583                if (!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) {
1584                    $_default_mod_string = implode('|',(array)$this->default_modifiers);
1585                    $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
1586                }
1587                $this->_parse_modifiers($return, $modifiers);
1588                return $return;
1589            } elseif (preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1590                    // double quoted text
1591                    preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
1592                    $return = $this->_expand_quoted_text($match[1]);
1593                    if($match[2] != '') {
1594                        $this->_parse_modifiers($return, $match[2]);
1595                    }
1596                    return $return;
1597              }              }
1598          }          elseif(preg_match('!^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1599                    // numerical constant
1600          if (count($sect_prop_exprs)) {                  preg_match('!^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
1601              foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {                  if($match[2] != '') {
1602                  $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);                      $this->_parse_modifiers($match[1], $match[2]);
1603                        return $match[1];
1604                    }
1605              }              }
1606            elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1607                    // single quoted text
1608                    preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$!', $val, $match);
1609                    if($match[2] != '') {
1610                        $this->_parse_modifiers($match[1], $match[2]);
1611                        return $match[1];
1612                    }
1613                }
1614            elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1615                    // config var
1616                    return $this->_parse_conf_var($val);
1617                }
1618            elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$!', $val)) {
1619                    // section var
1620                    return $this->_parse_section_prop($val);
1621                }
1622            elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
1623                // literal string
1624                return $this->_expand_quoted_text('"' . $val .'"');
1625            }
1626            return $val;
1627        }
1628    
1629        /**
1630         * expand quoted text with embedded variables
1631         *
1632         * @param string $var_expr
1633         * @return string
1634         */
1635        function _expand_quoted_text($var_expr)
1636        {
1637            // if contains unescaped $, expand it
1638            if(preg_match_all('%(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)%', $var_expr, $_match)) {
1639                $_match = $_match[0];
1640                rsort($_match);
1641                reset($_match);
1642                foreach($_match as $_var) {
1643                    $var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr);
1644                }
1645                $_return = preg_replace('%\.""|(?<!\\\\)""\.%', '', $var_expr);
1646            } else {
1647                $_return = $var_expr;
1648          }          }
1649            // replace double quoted literal string with single quotes
1650            $_return = preg_replace('!^"([\s\w]+)"$!',"'\\1'",$_return);
1651            return $_return;
1652      }      }
1653    
1654        /**
1655  /*======================================================================*\       * parse variable expression into PHP code
1656      Function: _parse_var       *
1657      Purpose:  parse variable expression into PHP code       * @param string $var_expr
1658  \*======================================================================*/       * @param string $output
1659         * @return string
1660         */
1661      function _parse_var($var_expr)      function _parse_var($var_expr)
1662      {      {
1663          $parts = explode('|', substr($var_expr, 1), 2);          $_has_math = false;
1664          $var_ref = $parts[0];          $_math_vars = preg_split('!('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')!', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
         $modifiers = isset($parts[1]) ? $parts[1] : '';  
                   
                 if(!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) {  
                         $_default_mod_string = implode('|',(array)$this->default_modifiers);  
                         $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;  
                 }  
                           
         preg_match_all('!\[(?:\$\w+|\w+(\.\w+)?)\]|(->|\.)\$?\w+|^\w+!', $var_ref, $match);  
         $indexes = $match[0];  
         $var_name = array_shift($indexes);  
1665    
1666          /* Handle $smarty.* variable references as a special case. */          if(count($_math_vars) > 1) {
1667          if ($var_name == 'smarty') {              $_first_var = "";
1668              /*              $_complete_var = "";
1669               * If the reference could be compiled, use the compiled output;              $_output = "";
1670               * otherwise, fall back on the $smarty variable generated at              // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
1671               * run-time.              foreach($_math_vars as $_k => $_math_var) {
1672               */                  $_math_var = $_math_vars[$_k];
1673              if (($smarty_ref = $this->_compile_smarty_ref($indexes)) !== null) {  
1674                  $output = $smarty_ref;                  if(!empty($_math_var) || is_numeric($_math_var)) {
1675              } else {                      // hit a math operator, so process the stuff which came before it
1676                  $var_name = substr(array_shift($indexes), 1);                      if(preg_match('!^' . $this->_dvar_math_regexp . '$!', $_math_var)) {
1677                  $output = "\$this->_smarty_vars['$var_name']";                          $_has_math = true;
1678                            if(!empty($_complete_var) || is_numeric($_complete_var)) {
1679                                $_output .= $this->_parse_var($_complete_var);
1680                            }
1681    
1682                            // just output the math operator to php
1683                            $_output .= $_math_var;
1684    
1685                            if(empty($_first_var))
1686                                $_first_var = $_complete_var;
1687    
1688                            $_complete_var = "";
1689                        } else {
1690                            // fetch multiple -> (like $foo->bar->baz ) which wouldn't get fetched else, because it would only get $foo->bar and treat the ->baz as "-" ">baz" then
1691                            for($_i = $_k + 1; $_i <= count($_math_vars); $_i += 2) {
1692                                // fetch -> because it gets splitted at - and move it back together
1693                                if( /* prevent notice */ (isset($_math_vars[$_i]) && isset($_math_vars[$_i+1])) && ($_math_vars[$_i] === '-' && $_math_vars[$_i+1]{0} === '>')) {
1694                                    $_math_var .= $_math_vars[$_i].$_math_vars[$_i+1];
1695                                    $_math_vars[$_i] = $_math_vars[$_i+1] = '';
1696                                } else {
1697                                    break;
1698                                }
1699                            }
1700                            $_complete_var .= $_math_var;
1701                        }
1702                    }
1703                }
1704                if($_has_math) {
1705                    if(!empty($_complete_var) || is_numeric($_complete_var))
1706                        $_output .= $this->_parse_var($_complete_var);
1707    
1708                    // get the modifiers working (only the last var from math + modifier is left)
1709                    $var_expr = $_complete_var;
1710              }              }
         } else {  
             $output = "\$this->_tpl_vars['$var_name']";  
1711          }          }
1712    
1713          foreach ($indexes as $index) {          // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
1714              if ($index{0} == '[') {          if(is_numeric($var_expr{0}))
1715                  $index = substr($index, 1, -1);              $_var_ref = $var_expr;
1716                  if (is_numeric($index)) {          else
1717                      $output .= "[$index]";              $_var_ref = substr($var_expr, 1);
1718                  } elseif ($index{0} == '$') {  
1719                      $output .= "[\$this->_tpl_vars['" . substr($index, 1) . "']]";          if(!$_has_math) {
1720                // get [foo] and .foo and ->foo and (...) pieces
1721                preg_match_all('!(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+!', $_var_ref, $match);
1722    
1723                $_indexes = $match[0];
1724                $_var_name = array_shift($_indexes);
1725    
1726                /* Handle $smarty.* variable references as a special case. */
1727                if ($_var_name == 'smarty') {
1728                    /*
1729                     * If the reference could be compiled, use the compiled output;
1730                     * otherwise, fall back on the $smarty variable generated at
1731                     * run-time.
1732                     */
1733                    if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
1734                        $_output = $smarty_ref;
1735                  } else {                  } else {
1736                      $parts = explode('.', $index);                      $_var_name = substr(array_shift($_indexes), 1);
1737                      $section = $parts[0];                      $_output = "\$this->_smarty_vars['$_var_name']";
1738                      $section_prop = isset($parts[1]) ? $parts[1] : 'index';                  }
1739                      $output .= "[\$this->_sections['$section']['$section_prop']]";              } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) {
1740                  }                  // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
1741              } else if ($index{0} == '.') {                  if(count($_indexes) > 0)
1742                  if ($index{1} == '$')                  {
1743                      $output .= "[\$this->_tpl_vars['" . substr($index, 2) . "']]";                      $_var_name .= implode("", $_indexes);
1744                  else                      $_indexes = array();
1745                      $output .= "['" . substr($index, 1) . "']";                  }
1746                    $_output = $_var_name;
1747              } else {              } else {
1748                  $output .= $index;                  $_output = "\$this->_tpl_vars['$_var_name']";
1749              }              }
         }  
1750    
1751          $this->_parse_modifiers($output, $modifiers);              foreach ($_indexes as $_index) {
1752                    if ($_index{0} == '[') {
1753                        $_index = substr($_index, 1, -1);
1754                        if (is_numeric($_index)) {
1755                            $_output .= "[$_index]";
1756                        } elseif ($_index{0} == '$') {
1757                            if (strpos($_index, '.') !== false) {
1758                                $_output .= '[' . $this->_parse_var($_index) . ']';
1759                            } else {
1760                                $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
1761                            }
1762                        } else {
1763                            $_var_parts = explode('.', $_index);
1764                            $_var_section = $_var_parts[0];
1765                            $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
1766                            $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
1767                        }
1768                    } else if ($_index{0} == '.') {
1769                        if ($_index{1} == '$')
1770                            $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
1771                        else
1772                            $_output .= "['" . substr($_index, 1) . "']";
1773                    } else if (substr($_index,0,2) == '->') {
1774                        if(substr($_index,2,2) == '__') {
1775                            $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1776                        } elseif($this->security && substr($_index, 2, 1) == '_') {
1777                            $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1778                        } elseif ($_index{2} == '$') {
1779                            if ($this->security) {
1780                                $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
1781                            } else {
1782                                $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
1783                            }
1784                        } else {
1785                            $_output .= $_index;
1786                        }
1787                    } elseif ($_index{0} == '(') {
1788                        $_index = $this->_parse_parenth_args($_index);
1789                        $_output .= $_index;
1790                    } else {
1791                        $_output .= $_index;
1792                    }
1793                }
1794            }
1795    
1796          return $output;          return $_output;
1797      }      }
1798    
1799        /**
1800  /*======================================================================*\       * parse arguments in function call parenthesis
1801      Function: _parse_conf_var       *
1802      Purpose:  parse configuration variable expression into PHP code       * @param string $parenth_args
1803  \*======================================================================*/       * @return string
1804         */
1805        function _parse_parenth_args($parenth_args)
1806        {
1807            preg_match_all('!' . $this->_param_regexp . '!',$parenth_args, $match);
1808            $match = $match[0];
1809            rsort($match);
1810            reset($match);
1811            $orig_vals = $match;
1812            $this->_parse_vars_props($match);
1813            return str_replace($orig_vals, $match, $parenth_args);
1814        }
1815    
1816        /**
1817         * parse configuration variable expression into PHP code
1818         *
1819         * @param string $conf_var_expr
1820         */
1821      function _parse_conf_var($conf_var_expr)      function _parse_conf_var($conf_var_expr)
1822      {      {
1823          $parts = explode('|', $conf_var_expr, 2);          $parts = explode('|', $conf_var_expr, 2);
# Line 1183  class Smarty_Compiler extends Smarty { Line 1833  class Smarty_Compiler extends Smarty {
1833          return $output;          return $output;
1834      }      }
1835    
1836        /**
1837  /*======================================================================*\       * parse section property expression into PHP code
1838      Function: _parse_section_prop       *
1839      Purpose:  parse section property expression into PHP code       * @param string $section_prop_expr
1840  \*======================================================================*/       * @return string
1841         */
1842      function _parse_section_prop($section_prop_expr)      function _parse_section_prop($section_prop_expr)
1843      {      {
1844          $parts = explode('|', $section_prop_expr, 2);          $parts = explode('|', $section_prop_expr, 2);
# Line 1206  class Smarty_Compiler extends Smarty { Line 1857  class Smarty_Compiler extends Smarty {
1857      }      }
1858    
1859    
1860  /*======================================================================*\      /**
1861      Function: _parse_modifiers       * parse modifier chain into PHP code
1862      Purpose:  parse modifier chain into PHP code       *
1863  \*======================================================================*/       * sets $output to parsed modified chain
1864         * @param string $output
1865         * @param string $modifier_string
1866         */
1867      function _parse_modifiers(&$output, $modifier_string)      function _parse_modifiers(&$output, $modifier_string)
1868      {      {
1869          $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';          preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $_match);
1870          preg_match_all('!\|(@?\w+)((?>:(?:'. $qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $match);          list(, $_modifiers, $modifier_arg_strings) = $_match;
1871          list(, $modifiers, $modifier_arg_strings) = $match;  
1872            for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
1873          for ($i = 0, $for_max = count($modifiers); $i < $for_max; $i++) {              $_modifier_name = $_modifiers[$_i];
1874              $modifier_name = $modifiers[$i];  
1875                                        if($_modifier_name == 'smarty') {
1876                          if($modifier_name == 'smarty') {                  // skip smarty modifier
1877                                  // skip smarty modifier                  continue;
1878                                  continue;              }
1879                          }  
1880                                        preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$_i], $_match);
1881              preg_match_all('!:(' . $qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$i], $match);              $_modifier_args = $_match[1];
1882              $modifier_args = $match[1];  
1883                if ($_modifier_name{0} == '@') {
1884              if ($modifier_name{0} == '@') {                  $_map_array = false;
1885                  $map_array = 'false';                  $_modifier_name = substr($_modifier_name, 1);
                 $modifier_name = substr($modifier_name, 1);  
1886              } else {              } else {
1887                  $map_array = 'true';                  $_map_array = true;
1888                }
1889    
1890                if (empty($this->_plugins['modifier'][$_modifier_name])
1891                    && !$this->_get_plugin_filepath('modifier', $_modifier_name)
1892                    && function_exists($_modifier_name)) {
1893                    if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
1894                        $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
1895                    } else {
1896                        $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);
1897                    }
1898              }              }
1899                                        $this->_add_plugin('modifier', $_modifier_name);
             $this->_add_plugin('modifier', $modifier_name);  
1900    
1901              $this->_parse_vars_props($modifier_args);              $this->_parse_vars_props($_modifier_args);
1902    
1903              if (count($modifier_args) > 0)              if($_modifier_name == 'default') {
1904                  $modifier_args = ', '.implode(', ', $modifier_args);                  // supress notifications of default modifier vars and args
1905                    if($output{0} == '$') {
1906                        $output = '@' . $output;
1907                    }
1908                    if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') {
1909                        $_modifier_args[0] = '@' . $_modifier_args[0];
1910                    }
1911                }
1912                if (count($_modifier_args) > 0)
1913                    $_modifier_args = ', '.implode(', ', $_modifier_args);
1914              else              else
1915                  $modifier_args = '';                  $_modifier_args = '';
1916    
1917                if ($_map_array) {
1918                    $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))";
1919    
1920              $output = "\$this->_run_mod_handler('$modifier_name', $map_array, $output$modifier_args)";              } else {
1921    
1922                    $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
1923    
1924                }
1925          }          }
1926      }      }
1927    
1928    
1929  /*======================================================================*\      /**
1930      Function: _add_plugin       * add plugin
1931      Purpose:         *
1932  \*======================================================================*/       * @param string $type
1933         * @param string $name
1934         * @param boolean? $delayed_loading
1935         */
1936      function _add_plugin($type, $name, $delayed_loading = null)      function _add_plugin($type, $name, $delayed_loading = null)
1937      {      {
1938          if (!isset($this->_plugin_info[$type])) {          if (!isset($this->_plugin_info[$type])) {
# Line 1263  class Smarty_Compiler extends Smarty { Line 1944  class Smarty_Compiler extends Smarty {
1944                                                        $delayed_loading);                                                        $delayed_loading);
1945          }          }
1946      }      }
       
1947    
1948  /*======================================================================*\  
1949      Function: _compile_smarty_ref      /**
1950      Purpose:  Compiles references of type $smarty.foo       * Compiles references of type $smarty.foo
1951  \*======================================================================*/       *
1952         * @param string $indexes
1953         * @return string
1954         */
1955      function _compile_smarty_ref(&$indexes)      function _compile_smarty_ref(&$indexes)
1956      {      {
1957          /* Extract the reference name. */          /* Extract the reference name. */
1958          $ref = substr($indexes[0], 1);          $_ref = substr($indexes[0], 1);
1959            foreach($indexes as $_index_no=>$_index) {
1960                if ($_index{0} != '.' && $_index_no<2 || !preg_match('!^(\.|\[|->)!', $_index)) {
1961                    $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
1962                }
1963            }
1964    
1965          switch ($ref) {          switch ($_ref) {
1966              case 'now':              case 'now':
1967                  $compiled_ref = 'time()';                  $compiled_ref = 'time()';
1968                  if (count($indexes) > 1) {                  $_max_index = 1;
                     $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference');  
                 }  
1969                  break;                  break;
1970    
1971              case 'foreach':              case 'foreach':
1972              case 'section':              case 'section':
                 if ($indexes[1]{0} != '.') {  
                     $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference');  
                 }  
                 $name = substr($indexes[1], 1);  
1973                  array_shift($indexes);                  array_shift($indexes);
1974                  if ($ref == 'foreach')                  $_var = $this->_parse_var_props(substr($indexes[0], 1));
1975                      $compiled_ref = "\$this->_foreach['$name']";                  if ($_ref == 'foreach')
1976                        $compiled_ref = "\$this->_foreach[$_var]";
1977                  else                  else
1978                      $compiled_ref = "\$this->_sections['$name']";                      $compiled_ref = "\$this->_sections[$_var]";
1979                  break;                  break;
1980    
1981              case 'get':              case 'get':
1982                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
                 $compiled_ref = "\$GLOBALS['HTTP_GET_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
1983                  break;                  break;
1984    
1985              case 'post':              case 'post':
1986                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
                 $name = substr($indexes[0], 1);  
                 $compiled_ref = "\$GLOBALS['HTTP_POST_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
1987                  break;                  break;
1988    
1989              case 'cookies':              case 'cookies':
1990                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
                 $name = substr($indexes[0], 1);  
                 $compiled_ref = "\$GLOBALS['HTTP_COOKIE_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
1991                  break;                  break;
1992    
1993              case 'env':              case 'env':
1994                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
                 $compiled_ref = "\$GLOBALS['HTTP_ENV_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
1995                  break;                  break;
1996    
1997              case 'server':              case 'server':
1998                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
                 $name = substr($indexes[0], 1);  
                 $compiled_ref = "\$GLOBALS['HTTP_SERVER_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
1999                  break;                  break;
2000    
2001              case 'session':              case 'session':
2002                  array_shift($indexes);                  $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
                 $name = substr($indexes[0], 1);  
                 $compiled_ref = "\$GLOBALS['HTTP_SESSION_VARS']";  
                 if ($name = substr($indexes[0], 1))  
                     $compiled_ref .= "['$name']";  
2003                  break;                  break;
2004    
2005              /*              /*
# Line 1346  class Smarty_Compiler extends Smarty { Line 2007  class Smarty_Compiler extends Smarty {
2007               * compiler.               * compiler.
2008               */               */
2009              case 'request':              case 'request':
2010                  $this->_init_smarty_vars = true;                  if ($this->request_use_auto_globals) {
2011                        $compiled_ref = '$_REQUEST';
2012                        break;
2013                    } else {
2014                        $this->_init_smarty_vars = true;
2015                    }
2016                  return null;                  return null;
2017    
2018              case 'capture':              case 'capture':
# Line 1354  class Smarty_Compiler extends Smarty { Line 2020  class Smarty_Compiler extends Smarty {
2020    
2021              case 'template':              case 'template':
2022                  $compiled_ref = "'$this->_current_file'";                  $compiled_ref = "'$this->_current_file'";
2023                  if (count($indexes) > 1) {                  $_max_index = 1;
2024                      $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference');                  break;
2025                  }  
2026                case 'version':
2027                    $compiled_ref = "'$this->_version'";
2028                    $_max_index = 1;
2029                    break;
2030    
2031                case 'const':
2032                    array_shift($indexes);
2033                    $_val = $this->_parse_var_props(substr($indexes[0],1));
2034                    $compiled_ref = '@constant(' . $_val . ')';
2035                    $_max_index = 1;
2036                    break;
2037    
2038                case 'config':
2039                    $compiled_ref = "\$this->_config[0]['vars']";
2040                    $_max_index = 3;
2041                  break;                  break;
                                   
                         case 'version':  
                                 $compiled_ref = "'$this->_version'";  
                                 break;  
2042    
2043              default:              default:
2044                  $this->_syntax_error('$smarty.' . $ref . ' is an unknown reference');                  $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
2045                  break;                  break;
2046          }          }
2047    
2048            if (isset($_max_index) && count($indexes) > $_max_index) {
2049                $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
2050            }
2051    
2052          array_shift($indexes);          array_shift($indexes);
2053          return $compiled_ref;          return $compiled_ref;
2054      }      }
2055    
2056        /**
2057         * compiles call to plugin of type $type with name $name
2058         * returns a string containing the function-name or method call
2059         * without the paramter-list that would have follow to make the
2060         * call valid php-syntax
2061         *
2062         * @param string $type
2063         * @param string $name
2064         * @return string
2065         */
2066        function _compile_plugin_call($type, $name) {
2067            if (isset($this->_plugins[$type][$name])) {
2068                /* plugin loaded */
2069                if (is_array($this->_plugins[$type][$name][0])) {
2070                    return ((is_object($this->_plugins[$type][$name][0][0])) ?
2071                            "\$this->_plugins['$type']['$name'][0][0]->"    /* method callback */
2072                            : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */
2073                           ). $this->_plugins[$type][$name][0][1];
2074    
2075  /*======================================================================*\              } else {
2076      Function: _load_filters                  /* function callback */
2077      Purpose:  load pre- and post-filters                  return $this->_plugins[$type][$name][0];
2078  \*======================================================================*/  
2079                }
2080            } else {
2081                /* plugin not loaded -> auto-loadable-plugin */
2082                return 'smarty_'.$type.'_'.$name;
2083    
2084            }
2085        }
2086    
2087        /**
2088         * load pre- and post-filters
2089         */
2090      function _load_filters()      function _load_filters()
2091      {      {
2092          if (count($this->_plugins['prefilter']) > 0) {          if (count($this->_plugins['prefilter']) > 0) {
2093              foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {              foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
2094                  if ($prefilter === false) {                  if ($prefilter === false) {
2095                      unset($this->_plugins['prefilter'][$filter_name]);                      unset($this->_plugins['prefilter'][$filter_name]);
2096                      $this->_load_plugins(array(array('prefilter', $filter_name, null, null, false)));                      $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
2097                        require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
2098                        smarty_core_load_plugins($_params, $this);
2099                  }                  }
2100              }              }
2101          }          }
# Line 1391  class Smarty_Compiler extends Smarty { Line 2103  class Smarty_Compiler extends Smarty {
2103              foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {              foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
2104                  if ($postfilter === false) {                  if ($postfilter === false) {
2105                      unset($this->_plugins['postfilter'][$filter_name]);                      unset($this->_plugins['postfilter'][$filter_name]);
2106                      $this->_load_plugins(array(array('postfilter', $filter_name, null, null, false)));                      $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
2107                        require_once(SMARTY_DIR . 'core' . DIRECTORY_SEPARATOR . 'core.load_plugins.php');
2108                        smarty_core_load_plugins($_params, $this);
2109                  }                  }
2110              }              }
2111          }          }
2112      }      }
2113    
2114    
2115  /*======================================================================*\      /**
2116      Function: _syntax_error       * Quote subpattern references
2117      Purpose:  display Smarty syntax error       *
2118  \*======================================================================*/       * @param string $string
2119      function _syntax_error($error_msg, $error_type = E_USER_ERROR)       * @return string
2120      {       */
2121          trigger_error("Smarty: [in " . $this->_current_file . " line " .      function _quote_replace($string)
2122                        $this->_current_line_no . "]: syntax error: $error_msg", $error_type);      {
2123            return preg_replace('![\\$]\d!', '\\\\\\0', $string);
2124        }
2125    
2126        /**
2127         * display Smarty syntax error
2128         *
2129         * @param string $error_msg
2130         * @param integer $error_type
2131         * @param string $file
2132         * @param integer $line
2133         */
2134        function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
2135        {
2136            $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
2137        }
2138    
2139    
2140        /**
2141         * check if the compilation changes from cacheable to
2142         * non-cacheable state with the beginning of the current
2143         * plugin. return php-code to reflect the transition.
2144         * @return string
2145         */
2146        function _push_cacheable_state($type, $name) {
2147            $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2148            if ($_cacheable
2149                || 0<$this->_cacheable_state++) return '';
2150            if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
2151            $_ret = 'if ($this->caching) { echo \'{nocache:'
2152                . $this->_cache_serial . '#' . $this->_nocache_count
2153                . '}\';}';
2154            return $_ret;
2155        }
2156    
2157    
2158        /**
2159         * check if the compilation changes from non-cacheable to
2160         * cacheable state with the end of the current plugin return
2161         * php-code to reflect the transition.
2162         * @return string
2163         */
2164        function _pop_cacheable_state($type, $name) {
2165            $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
2166            if ($_cacheable
2167                || --$this->_cacheable_state>0) return '';
2168            return 'if ($this->caching) { echo \'{/nocache:'
2169                . $this->_cache_serial . '#' . ($this->_nocache_count++)
2170                . '}\';}';
2171        }
2172    
2173    
2174        /**
2175         * push opening tag-name, file-name and line-number on the tag-stack
2176         * @param: string the opening tag's name
2177         */
2178        function _push_tag($open_tag)
2179        {
2180            array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
2181        }
2182    
2183        /**
2184         * pop closing tag-name
2185         * raise an error if this stack-top doesn't match with the closing tag
2186         * @param: string the closing tag's name
2187         * @return: string the opening tag's name
2188         */
2189        function _pop_tag($close_tag)
2190        {
2191            $message = '';
2192            if (count($this->_tag_stack)>0) {
2193                list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
2194                if ($close_tag == $_open_tag) {
2195                    return $_open_tag;
2196                }
2197                if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
2198                    return $this->_pop_tag($close_tag);
2199                }
2200                if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
2201                    $this->_pop_tag($close_tag);
2202                    return $_open_tag;
2203                }
2204                if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
2205                    $this->_pop_tag($close_tag);
2206                    return $_open_tag;
2207                }
2208                $message = " expected {/$_open_tag} (opened line $_line_no).";
2209            }
2210            $this->_syntax_error("mismatched tag {/$close_tag}.$message",
2211                                 E_USER_ERROR, __FILE__, __LINE__);
2212      }      }
2213    
2214  }  }
2215    
2216    /**
2217     * compare to values by their string length
2218     *
2219     * @access private
2220     * @param string $a
2221     * @param string $b
2222     * @return 0|-1|1
2223     */
2224    function _smarty_sort_length($a, $b)
2225    {
2226        if($a == $b)
2227            return 0;
2228    
2229        if(strlen($a) == strlen($b))
2230            return ($a > $b) ? -1 : 1;
2231    
2232        return (strlen($a) > strlen($b)) ? -1 : 1;
2233    }
2234    
2235    
2236  /* vim: set et: */  /* vim: set et: */
2237    
2238  ?>  ?>

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed