[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/contrib/ -> template_file_cache.php (source)

   1  <?php
   2  /***************************************************************************
   3   *                              template.php
   4   *                            -------------------
   5   *   begin                : Saturday, Feb 13, 2001
   6   *   copyright            : (C) 2001 The phpBB Group
   7   *   email                : support@phpbb.com
   8   *
   9   *   $Id: template.php,v 1.7 2002/01/28 19:12:37 psotfx Exp $
  10   *
  11   ***************************************************************************/
  12  
  13  /***************************************************************************
  14   *
  15   *   This program is free software; you can redistribute it and/or modify
  16   *   it under the terms of the GNU General Public License as published by
  17   *   the Free Software Foundation; either version 2 of the License, or
  18   *   (at your option) any later version.
  19   *
  20   ***************************************************************************/
  21  
  22  /**
  23   * Template class. By Nathan Codding of the phpBB group.
  24   * The interface was originally inspired by PHPLib templates,
  25   * and the template file formats are quite similar.
  26   *
  27   * Updated 9th June 2003 - psoTFX
  28   * Backported various aspects of 2.2 template class
  29   *
  30   */
  31  
  32  class Template {
  33      var $classname = 'Template';
  34  
  35      // variable that holds all the data we'll be substituting into
  36      // the compiled templates.
  37      var $_tpldata = array();
  38  
  39      // Hash of filenames for each template handle.
  40      var $files = array();
  41  
  42      // Root template directories
  43      var $cache_root = 'cache/';
  44      var $root = '';
  45  
  46      // this will hash handle names to the compiled code for that handle.
  47      var $compiled_code = array();
  48  
  49      // This will hold the uncompiled code for that handle.
  50      var $uncompiled_code = array();
  51  
  52      /**
  53       * Constructor. Simply sets the root dir.
  54       *
  55       */
  56  	function Template($root = '.')
  57      {
  58          global $board_config, $db;
  59  
  60          $this->set_rootdir($root);
  61          $this->db = $db;
  62      }
  63  
  64      /**
  65       * Destroys this template object. Should be called when you're done with it, in order
  66       * to clear out the template data so you can load/parse a new template set.
  67       */
  68  	function destroy()
  69      {
  70          $this->_tpldata = array();
  71      }
  72  
  73      /**
  74       * Sets the template root directory for this Template object.
  75       */
  76  	function set_rootdir($dir)
  77      {
  78          global $phpbb_root_path;
  79  
  80          if (is_file($dir) || is_link($dir))
  81          {
  82              return false;
  83          }
  84  
  85          $this->root = phpbb_realpath($dir);
  86          $this->cachedir = phpbb_realpath($phpbb_root_path . $this->cache_root) . substr($dir, strrpos($dir, '/')) . '/';
  87  
  88          if (!file_exists($this->cachedir . 'admin/'))
  89          {
  90              @umask(0);
  91              if (!file_exists($this->cachedir))
  92              {
  93                  mkdir($this->cachedir, 0777);
  94              }
  95              mkdir($this->cachedir . 'admin/', 0777);
  96          }
  97  
  98          return true;
  99      }
 100  
 101      /**
 102       * Sets the template filenames for handles. $filename_array
 103       * should be a hash of handle => filename pairs.
 104       */
 105  	function set_filenames($filename_array)
 106      {
 107          if (!is_array($filename_array))
 108          {
 109              return false;
 110          }
 111  
 112          $template_names = '';
 113          @reset($filename_array);
 114          while (list($handle, $filename) = @each($filename_array))
 115          {
 116              $this->filename[$handle] = $filename;
 117              $this->files[$handle] = $this->make_filename($filename);
 118          }
 119  
 120          return true;
 121      }
 122  
 123  
 124      /**
 125       * Load the file for the handle, compile the file,
 126       * and run the compiled code. This will print out
 127       * the results of executing the template.
 128       */
 129  	function pparse($handle)
 130      {
 131          global $phpEx;
 132  
 133          $cache_file = $this->cachedir . $this->filename[$handle] . '.' . $phpEx;
 134  
 135          if(@filemtime($cache_file) == @filemtime($this->files[$handle]))
 136          {
 137              $_str = '';
 138              include($cache_file);
 139  
 140              if ($_str != '')
 141              {
 142                  echo $_str;
 143              }
 144          }
 145          else 
 146          {
 147              if (!$this->loadfile($handle))
 148              {
 149                  die("Template->pparse(): Couldn't load template file for handle $handle");
 150              }
 151  
 152              // Actually compile the code now.
 153              $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
 154  
 155              $fp = fopen($cache_file, 'w+');
 156              fwrite ($fp, '<?php' . "\n" . $this->compiled_code[$handle] . "\n?" . '>');
 157              fclose($fp);
 158  
 159              touch($cache_file, filemtime($this->files[$handle]));
 160              @chmod($cache_file, 0777);
 161  
 162              eval($this->compiled_code[$handle]);
 163          }
 164      
 165          return true;
 166      }
 167  
 168      /**
 169       * Inserts the uncompiled code for $handle as the
 170       * value of $varname in the root-level. This can be used
 171       * to effectively include a template in the middle of another
 172       * template.
 173       * Note that all desired assignments to the variables in $handle should be done
 174       * BEFORE calling this function.
 175       */
 176  	function assign_var_from_handle($varname, $handle)
 177      {
 178          global $phpEx;
 179  
 180          $cache_file = $this->cachedir . $this->filename[$handle] . '.' . $phpEx;
 181  
 182          if(@filemtime($cache_file) == @filemtime($this->files[$handle]))
 183          {
 184              $_str = '';
 185              include($cache_file);
 186          }
 187          else 
 188          {
 189              if (!$this->loadfile($handle))
 190              {
 191                  die("Template->pparse(): Couldn't load template file for handle $handle");
 192              }
 193  
 194              $code = $this->compile($this->uncompiled_code[$handle], true, '_str');
 195  
 196              $fp = fopen($cache_file, 'w+');
 197              fwrite ($fp, '<?php' . "\n" . $code . "\n?" . '>');
 198              fclose($fp);
 199  
 200              touch($cache_file, filemtime($this->files[$handle]));
 201              @chmod($cache_file, 0777);
 202  
 203              // Compile It, With The "no Echo Statements" Option On.
 204              $_str = '';
 205              // evaluate the variable assignment.
 206              eval($code);
 207          
 208          }
 209  
 210          // assign the value of the generated variable to the given varname.
 211          $this->assign_var($varname, $_str);
 212  
 213          return true;
 214      }
 215  
 216      /**
 217       * Block-level variable assignment. Adds a new block iteration with the given
 218       * variable assignments. Note that this should only be called once per block
 219       * iteration.
 220       */
 221  	function assign_block_vars($blockname, $vararray)
 222      {
 223          if (strstr($blockname, '.'))
 224          {
 225              // Nested block.
 226              $blocks = explode('.', $blockname);
 227              $blockcount = sizeof($blocks) - 1;
 228  
 229              $str = &$this->_tpldata; 
 230              for ($i = 0; $i < $blockcount; $i++) 
 231              {
 232                  $str = &$str[$blocks[$i]]; 
 233                  $str = &$str[sizeof($str) - 1]; 
 234              } 
 235  
 236              // Now we add the block that we're actually assigning to.
 237              // We're adding a new iteration to this block with the given
 238              // variable assignments.
 239              $str[$blocks[$blockcount]][] = $vararray;
 240          }
 241          else
 242          {
 243              // Top-level block.
 244              // Add a new iteration to this block with the variable assignments
 245              // we were given.
 246              $this->_tpldata[$blockname][] = $vararray;
 247          }
 248  
 249          return true;
 250      }
 251  
 252      /**
 253       * Root-level variable assignment. Adds to current assignments, overriding
 254       * any existing variable assignment with the same name.
 255       */
 256  	function assign_vars($vararray)
 257      {
 258          reset ($vararray);
 259          while (list($key, $val) = each($vararray))
 260          {
 261              $this->_tpldata['.'][0][$key] = $val;
 262          }
 263  
 264          return true;
 265      }
 266  
 267      /**
 268       * Root-level variable assignment. Adds to current assignments, overriding
 269       * any existing variable assignment with the same name.
 270       */
 271  	function assign_var($varname, $varval)
 272      {
 273          $this->_tpldata['.'][0][$varname] = $varval;
 274  
 275          return true;
 276      }
 277  
 278  
 279      /**
 280       * Generates a full path+filename for the given filename, which can either
 281       * be an absolute name, or a name relative to the rootdir for this Template
 282       * object.
 283       */
 284  	function make_filename($filename)
 285      {
 286          // Check if it's an absolute or relative path.
 287          if (substr($filename, 0, 1) != '/')
 288          {
 289              $filename = phpbb_realpath($this->root . '/' . $filename);
 290          }
 291  
 292          if (!file_exists($filename))
 293          {
 294              die("Template->make_filename(): Error - file $filename does not exist");
 295          }
 296  
 297          return $filename;
 298      }
 299  
 300  
 301      /**
 302       * If not already done, load the file for the given handle and populate
 303       * the uncompiled_code[] hash with its code. Do not compile.
 304       */
 305  	function loadfile($handle)
 306      {
 307          // If the file for this handle is already loaded and compiled, do nothing.
 308          if (!empty($this->uncompiled_code[$handle]))
 309          {
 310              return true;
 311          }
 312  
 313          // If we don't have a file assigned to this handle, die.
 314          if (!isset($this->files[$handle]))
 315          {
 316              die("Template->loadfile(): No file specified for handle $handle");
 317          }
 318  
 319          $filename = $this->files[$handle];
 320  
 321          $str = implode('', @file($filename));
 322          if (empty($str))
 323          {
 324              die("Template->loadfile(): File $filename for handle $handle is empty");
 325          }
 326  
 327          $this->uncompiled_code[$handle] = $str;
 328  
 329          return true;
 330      }
 331  
 332  
 333  
 334      /**
 335       * Compiles the given string of code, and returns
 336       * the result in a string.
 337       * If "do_not_echo" is true, the returned code will not be directly
 338       * executable, but can be used as part of a variable assignment
 339       * for use in assign_code_from_handle().
 340       */
 341  	function compile($code, $do_not_echo = false, $retvar = '')
 342      {
 343          $concat = (!$do_not_echo) ? ',' : '.';
 344  
 345          // replace \ with \\ and then ' with \'.
 346          $code = str_replace('\\', '\\\\', $code);
 347          $code = str_replace('\'', '\\\'', $code);
 348  
 349          // change template varrefs into PHP varrefs
 350  
 351          // This one will handle varrefs WITH namespaces
 352          $varrefs = array();
 353          preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
 354          $varcount = sizeof($varrefs[1]);
 355          for ($i = 0; $i < $varcount; $i++)
 356          {
 357              $namespace = $varrefs[1][$i];
 358              $varname = $varrefs[3][$i];
 359              $new = $this->generate_block_varref($namespace, $varname, $concat);
 360  
 361              $code = str_replace($varrefs[0][$i], $new, $code);
 362          }
 363  
 364          // This will handle the remaining root-level varrefs
 365          $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' $concat ((isset(\$this->_tpldata['.'][0]['\\1'])) ? \$this->_tpldata['.'][0]['\\1'] : '') $concat '", $code);
 366  
 367          // Break it up into lines.
 368          $code_lines = explode("\n", $code);
 369  
 370          $block_nesting_level = 0;
 371          $block_names = array();
 372          $block_names[0] = '.';
 373  
 374          // Second: prepend echo ', append ' . "\n"; to each line.
 375          $line_count = sizeof($code_lines);
 376          for ($i = 0; $i < $line_count; $i++)
 377          {
 378              $code_lines[$i] = chop($code_lines[$i]);
 379              if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m))
 380              {
 381                  $n[0] = $m[0];
 382                  $n[1] = $m[1];
 383  
 384                  // Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. :)
 385                  if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n))
 386                  {
 387                      $block_nesting_level++;
 388                      $block_names[$block_nesting_level] = $m[1];
 389                      if ($block_nesting_level < 2)
 390                      {
 391                          // Block is not nested.
 392                          $code_lines[$i] = '$_' . $a[1] . '_count = (isset($this->_tpldata[\'' . $n[1] . '\'])) ?  sizeof($this->_tpldata[\'' . $n[1] . '\']) : 0;';
 393                          $code_lines[$i] .= 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
 394                          $code_lines[$i] .= '{';
 395                      }
 396                      else
 397                      {
 398                          // This block is nested.
 399  
 400                          // Generate a namespace string for this block.
 401                          $namespace = substr(implode('.', $block_names), 0, -1);
 402                          // strip leading period from root level..
 403                          $namespace = substr($namespace, 2);
 404                          // Get a reference to the data array for this block that depends on the
 405                          // current indices of all parent blocks.
 406                          $varref = $this->generate_block_data_ref($namespace, false);
 407                          // Create the for loop code to iterate over this block.
 408                          $code_lines[$i] = '$_' . $a[1] . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
 409                          $code_lines[$i] .= 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
 410                          $code_lines[$i] .= '{';
 411                      }
 412  
 413                      // We have the end of a block.
 414                      unset($block_names[$block_nesting_level]);
 415                      $block_nesting_level--;
 416                      $code_lines[$i] .= '} // END ' . $n[1];
 417                      $m[0] = $n[0];
 418                      $m[1] = $n[1];
 419                  }
 420                  else
 421                  {
 422                      // We have the start of a block.
 423                      $block_nesting_level++;
 424                      $block_names[$block_nesting_level] = $m[1];
 425                      if ($block_nesting_level < 2)
 426                      {
 427                          // Block is not nested.
 428                          $code_lines[$i] = '$_' . $m[1] . '_count = (isset($this->_tpldata[\'' . $m[1] . '\'])) ? sizeof($this->_tpldata[\'' . $m[1] . '\']) : 0;';
 429                          $code_lines[$i] .= 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
 430                          $code_lines[$i] .= '{';
 431                      }
 432                      else
 433                      {
 434                          // This block is nested.
 435  
 436                          // Generate a namespace string for this block.
 437                          $namespace = implode('.', $block_names);
 438                          // strip leading period from root level..
 439                          $namespace = substr($namespace, 2);
 440                          // Get a reference to the data array for this block that depends on the
 441                          // current indices of all parent blocks.
 442                          $varref = $this->generate_block_data_ref($namespace, false);
 443                          // Create the for loop code to iterate over this block.
 444                          $code_lines[$i] = '$_' . $m[1] . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
 445                          $code_lines[$i] .= 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
 446                          $code_lines[$i] .= '{';
 447                      }
 448                  }
 449              }
 450              else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m))
 451              {
 452                  // We have the end of a block.
 453                  unset($block_names[$block_nesting_level]);
 454                  $block_nesting_level--;
 455                  $code_lines[$i] = '} // END ' . $m[1];
 456              }
 457              else
 458              {
 459                  // We have an ordinary line of code.
 460                  if (!$do_not_echo)
 461                  {
 462                      $code_lines[$i] = "echo '" . $code_lines[$i] . "\n';\n";
 463                  }
 464                  else
 465                  {
 466                      $code_lines[$i] = '$' . $retvar . ".= '" . $code_lines[$i] . "\n';\n"; 
 467                  }
 468              }
 469          }
 470  
 471          // Bring it back into a single string of lines of code.
 472          $code = implode("\n", $code_lines);
 473          return $code;
 474      }
 475  
 476  
 477      /**
 478       * Generates a reference to the given variable inside the given (possibly nested)
 479       * block namespace. This is a string of the form:
 480       * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
 481       * It's ready to be inserted into an "echo" line in one of the templates.
 482       * NOTE: expects a trailing "." on the namespace.
 483       */
 484  	function generate_block_varref($namespace, $varname, $concat)
 485      {
 486          // Strip the trailing period.
 487          $namespace = substr($namespace, 0, strlen($namespace) - 1);
 488  
 489          // Get a reference to the data block for this namespace.
 490          $varref = $this->generate_block_data_ref($namespace, true);
 491          // Prepend the necessary code to stick this in an echo line.
 492  
 493          // Append the variable reference.
 494          $varref .= "['$varname']";
 495  
 496          $varref = "' $concat ((isset($varref)) ? $varref : '') $concat '";
 497  
 498          return $varref;
 499  
 500      }
 501  
 502  
 503      /**
 504       * Generates a reference to the array of data values for the given
 505       * (possibly nested) block namespace. This is a string of the form:
 506       * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
 507       *
 508       * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
 509       * NOTE: does not expect a trailing "." on the blockname.
 510       */
 511  	function generate_block_data_ref($blockname, $include_last_iterator)
 512      {
 513          // Get an array of the blocks involved.
 514          $blocks = explode('.', $blockname);
 515          $blockcount = sizeof($blocks) - 1;
 516          $varref = '$this->_tpldata';
 517          // Build up the string with everything but the last child.
 518          for ($i = 0; $i < $blockcount; $i++)
 519          {
 520              $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
 521          }
 522          // Add the block reference for the last child.
 523          $varref .= "['" . $blocks[$blockcount] . "']";
 524          // Add the iterator for the last child if requried.
 525          if ($include_last_iterator)
 526          {
 527              $varref .= '[$_' . $blocks[$blockcount] . '_i]';
 528          }
 529  
 530          return $varref;
 531      }
 532  
 533  }
 534  
 535  ?>


Generated: Mon Jan 14 19:21:40 2013 Cross-referenced by PHPXref 0.7.1