[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/includes/ -> functions_template.php (source)

   1  <?php
   2  /**
   3  *
   4  * @package phpBB3
   5  * @version $Id$
   6  * @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
   7  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
   8  *
   9  */
  10  
  11  /**
  12  * @ignore
  13  */
  14  if (!defined('IN_PHPBB'))
  15  {
  16      exit;
  17  }
  18  
  19  /**
  20  * Extension of template class - Functions needed for compiling templates only.
  21  *
  22  * psoTFX, phpBB Development Team - Completion of file caching, decompilation
  23  * routines and implementation of conditionals/keywords and associated changes
  24  *
  25  * The interface was inspired by PHPLib templates,  and the template file (formats are
  26  * quite similar)
  27  *
  28  * The keyword/conditional implementation is currently based on sections of code from
  29  * the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
  30  * (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
  31  * derived from an LGPL application may be relicenced under the GPL, this applies
  32  * to this source
  33  *
  34  * DEFINE directive inspired by a request by Cyberalien
  35  *
  36  * @package phpBB3
  37  */
  38  class template_compile
  39  {
  40      var $template;
  41  
  42      // Various storage arrays
  43      var $block_names = array();
  44      var $block_else_level = array();
  45  
  46      /**
  47      * constuctor
  48      */
  49  	function template_compile(&$template)
  50      {
  51          $this->template = &$template;
  52      }
  53  
  54      /**
  55      * Load template source from file
  56      * @access private
  57      */
  58  	function _tpl_load_file($handle, $store_in_db = false)
  59      {
  60          // Try and open template for read
  61          if (!file_exists($this->template->files[$handle]))
  62          {
  63              trigger_error("template->_tpl_load_file(): File {$this->template->files[$handle]} does not exist or is empty", E_USER_ERROR);
  64          }
  65  
  66          $this->template->compiled_code[$handle] = $this->compile(trim(@file_get_contents($this->template->files[$handle])));
  67  
  68          // Actually compile the code now.
  69          $this->compile_write($handle, $this->template->compiled_code[$handle]);
  70  
  71          // Store in database if required...
  72          if ($store_in_db)
  73          {
  74              global $db, $user;
  75  
  76              $sql_ary = array(
  77                  'template_id'            => $this->template->files_template[$handle],
  78                  'template_filename'        => $this->template->filename[$handle],
  79                  'template_included'        => '',
  80                  'template_mtime'        => time(),
  81                  'template_data'            => trim(@file_get_contents($this->template->files[$handle])),
  82              );
  83  
  84              $sql = 'INSERT INTO ' . STYLES_TEMPLATE_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  85              $db->sql_query($sql);
  86          }
  87      }
  88  
  89      /**
  90      * Remove any PHP tags that do not belong, these regular expressions are derived from
  91      * the ones that exist in zend_language_scanner.l
  92      * @access private
  93      */
  94  	function remove_php_tags(&$code)
  95      {
  96          // This matches the information gathered from the internal PHP lexer
  97          $match = array(
  98              '#<([\?%])=?.*?\1>#s',
  99              '#<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-Z0-9\-_]+\}|[a-zA-Z0-9\_\-\+\./]+) -->#', $code, $matches);
 132          $include_blocks = $matches[1];
 133          $code = preg_replace('#<!-- INCLUDE (?:\{\$?[A-Z0-9\-_]+\}|[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  
 197                      // Dynamic includes
 198                      // Cheap match rather than a full blown regexp, we already know
 199                      // the format of the input so just use string manipulation.
 200                      if ($temp[0] == '{')
 201                      {
 202                          $file = false;
 203  
 204                          if ($temp[1] == '$')
 205                          {
 206                              $var = substr($temp, 2, -1);
 207                              //$file = $this->template->_tpldata['DEFINE']['.'][$var];
 208                              $temp = "\$this->_tpldata['DEFINE']['.']['$var']";
 209                          }
 210                          else
 211                          {
 212                              $var = substr($temp, 1, -1);
 213                              //$file = $this->template->_rootref[$var];
 214                              $temp = "\$this->_rootref['$var']";
 215                          }
 216                      }
 217                      else
 218                      {
 219                          $file = $temp;
 220                      }
 221  
 222                      $compile_blocks[] = '<?php ' . $this->compile_tag_include($temp) . ' ?>';
 223  
 224                      // No point in checking variable includes
 225                      if ($file)
 226                      {
 227                          $this->template->_tpl_include($file, false);
 228                      }
 229                  break;
 230  
 231                  case 'INCLUDEPHP':
 232                      $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . $this->compile_tag_include_php(array_shift($includephp_blocks)) . ' ?>' : '';
 233                  break;
 234  
 235                  case 'PHP':
 236                      $compile_blocks[] = ($config['tpl_allow_php']) ? '<?php ' . array_shift($php_blocks) . ' ?>' : '';
 237                  break;
 238  
 239                  default:
 240                      $this->compile_var_tags($block_val[0]);
 241                      $trim_check = trim($block_val[0]);
 242                      $compile_blocks[] = (!$no_echo) ? ((!empty($trim_check)) ? $block_val[0] : '') : ((!empty($trim_check)) ? $block_val[0] : '');
 243                  break;
 244              }
 245          }
 246  
 247          $template_php = '';
 248          for ($i = 0, $size = sizeof($text_blocks); $i < $size; $i++)
 249          {
 250              $trim_check_text = trim($text_blocks[$i]);
 251              $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] : '');
 252          }
 253  
 254          // Remove unused opening/closing tags
 255          $template_php = str_replace(' ?><?php ', ' ', $template_php);
 256  
 257          // Now add a newline after each php closing tag which already has a newline
 258          // PHP itself strips a newline if a closing tag is used (this is documented behaviour) and it is mostly not intended by style authors to remove newlines
 259          $template_php = preg_replace('#\?\>([\r\n])#', '?>\1\1', $template_php);
 260  
 261          // There will be a number of occasions where we switch into and out of
 262          // PHP mode instantaneously. Rather than "burden" the parser with this
 263          // we'll strip out such occurences, minimising such switching
 264          if ($no_echo)
 265          {
 266              return "\$$echo_var .= '" . $template_php . "'";
 267          }
 268  
 269          return $template_php;
 270      }
 271  
 272      /**
 273      * Compile variables
 274      * @access private
 275      */
 276  	function compile_var_tags(&$text_blocks)
 277      {
 278          // change template varrefs into PHP varrefs
 279          $varrefs = array();
 280  
 281          // This one will handle varrefs WITH namespaces
 282          preg_match_all('#\{((?:[a-z0-9\-_]+\.)+)(\$)?([A-Z0-9\-_]+)\}#', $text_blocks, $varrefs, PREG_SET_ORDER);
 283  
 284          foreach ($varrefs as $var_val)
 285          {
 286              $namespace = $var_val[1];
 287              $varname = $var_val[3];
 288              $new = $this->generate_block_varref($namespace, $varname, true, $var_val[2]);
 289  
 290              $text_blocks = str_replace($var_val[0], $new, $text_blocks);
 291          }
 292  
 293          // This will handle the remaining root-level varrefs
 294          // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
 295          if (strpos($text_blocks, '{L_') !== false)
 296          {
 297              $text_blocks = preg_replace('#\{L_([A-Z0-9\-_]+)\}#', "<?php echo ((isset(\$this->_rootref['L_\\1'])) ? \$this->_rootref['L_\\1'] : ((isset(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '{ \\1 }')); ?>", $text_blocks);
 298          }
 299  
 300          // Handle addslashed language variables prefixed with LA_
 301          // If a template variable already exist, it will be used in favor of it...
 302          if (strpos($text_blocks, '{LA_') !== false)
 303          {
 304              $text_blocks = preg_replace('#\{LA_([A-Z0-9\-_]+)\}#', "<?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);
 305          }
 306  
 307          // Handle remaining varrefs
 308          $text_blocks = preg_replace('#\{([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_rootref['\\1'])) ? \$this->_rootref['\\1'] : ''; ?>", $text_blocks);
 309          $text_blocks = preg_replace('#\{\$([A-Z0-9\-_]+)\}#', "<?php echo (isset(\$this->_tpldata['DEFINE']['.']['\\1'])) ? \$this->_tpldata['DEFINE']['.']['\\1'] : ''; ?>", $text_blocks);
 310  
 311          return;
 312      }
 313  
 314      /**
 315      * Compile blocks
 316      * @access private
 317      */
 318  	function compile_tag_block($tag_args)
 319      {
 320          $no_nesting = false;
 321  
 322          // Is the designer wanting to call another loop in a loop?
 323          if (strpos($tag_args, '!') === 0)
 324          {
 325              // Count the number of ! occurrences (not allowed in vars)
 326              $no_nesting = substr_count($tag_args, '!');
 327              $tag_args = substr($tag_args, $no_nesting);
 328          }
 329  
 330          // Allow for control of looping (indexes start from zero):
 331          // foo(2)    : Will start the loop on the 3rd entry
 332          // foo(-2)   : Will start the loop two entries from the end
 333          // foo(3,4)  : Will start the loop on the fourth entry and end it on the fifth
 334          // foo(3,-4) : Will start the loop on the fourth entry and end it four from last
 335          if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match))
 336          {
 337              $tag_args = $match[1];
 338  
 339              if ($match[2] < 0)
 340              {
 341                  $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')';
 342              }
 343              else
 344              {
 345                  $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')';
 346              }
 347  
 348              if (strlen($match[3]) < 1 || $match[3] == -1)
 349              {
 350                  $loop_end = '$_' . $tag_args . '_count';
 351              }
 352              else if ($match[3] >= 0)
 353              {
 354                  $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')';
 355              }
 356              else //if ($match[3] < -1)
 357              {
 358                  $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1);
 359              }
 360          }
 361          else
 362          {
 363              $loop_start = 0;
 364              $loop_end = '$_' . $tag_args . '_count';
 365          }
 366  
 367          $tag_template_php = '';
 368          array_push($this->block_names, $tag_args);
 369  
 370          if ($no_nesting !== false)
 371          {
 372              // We need to implode $no_nesting times from the end...
 373              $block = array_slice($this->block_names, -$no_nesting);
 374          }
 375          else
 376          {
 377              $block = $this->block_names;
 378          }
 379  
 380          if (sizeof($block) < 2)
 381          {
 382              // Block is not nested.
 383              $tag_template_php = '$_' . $tag_args . "_count = (isset(\$this->_tpldata['$tag_args'])) ? sizeof(\$this->_tpldata['$tag_args']) : 0;";
 384              $varref = "\$this->_tpldata['$tag_args']";
 385          }
 386          else
 387          {
 388              // This block is nested.
 389              // Generate a namespace string for this block.
 390              $namespace = implode('.', $block);
 391  
 392              // Get a reference to the data array for this block that depends on the
 393              // current indices of all parent blocks.
 394              $varref = $this->generate_block_data_ref($namespace, false);
 395  
 396              // Create the for loop code to iterate over this block.
 397              $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
 398          }
 399  
 400          $tag_template_php .= 'if ($_' . $tag_args . '_count) {';
 401  
 402          /**
 403          * 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
 404          * <code>
 405          *    if (!$offset)
 406          *    {
 407          *        $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
 408          *    }
 409          * </code>
 410          */
 411  
 412          $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){';
 413          $tag_template_php .= '$_'. $tag_args . '_val = &' . $varref . '[$_'. $tag_args. '_i];';
 414  
 415          return $tag_template_php;
 416      }
 417  
 418      /**
 419      * Compile IF tags - much of this is from Smarty with
 420      * some adaptions for our block level methods
 421      * @access private
 422      */
 423  	function compile_tag_if($tag_args, $elseif)
 424      {
 425          // Tokenize args for 'if' tag.
 426          preg_match_all('/(?:
 427              "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         |
 428              \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     |
 429              [(),]                                  |
 430              [^\s(),]+)/x', $tag_args, $match);
 431  
 432          $tokens = $match[0];
 433          $is_arg_stack = array();
 434  
 435          for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
 436          {
 437              $token = &$tokens[$i];
 438  
 439              switch ($token)
 440              {
 441                  case '!==':
 442                  case '===':
 443                  case '<<':
 444                  case '>>':
 445                  case '|':
 446                  case '^':
 447                  case '&':
 448                  case '~':
 449                  case ')':
 450                  case ',':
 451                  case '+':
 452                  case '-':
 453                  case '*':
 454                  case '/':
 455                  case '@':
 456                  break;
 457  
 458                  case '==':
 459                  case 'eq':
 460                      $token = '==';
 461                  break;
 462  
 463                  case '!=':
 464                  case '<>':
 465                  case 'ne':
 466                  case 'neq':
 467                      $token = '!=';
 468                  break;
 469  
 470                  case '<':
 471                  case 'lt':
 472                      $token = '<';
 473                  break;
 474  
 475                  case '<=':
 476                  case 'le':
 477                  case 'lte':
 478                      $token = '<=';
 479                  break;
 480  
 481                  case '>':
 482                  case 'gt':
 483                      $token = '>';
 484                  break;
 485  
 486                  case '>=':
 487                  case 'ge':
 488                  case 'gte':
 489                      $token = '>=';
 490                  break;
 491  
 492                  case '&&':
 493                  case 'and':
 494                      $token = '&&';
 495                  break;
 496  
 497                  case '||':
 498                  case 'or':
 499                      $token = '||';
 500                  break;
 501  
 502                  case '!':
 503                  case 'not':
 504                      $token = '!';
 505                  break;
 506  
 507                  case '%':
 508                  case 'mod':
 509                      $token = '%';
 510                  break;
 511  
 512                  case '(':
 513                      array_push($is_arg_stack, $i);
 514                  break;
 515  
 516                  case 'is':
 517                      $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
 518                      $is_arg    = implode('    ', array_slice($tokens,    $is_arg_start, $i -    $is_arg_start));
 519  
 520                      $new_tokens    = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
 521  
 522                      array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens);
 523  
 524                      $i = $is_arg_start;
 525  
 526                  // no break
 527  
 528                  default:
 529                      if (preg_match('#^((?:[a-z0-9\-_]+\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs))
 530                      {
 531                          $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] . '\']');
 532                      }
 533                      else if (preg_match('#^\.((?:[a-z0-9\-_]+\.?)+)$#s', $token, $varrefs))
 534                      {
 535                          // Allow checking if loops are set with .loopname
 536                          // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
 537                          $blocks = explode('.', $varrefs[1]);
 538  
 539                          // If the block is nested, we have a reference that we can grab.
 540                          // If the block is not nested, we just go and grab the block from _tpldata
 541                          if (sizeof($blocks) > 1)
 542                          {
 543                              $block = array_pop($blocks);
 544                              $namespace = implode('.', $blocks);
 545                              $varref = $this->generate_block_data_ref($namespace, true);
 546  
 547                              // Add the block reference for the last child.
 548                              $varref .= "['" . $block . "']";
 549                          }
 550                          else
 551                          {
 552                              $varref = '$this->_tpldata';
 553  
 554                              // Add the block reference for the last child.
 555                              $varref .= "['" . $blocks[0] . "']";
 556                          }
 557                          $token = "sizeof($varref)";
 558                      }
 559                      else if (!empty($token))
 560                      {
 561                          $token = '(' . $token . ')';
 562                      }
 563  
 564                  break;
 565              }
 566          }
 567  
 568          // If there are no valid tokens left or only control/compare characters left, we do skip this statement
 569          if (!sizeof($tokens) || str_replace(array(' ', '=', '!', '<', '>', '&', '|', '%', '(', ')'), '', implode('', $tokens)) == '')
 570          {
 571              $tokens = array('false');
 572          }
 573          return (($elseif) ? '} else if (' : 'if (') . (implode(' ', $tokens) . ') { ');
 574      }
 575  
 576      /**
 577      * Compile DEFINE tags
 578      * @access private
 579      */
 580  	function compile_tag_define($tag_args, $op)
 581      {
 582          preg_match('#^((?:[a-z0-9\-_]+\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (\'?)([^\']*)(\'?))?$#', $tag_args, $match);
 583  
 584          if (empty($match[2]) || (!isset($match[4]) && $op))
 585          {
 586              return '';
 587          }
 588  
 589          if (!$op)
 590          {
 591              return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
 592          }
 593  
 594          // Are we a string?
 595          if ($match[3] && $match[5])
 596          {
 597              $match[4] = str_replace(array('\\\'', '\\\\', '\''), array('\'', '\\', '\\\''), $match[4]);
 598  
 599              // Compile reference, we allow template variables in defines...
 600              $match[4] = $this->compile($match[4]);
 601  
 602              // Now replace the php code
 603              $match[4] = "'" . str_replace(array('<?php echo ', '; ?>'), array("' . ", " . '"), $match[4]) . "'";
 604          }
 605          else
 606          {
 607              preg_match('#true|false|\.#i', $match[4], $type);
 608  
 609              switch (strtolower($type[0]))
 610              {
 611                  case 'true':
 612                  case 'false':
 613                      $match[4] = strtoupper($match[4]);
 614                  break;
 615  
 616                  case '.':
 617                      $match[4] = doubleval($match[4]);
 618                  break;
 619  
 620                  default:
 621                      $match[4] = intval($match[4]);
 622                  break;
 623              }
 624          }
 625  
 626          return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $match[4] . ';';
 627      }
 628  
 629      /**
 630      * Compile INCLUDE tag
 631      * @access private
 632      */
 633  	function compile_tag_include($tag_args)
 634      {
 635          // Process dynamic includes
 636          if ($tag_args[0] == '$')
 637          {
 638              return "if (isset($tag_args)) { \$this->_tpl_include($tag_args); }";
 639          }
 640  
 641          return "\$this->_tpl_include('$tag_args');";
 642      }
 643  
 644      /**
 645      * Compile INCLUDE_PHP tag
 646      * @access private
 647      */
 648  	function compile_tag_include_php($tag_args)
 649      {
 650          return "\$this->_php_include('$tag_args');";
 651      }
 652  
 653      /**
 654      * parse expression
 655      * This is from Smarty
 656      * @access private
 657      */
 658  	function _parse_is_expr($is_arg, $tokens)
 659      {
 660          $expr_end = 0;
 661          $negate_expr = false;
 662  
 663          if (($first_token = array_shift($tokens)) == 'not')
 664          {
 665              $negate_expr = true;
 666              $expr_type = array_shift($tokens);
 667          }
 668          else
 669          {
 670              $expr_type = $first_token;
 671          }
 672  
 673          switch ($expr_type)
 674          {
 675              case 'even':
 676                  if (@$tokens[$expr_end] == 'by')
 677                  {
 678                      $expr_end++;
 679                      $expr_arg = $tokens[$expr_end++];
 680                      $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
 681                  }
 682                  else
 683                  {
 684                      $expr = "!($is_arg & 1)";
 685                  }
 686              break;
 687  
 688              case 'odd':
 689                  if (@$tokens[$expr_end] == 'by')
 690                  {
 691                      $expr_end++;
 692                      $expr_arg = $tokens[$expr_end++];
 693                      $expr = "(($is_arg / $expr_arg) % $expr_arg)";
 694                  }
 695                  else
 696                  {
 697                      $expr = "($is_arg & 1)";
 698                  }
 699              break;
 700  
 701              case 'div':
 702                  if (@$tokens[$expr_end] == 'by')
 703                  {
 704                      $expr_end++;
 705                      $expr_arg = $tokens[$expr_end++];
 706                      $expr = "!($is_arg % $expr_arg)";
 707                  }
 708              break;
 709          }
 710  
 711          if ($negate_expr)
 712          {
 713              $expr = "!($expr)";
 714          }
 715  
 716          array_splice($tokens, 0, $expr_end, $expr);
 717  
 718          return $tokens;
 719      }
 720  
 721      /**
 722      * Generates a reference to the given variable inside the given (possibly nested)
 723      * block namespace. This is a string of the form:
 724      * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
 725      * It's ready to be inserted into an "echo" line in one of the templates.
 726      * NOTE: expects a trailing "." on the namespace.
 727      * @access private
 728      */
 729  	function generate_block_varref($namespace, $varname, $echo = true, $defop = false)
 730      {
 731          // Strip the trailing period.
 732          $namespace = substr($namespace, 0, -1);
 733  
 734          // Get a reference to the data block for this namespace.
 735          $varref = $this->generate_block_data_ref($namespace, true, $defop);
 736          // Prepend the necessary code to stick this in an echo line.
 737  
 738          // Append the variable reference.
 739          $varref .= "['$varname']";
 740          $varref = ($echo) ? "<?php echo $varref; ?>" : ((isset($varref)) ? $varref : '');
 741  
 742          return $varref;
 743      }
 744  
 745      /**
 746      * Generates a reference to the array of data values for the given
 747      * (possibly nested) block namespace. This is a string of the form:
 748      * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
 749      *
 750      * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
 751      * NOTE: does not expect a trailing "." on the blockname.
 752      * @access private
 753      */
 754  	function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
 755      {
 756          // Get an array of the blocks involved.
 757          $blocks = explode('.', $blockname);
 758          $blockcount = sizeof($blocks) - 1;
 759  
 760          // DEFINE is not an element of any referenced variable, we must use _tpldata to access it
 761          if ($defop)
 762          {
 763              $varref = '$this->_tpldata[\'DEFINE\']';
 764              // Build up the string with everything but the last child.
 765              for ($i = 0; $i < $blockcount; $i++)
 766              {
 767                  $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
 768              }
 769              // Add the block reference for the last child.
 770              $varref .= "['" . $blocks[$blockcount] . "']";
 771              // Add the iterator for the last child if requried.
 772              if ($include_last_iterator)
 773              {
 774                  $varref .= '[$_' . $blocks[$blockcount] . '_i]';
 775              }
 776              return $varref;
 777          }
 778          else if ($include_last_iterator)
 779          {
 780              return '$_'. $blocks[$blockcount] . '_val';
 781          }
 782          else
 783          {
 784              return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']';
 785          }
 786      }
 787  
 788      /**
 789      * Write compiled file to cache directory
 790      * @access private
 791      */
 792  	function compile_write($handle, $data)
 793      {
 794          global $phpEx;
 795  
 796          $filename = $this->template->cachepath . str_replace('/', '.', $this->template->filename[$handle]) . '.' . $phpEx;
 797  
 798          $data = "<?php if (!defined('IN_PHPBB')) exit;" . ((strpos($data, '<?php') === 0) ? substr($data, 5) : ' ?>' . $data);
 799  
 800          if ($fp = @fopen($filename, 'wb'))
 801          {
 802              @flock($fp, LOCK_EX);
 803              @fwrite ($fp, $data);
 804              @flock($fp, LOCK_UN);
 805              @fclose($fp);
 806  
 807              phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE);
 808          }
 809  
 810          return;
 811      }
 812  }
 813  
 814  ?>


Generated: Wed Oct 2 15:03:47 2013 Cross-referenced by PHPXref 0.7.1