Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_template.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 20.85 KiB


001  <?php
002  /**
003  *
004  * @package phpBB3
005  * @version $Id$
006  * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
008  *
009  */
010   
011  /**
012  * @ignore
013  */
014  if (!defined('IN_PHPBB'))
015  {
016      exit;
017  }
018   
019  /**
020  * Extension of template class - Functions needed for compiling templates only.
021  *
022  * psoTFX, phpBB Development Team - Completion of file caching, decompilation
023  * routines and implementation of conditionals/keywords and associated changes
024  *
025  * The interface was inspired by PHPLib templates,  and the template file (formats are
026  * quite similar)
027  *
028  * The keyword/conditional implementation is currently based on sections of code from
029  * the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
030  * (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
031  * derived from an LGPL application may be relicenced under the GPL, this applies
032  * to this source
033  *
034  * DEFINE directive inspired by a request by Cyberalien
035  *
036  * @package phpBB3
037  */
038  class template_compile
039  {
040      var $template;
041   
042      // Various storage arrays
043      var $block_names = array();
044      var $block_else_level = array();
045   
046      /**
047      * constuctor
048      */
049      function template_compile(&$template)
050      {
051          $this->template = &$template;
052      }
053      
054      /**
055      * Load template source from file
056      * @access private
057      */
058      function _tpl_load_file($handle, $store_in_db = false)
059      {
060          // Try and open template for read
061          if (!file_exists($this->template->files[$handle]))
062          {
063              trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR);
064          }
065   
066          $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle])));
067   
068          // Actually compile the code now.
069          $this->compile_write($handle, $this->template->compiled_code[$handle]);
070   
071          // Store in database if required...
072          if ($store_in_db)
073          {
074              global $db, $user;
075   
076              $sql_ary = array(
077                  'template_id'            => $user->theme['template_id'],
078                  'template_filename'        => $this->template->filename[$handle],
079                  'template_included'        => '',
080                  'template_mtime'        => time(),
081                  'template_data'            => trim(@file_get_contents($this->template->files[$handle])),
082              );
083   
084              $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
085              $db->sql_query($sql);
086          }
087      }
088   
089      /**
090      * Remove any PHP tags that do not belong, these regular expressions are derived from
091      * the ones that exist in zend_language_scanner.l
092      * @access private
093      */
094      function remove_php_tags(&$code)
095      {
096          // This matches the information gathered from the internal PHP lexer
097          $match = array(
098              '#<([\?%])=?.*?\1>#s',
099              '#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s',
100              '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s'
101          );
102   
103          $code = preg_replace($match, '', $code);
104      }
105   
106      /**
107      * The all seeing all doing compile method. Parts are inspired by or directly from Smarty
108      * @access private
109      */
110      function compile($code, $no_echo = false, $echo_var = '')
111      {
112          global $config;
113   
114          if ($echo_var)
115          {
116              global $$echo_var;
117          }
118   
119          // Remove any "loose" php ... we want to give admins the ability
120          // to switch on/off PHP for a given template. Allowing unchecked
121          // php is a no-no. There is a potential issue here in that non-php
122          // content may be removed ... however designers should use entities
123          // if they wish to display < and >
124          $this->remove_php_tags($code);
125   
126          // Pull out all block/statement level elements and separate plain text
127          preg_match_all('#<!-- PHP -->(.*?)<!-- ENDPHP -->#s', $code, $matches);
128          $php_blocks = $matches[1];
129          $code = preg_replace('#<!-- PHP -->.*?<!-- ENDPHP -->#s', '<!-- PHP -->', $code);
130   
131          preg_match_all('#<!-- INCLUDE ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches);
132          $include_blocks = $matches[1];
133          $code = preg_replace('#<!-- INCLUDE [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDE -->', $code);
134   
135          preg_match_all('#<!-- INCLUDEPHP ([a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches);
136          $includephp_blocks = $matches[1];
137          $code = preg_replace('#<!-- INCLUDEPHP [a-zA-Z0-9\_\-\+\./]+ -->#', '<!-- INCLUDEPHP -->', $code);
138   
139          preg_match_all('#<!-- ([^<].*?) (.*?)? ?-->#', $code, $blocks, PREG_SET_ORDER);
140   
141          $text_blocks = preg_split('#<!-- [^<].*? (?:.*?)? ?-->#', $code);
142   
143          for ($i = 0, $j = sizeof($text_blocks); $i < $j; $i++)
144          {
145              $this->compile_var_tags($text_blocks[$i]);
146          }
147          $compile_blocks = array();
148   
149          for ($curr_tb = 0, $tb_size = sizeof($blocks); $curr_tb < $tb_size; $curr_tb++)
150          {
151              $block_val = &$blocks[$curr_tb];
152   
153              switch ($block_val[1])
154              {
155                  case 'BEGIN':
156                      $this->block_else_level[] = false;
157                      $compile_blocks[] = '<?php ' . $this->compile_tag_block($block_val[2]) . ' ?>';
158                  break;
159   
160                  case 'BEGINELSE':
161                      $this->block_else_level[sizeof($this->block_else_level) - 1] = true;
162                      $compile_blocks[] = '<?php }} else { ?>';
163                  break;
164   
165                  case 'END':
166                      array_pop($this->block_names);
167                      $compile_blocks[] = '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>';
168                  break;
169   
170                  case 'IF':
171                      $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], false) . ' ?>';
172                  break;
173   
174                  case 'ELSE':
175                      $compile_blocks[] = '<?php } else { ?>';
176                  break;
177   
178                  case 'ELSEIF':
179                      $compile_blocks[] = '<?php ' . $this->compile_tag_if($block_val[2], true) . ' ?>';
180                  break;
181   
182                  case 'ENDIF':
183                      $compile_blocks[] = '<?php } ?>';
184                  break;
185   
186                  case 'DEFINE':
187                      $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], true) . ' ?>';
188                  break;
189   
190                  case 'UNDEFINE':
191                      $compile_blocks[] = '<?php ' . $this->compile_tag_define($block_val[2], false) . ' ?>';
192                  break;
193   
194                  case 'INCLUDE':
195                      $temp = array_shift($include_blocks);
196                      $compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>';
197                      $this->template->_tpl_include($temp, false);
198                  break;
199   
200                  case 'INCLUDEPHP':
201                      $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : '';
202                  break;
203   
204                  case 'PHP':
205                      $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : '';
206                  break;
207   
208                  default:
209                      $this->compile_var_tags($block_val[0]);
210                      $trim_check = trim($block_val[0]);
211                      $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : '');
212                  break;
213              }
214          }
215   
216          $template_php = '';
217          for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++)
218          {
219              $trim_check_text = trim($text_blocks[$i]);
220              $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '');
221          }
222   
223          // There will be a number of occasions where we switch into and out of
224          // PHP mode instantaneously. Rather than "burden" the parser with this
225          // we'll strip out such occurences, minimising such switching
226          $template_php = str_replace(' ?><?php ', ' ', $template_php);
227   
228          return (!$no_echo) ? $template_php : "\$$echo_var .= '" . $template_php . "'";
229      }
230   
231      /**
232      * Compile variables
233      * @access private
234      */
235      function compile_var_tags(&$text_blocks)
236      {
237          // change template varrefs into PHP varrefs
238          $varrefs = array();
239   
240          // This one will handle varrefs WITH namespaces
241          preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER);
242   
243          foreach ($varrefs as $var_val)
244          {
245              $namespace = $var_val[1];
246              $varname = $var_val[3];
247              $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]);
248   
249              $text_blocks = str_replace($var_val[0], $new, $text_blocks);
250          }
251   
252          // This will handle the remaining root-level varrefs
253          // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
254          if (strpos($text_blocks, '{L_') !== false)
255          {
256              $text_blocks = preg_replace('#\{L_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks);
257          }
258   
259          // Handle addslashed language variables prefixed with LA_
260          // If a template variable already exist, it will be used in favor of it...
261          if (strpos($text_blocks, '{LA_') !== false)
262          {
263              $text_blocks = preg_replace('#\{LA_([a-z0-9\-_]*)\}#is', "<?php echo ((isset(\$this->_rootref['LA_\\1'])) ? \$this->_rootref['LA_\\1'] : ((isset(\$this->_rootref['L_\\1'])) ? addslashes(\$this->_rootref['L_\\1']) : ((isset(\$user->lang['\\1'])) ? addslashes(\$user->lang['\\1']) : '{ \\1 }'))); ?>", $text_blocks);
264          }
265   
266          // Handle remaining varrefs
267          $text_blocks = preg_replace('#\{([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks);
268          $text_blocks = preg_replace('#\{\$([a-z0-9\-_]*)\}#is', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks);
269   
270          return;
271      }
272   
273      /**
274      * Compile blocks
275      * @access private
276      */
277      function compile_tag_block($tag_args)
278      {
279          $no_nesting = false;
280   
281          // Is the designer wanting to call another loop in a loop?
282          if (strpos($tag_args, '!') === 0)
283          {
284              // Count the number if ! occurrences (not allowed in vars)
285              $no_nesting = substr_count($tag_args, '!');
286              $tag_args = substr($tag_args, $no_nesting);
287          }
288   
289          // Allow for control of looping (indexes start from zero):
290          // foo(2)    : Will start the loop on the 3rd entry
291          // foo(-2)   : Will start the loop two entries from the end
292          // foo(3,4)  : Will start the loop on the fourth entry and end it on the fifth
293          // foo(3,-4) : Will start the loop on the fourth entry and end it four from last
294          if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match))
295          {
296              $tag_args = $match[1];
297   
298              if ($match[2] < 0)
299              {
300                  $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')';
301              }
302              else
303              {
304                  $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')';
305              }
306   
307              if (strlen($match[3]) < 1 || $match[3] == -1)
308              {
309                  $loop_end = '$_' . $tag_args . '_count';
310              }
311              else if ($match[3] >= 0)
312              {
313                  $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')';
314              }
315              else //if ($match[3] < -1)
316              {
317                  $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1);
318              }
319          }
320          else
321          {
322              $loop_start = 0;
323              $loop_end = '$_' . $tag_args . '_count';
324          }
325   
326          $tag_template_php = '';
327          array_push($this->block_names, $tag_args);
328   
329          if ($no_nesting !== false)
330          {
331              // We need to implode $no_nesting times from the end...
332              $block = array_slice($this->block_names, -$no_nesting);
333          }
334          else
335          {
336              $block = $this->block_names;
337          }
338   
339          if (sizeof($block) < 2)
340          {
341              // Block is not nested.
342              $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;";
343              $varref = "\$this->_tpldata['$tag_args']";
344          }
345          else
346          {
347              // This block is nested.
348              // Generate a namespace string for this block.
349              $namespace = implode('.', $block);
350   
351              // Get a reference to the data array for this block that depends on the
352              // current indices of all parent blocks.
353              $varref = $this->generate_block_data_ref($namespace, false);
354   
355              // Create the for loop code to iterate over this block.
356              $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
357          }
358   
359          $tag_template_php .= 'if ($_' . $tag_args . '_count) {';
360   
361          /**
362          * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory
363          * <code>
364          *    if (!$offset)
365          *    {
366          *        $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
367          *    }
368          * </code>
369          */
370   
371          $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){';
372          $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];';
373   
374          return $tag_template_php;
375      }
376   
377      /**
378      * Compile IF tags - much of this is from Smarty with
379      * some adaptions for our block level methods
380      * @access private
381      */
382      function compile_tag_if($tag_args, $elseif)
383      {
384          // Tokenize args for 'if' tag.
385          preg_match_all('/(?:
386              "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         |
387              \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     |
388              [(),]                                  |
389              [^\s(),]+)/x', $tag_args, $match);
390   
391          $tokens = $match[0];
392          $is_arg_stack = array();
393   
394          for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
395          {
396              $token = &$tokens[$i];
397   
398              switch ($token)
399              {
400                  case '!==':
401                  case '===':
402                  case '<<':
403                  case '>>':
404                  case '|':
405                  case '^':
406                  case '&':
407                  case '~':
408                  case ')':
409                  case ',':
410                  case '+':
411                  case '-':
412                  case '*':
413                  case '/':
414                  case '@':
415                  break;
416   
417                  case '==':
418                  case 'eq':
419                      $token = '==';
420                  break;
421   
422                  case '!=':
423                  case '<>':
424                  case 'ne':
425                  case 'neq':
426                      $token = '!=';
427                  break;
428   
429                  case '<':
430                  case 'lt':
431                      $token = '<';
432                  break;
433   
434                  case '<=':
435                  case 'le':
436                  case 'lte':
437                      $token = '<=';
438                  break;
439   
440                  case '>':
441                  case 'gt':
442                      $token = '>';
443                  break;
444   
445                  case '>=':
446                  case 'ge':
447                  case 'gte':
448                      $token = '>=';
449                  break;
450   
451                  case '&&':
452                  case 'and':
453                      $token = '&&';
454                  break;
455   
456                  case '||':
457                  case 'or':
458                      $token = '||';
459                  break;
460   
461                  case '!':
462                  case 'not':
463                      $token = '!';
464                  break;
465   
466                  case '%':
467                  case 'mod':
468                      $token = '%';
469                  break;
470   
471                  case '(':
472                      array_push($is_arg_stack, $i);
473                  break;
474   
475                  case 'is':
476                      $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
477                      $is_arg    = implode('    ', array_slice($tokens,    $is_arg_start, $i -    $is_arg_start));
478   
479                      $new_tokens    = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
480   
481                      array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens);
482   
483                      $i = $is_arg_start;
484   
485                  // no break
486   
487                  default:
488                      if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs))
489                      {
490                          $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']' : (($varrefs[2]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$this->_rootref[\'' . $varrefs[3] . '\']');
491                      }
492                      else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs))
493                      {
494                          // Allow checking if loops are set with .loopname
495                          // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
496                          $blocks = explode('.', $varrefs[1]);
497   
498                          // If the block is nested, we have a reference that we can grab.
499                          // If the block is not nested, we just go and grab the block from _tpldata
500                          if (sizeof($blocks) > 1)
501                          {
502                              $block = array_pop($blocks);
503                              $namespace = implode('.', $blocks);
504                              $varref = $this->generate_block_data_ref($namespace, true);
505   
506                              // Add the block reference for the last child.
507                              $varref .= "['" . $block . "']";
508                          }
509                          else
510                          {
511                              $varref = '$this->_tpldata';
512   
513                              // Add the block reference for the last child.
514                              $varref .= "['" . $blocks[0] . "']";
515                          }
516                          $token = "sizeof($varref)";
517                      }
518   
519                  break;
520              }
521          }
522   
523          return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { ');
524      }
525   
526      /**
527      * Compile DEFINE tags
528      * @access private
529      */
530      function compile_tag_define($tag_args, $op)
531      {
532          preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match);
533   
534          if (empty($match[2]) || (!isset($match[4]) && $op))
535          {
536              return '';
537          }
538   
539          if (!$op)
540          {
541              return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
542          }
543   
544          // Are we a string?
545          if ($match[3] && $match[5])
546          {
547              $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]);
548   
549              // Compile reference, we allow template variables in defines...
550              $match[4] = $this->compile($match[4]);
551   
552              // Now replace the php code
553              $match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'";
554          }
555          else
556          {
557              preg_match('#true|false|\.#i', $match[4], $type);
558   
559              switch (strtolower($type[0]))
560              {
561                  case 'true':
562                  case 'false':
563                      $match[4] = strtoupper($match[4]);
564                  break;
565   
566                  case '.':
567                      $match[4] = doubleval($match[4]);
568                  break;
569   
570                  default:
571                      $match[4] = intval($match[4]);
572                  break;
573              }
574          }
575   
576          return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';';
577      }
578   
579      /**
580      * Compile INCLUDE tag
581      * @access private
582      */
583      function compile_tag_include($tag_args)
584      {
585          return "\$this->_tpl_include('$tag_args');";
586      }
587   
588      /**
589      * Compile INCLUDE_PHP tag
590      * @access private
591      */
592      function compile_tag_include_php($tag_args)
593      {
594          return "include('" . $tag_args . "');";
595      }
596   
597      /**
598      * parse expression
599      * This is from Smarty
600      * @access private
601      */
602      function _parse_is_expr($is_arg, $tokens)
603      {
604          $expr_end = 0;
605          $negate_expr = false;
606   
607          if (($first_token = array_shift($tokens)) == 'not')
608          {
609              $negate_expr = true;
610              $expr_type = array_shift($tokens);
611          }
612          else
613          {
614              $expr_type = $first_token;
615          }
616   
617          switch ($expr_type)
618          {
619              case 'even':
620                  if (@$tokens[$expr_end] == 'by')
621                  {
622                      $expr_end++;
623                      $expr_arg = $tokens[$expr_end++];
624                      $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
625                  }
626                  else
627                  {
628                      $expr = "!($is_arg & 1)";
629                  }
630              break;
631   
632              case 'odd':
633                  if (@$tokens[$expr_end] == 'by')
634                  {
635                      $expr_end++;
636                      $expr_arg = $tokens[$expr_end++];
637                      $expr = "(($is_arg / $expr_arg) % $expr_arg)";
638                  }
639                  else
640                  {
641                      $expr = "($is_arg & 1)";
642                  }
643              break;
644   
645              case 'div':
646                  if (@$tokens[$expr_end] == 'by')
647                  {
648                      $expr_end++;
649                      $expr_arg = $tokens[$expr_end++];
650                      $expr = "!($is_arg % $expr_arg)";
651                  }
652              break;
653          }
654   
655          if ($negate_expr)
656          {
657              $expr = "!($expr)";
658          }
659   
660          array_splice($tokens, 0, $expr_end, $expr);
661   
662          return $tokens;
663      }
664   
665      /**
666      * Generates a reference to the given variable inside the given (possibly nested)
667      * block namespace. This is a string of the form:
668      * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
669      * It's ready to be inserted into an "echo" line in one of the templates.
670      * NOTE: expects a trailing "." on the namespace.
671      * @access private
672      */
673      function generate_block_varref($namespace, $varname, $echo = true, $defop = false)
674      {
675          // Strip the trailing period.
676          $namespace = substr($namespace, 0, -1);
677   
678          // Get a reference to the data block for this namespace.
679          $varref = $this->generate_block_data_ref($namespace, true, $defop);
680          // Prepend the necessary code to stick this in an echo line.
681   
682          // Append the variable reference.
683          $varref .= "['$varname']";
684          $varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : '');
685   
686          return $varref;
687      }
688   
689      /**
690      * Generates a reference to the array of data values for the given
691      * (possibly nested) block namespace. This is a string of the form:
692      * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
693      *
694      * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
695      * NOTE: does not expect a trailing "." on the blockname.
696      * @access private
697      */
698      function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
699      {
700          // Get an array of the blocks involved.
701          $blocks = explode('.', $blockname);
702          $blockcount = sizeof($blocks) - 1;
703   
704          // DEFINE is not an element of any referenced variable, we must use _tpldata to access it
705          if ($defop)
706          {
707              $varref = '$this->_tpldata[\'DEFINE\']';
708              // Build up the string with everything but the last child.
709              for ($i = 0; $i < $blockcount; $i++)
710              {
711                  $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
712              }
713              // Add the block reference for the last child.
714              $varref .= "['" . $blocks[$blockcount] . "']";
715              // Add the iterator for the last child if requried.
716              if ($include_last_iterator)
717              {
718                  $varref .= '[$_' . $blocks[$blockcount] . '_i]';
719              }
720              return $varref;
721          }
722          else if ($include_last_iterator)
723          {
724              return '$_'. $blocks[$blockcount] . '_val';
725          }
726          else
727          {
728              return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']';
729          }
730      }
731   
732      /**
733      * Write compiled file to cache directory
734      * @access private
735      */
736      function compile_write($handle, $data)
737      {
738          global $phpEx;
739   
740          $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx;
741   
742          if ($fp = @fopen($filename, 'wb'))
743          {
744              @flock($fp, LOCK_EX);
745              @fwrite ($fp, $data);
746              @flock($fp, LOCK_UN);
747              @fclose($fp);
748   
749              @chmod($filename, 0666);
750          }
751   
752          return;
753      }
754  }
755   
756  ?>