[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/contrib/ -> template_db_cache.php (source)

   1  <?php
   2  /***************************************************************************
   3   *                              template.inc
   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   *
  16   *   This program is free software; you can redistribute it and/or modify
  17   *   it under the terms of the GNU General Public License as published by
  18   *   the Free Software Foundation; either version 2 of the License, or
  19   *   (at your option) any later version.
  20   *
  21   ***************************************************************************/
  22  
  23  /**
  24   * Template class. By Nathan Codding of the phpBB group.
  25   * The interface was originally inspired by PHPLib templates,
  26   * and the template file formats are quite similar.
  27   *
  28   */
  29  
  30  class Template {
  31      var $classname = "Template";
  32  
  33      // variable that holds all the data we'll be substituting into
  34      // the compiled templates.
  35      // ...
  36      // This will end up being a multi-dimensional array like this:
  37      // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
  38      // if it's a root-level variable, it'll be like this:
  39      // $this->_tpldata[.][0][varname] == value
  40      var $_tpldata = array();
  41  
  42      // Hash of filenames for each template handle.
  43      var $files = array();
  44  
  45      // Root template directory.
  46      var $root = "";
  47  
  48      // this will hash handle names to the compiled code for that handle.
  49      var $compiled_code = array();
  50  
  51      // This will hold the uncompiled code for that handle.
  52      var $uncompiled_code = array();
  53  
  54      /**
  55       * Constructor. Simply sets the root dir.
  56       *
  57       */
  58  	function Template($root = '.')
  59      {
  60          global $db;
  61  
  62          $this->set_rootdir($root);
  63          $this->db = &$db;
  64  
  65          $this->pparse_order = array();
  66      }
  67  
  68      /**
  69       * Destroys this template object. Should be called when you're done with it, in order
  70       * to clear out the template data so you can load/parse a new template set.
  71       */
  72  	function destroy()
  73      {
  74          $this->_tpldata = array();
  75      }
  76  
  77      /**
  78       * Sets the template root directory for this Template object.
  79       */
  80  	function set_rootdir($dir)
  81      {
  82          if (!is_dir($dir))
  83          {
  84              return false;
  85          }
  86  
  87          $this->root = $dir;
  88          return true;
  89      }
  90  
  91      /**
  92       * Sets the template filenames for handles. $filename_array
  93       * should be a hash of handle => filename pairs.
  94       */
  95  	function set_filenames($filename_array)
  96      {
  97          global $table_prefix;
  98  
  99          if ( !is_array($filename_array) )
 100          {
 101              return false;
 102          }
 103  
 104          $template_names = '';
 105          @reset($filename_array);
 106          while ( list($handle, $filename) = @each($filename_array) )
 107          {
 108              $this->files[$handle] = $this->make_filename($filename);
 109              $template_names .= ( $template_names != '' ) ? ", '" . addslashes($this->files[$handle]) . "'" : "'" . addslashes($this->files[$handle]) . "'";
 110          }
 111  
 112          $sql = "SELECT * 
 113              FROM " . $table_prefix . "template_cache 
 114              WHERE template_name IN ($template_names)";
 115          if ( $result = $this->db->sql_query($sql) )
 116          {
 117              while( $row = $this->db->sql_fetchrow($result) )
 118              {
 119                  if( $row['template_cached'] == filemtime($row['template_name']) )
 120                  {
 121                      $this->compiled_code[$row['template_handle']] = $row['template_compile'];
 122                      $this->echo_compiled[$row['template_handle']] = $row['template_echo'];
 123                  }
 124              } 
 125          } 
 126  
 127          $this->db->sql_freeresult();
 128  
 129          return true;
 130      }
 131  
 132  
 133      /**
 134       * Load the file for the handle, compile the file,
 135       * and run the compiled code. This will print out
 136       * the results of executing the template.
 137       */
 138  	function pparse($handle)
 139      {
 140          global $table_prefix;
 141  
 142          if( empty($this->compiled_code[$handle]) )
 143          {
 144              if ( !$this->loadfile($handle) )
 145              {
 146                  die("Template->pparse(): Couldn't load template file for handle $handle");
 147              }
 148  
 149              //
 150              // Actually compile the code now.
 151              //
 152              $this->echo_compiled[$handle] = 1;
 153              $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
 154  
 155              $sql = "REPLACE INTO " . $table_prefix . "template_cache (template_name, template_handle, template_cached, template_compile) VALUES ('" . addslashes($this->files[$handle]) . "', '" . addslashes($handle) . "', " . filemtime($this->files[$handle]) . ", '" . addslashes($this->compiled_code[$handle]) . "')";
 156              if ( !($result = $this->db->sql_query($sql)) )
 157              {
 158                  die("Couldn't insert template into cache!");
 159              }
 160  
 161          }
 162  
 163          $_str = "";
 164          eval($this->compiled_code[$handle]);
 165  
 166          if( $_str != "" ) 
 167          {
 168              echo $_str;
 169          }
 170  
 171          return true;
 172      }
 173  
 174      /**
 175       * Inserts the uncompiled code for $handle as the
 176       * value of $varname in the root-level. This can be used
 177       * to effectively include a template in the middle of another
 178       * template.
 179       * Note that all desired assignments to the variables in $handle should be done
 180       * BEFORE calling this function.
 181       */
 182  	function assign_var_from_handle($varname, $handle)
 183      {
 184          global $table_prefix;
 185  
 186          if( empty($this->compiled_code[$handle]) )
 187          {
 188              if ( !$this->loadfile($handle) )
 189              {
 190                  die("Template->pparse(): Couldn't load template file for handle $handle");
 191              }
 192  
 193              $code = $this->compile($this->uncompiled_code[$handle], true, '_str');
 194  
 195              $sql = "REPLACE INTO " . $table_prefix . "template_cache (template_name, template_handle, template_echo, template_cached, template_compile) VALUES ('" . addslashes($this->files[$handle]) . "', '" . addslashes($handle) . "', 0, " . filemtime($this->files[$handle]) . ", '" . addslashes($code) . "')";
 196              if ( !($result = $this->db->sql_query($sql)) )
 197              {
 198                  die("Couldn't insert template into cache!");
 199              }
 200          }
 201          else
 202          {
 203              $code = $this->compiled_code[$handle];
 204          }
 205  
 206          // Compile It, With The "no Echo Statements" Option On.
 207          $_str = "";
 208          // evaluate the variable assignment.
 209          eval($code);
 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              $str = '$this->_tpldata';
 229              for ($i = 0; $i < $blockcount; $i++)
 230              {
 231                  $str .= '[\'' . $blocks[$i] . '.\']';
 232                  eval('$lastiteration = sizeof(' . $str . ') - 1;');
 233                  $str .= '[' . $lastiteration . ']';
 234              }
 235              // Now we add the block that we're actually assigning to.
 236              // We're adding a new iteration to this block with the given
 237              // variable assignments.
 238              $str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';
 239  
 240              // Now we evaluate this assignment we've built up.
 241              eval($str);
 242          }
 243          else
 244          {
 245              // Top-level block.
 246              // Add a new iteration to this block with the variable assignments
 247              // we were given.
 248              $this->_tpldata[$blockname . '.'][] = $vararray;
 249          }
 250  
 251          return true;
 252      }
 253  
 254      /**
 255       * Root-level variable assignment. Adds to current assignments, overriding
 256       * any existing variable assignment with the same name.
 257       */
 258  	function assign_vars($vararray)
 259      {
 260          reset ($vararray);
 261          while (list($key, $val) = each($vararray))
 262          {
 263              $this->_tpldata['.'][0][$key] = $val;
 264          }
 265  
 266          return true;
 267      }
 268  
 269      /**
 270       * Root-level variable assignment. Adds to current assignments, overriding
 271       * any existing variable assignment with the same name.
 272       */
 273  	function assign_var($varname, $varval)
 274      {
 275          $this->_tpldata['.'][0][$varname] = $varval;
 276  
 277          return true;
 278      }
 279  
 280  
 281      /**
 282       * Generates a full path+filename for the given filename, which can either
 283       * be an absolute name, or a name relative to the rootdir for this Template
 284       * object.
 285       */
 286  	function make_filename($filename)
 287      {
 288          // Check if it's an absolute or relative path.
 289          if (substr($filename, 0, 1) != '/')
 290          {
 291              $filename = $this->root . '/' . $filename;
 292          }
 293  
 294          if (!file_exists($filename))
 295          {
 296              die("Template->make_filename(): Error - file $filename does not exist");
 297          }
 298  
 299          return $filename;
 300      }
 301  
 302  
 303      /**
 304       * If not already done, load the file for the given handle and populate
 305       * the uncompiled_code[] hash with its code. Do not compile.
 306       */
 307  	function loadfile($handle)
 308      {
 309          // If the file for this handle is already loaded and compiled, do nothing.
 310          if ( !empty($this->uncompiled_code[$handle]) )
 311          {
 312              return true;
 313          }
 314  
 315          // If we don't have a file assigned to this handle, die.
 316          if (!isset($this->files[$handle]))
 317          {
 318              die("Template->loadfile(): No file specified for handle $handle");
 319          }
 320  
 321          $filename = $this->files[$handle];
 322  
 323          $str = implode("", @file($filename));
 324          if (empty($str))
 325          {
 326              die("Template->loadfile(): File $filename for handle $handle is empty");
 327          }
 328  
 329          $this->uncompiled_code[$handle] = $str;
 330  
 331          return true;
 332      }
 333  
 334  
 335  
 336      /**
 337       * Compiles the given string of code, and returns
 338       * the result in a string.
 339       * If "do_not_echo" is true, the returned code will not be directly
 340       * executable, but can be used as part of a variable assignment
 341       * for use in assign_code_from_handle().
 342       */
 343  	function compile($code, $do_not_echo = false, $retvar = '')
 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);
 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', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $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] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
 394                          $code_lines[$i] .= "\n" . '{';
 395                      }
 396                      else
 397                      {
 398                          // This block is nested.
 399  
 400                          // Generate a namespace string for this block.
 401                          $namespace = implode('.', $block_names);
 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] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
 410                          $code_lines[$i] .= "\n" . '{';
 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] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
 430                          $code_lines[$i] .= "\n" . '{';
 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] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
 446                          $code_lines[$i] .= "\n" . '{';
 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";';
 463                  }
 464                  else
 465                  {
 466                      $code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\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      /**
 479       * Generates a reference to the given variable inside the given (possibly nested)
 480       * block namespace. This is a string of the form:
 481       * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
 482       * It's ready to be inserted into an "echo" line in one of the templates.
 483       * NOTE: expects a trailing "." on the namespace.
 484       */
 485  	function generate_block_varref($namespace, $varname)
 486      {
 487          // Strip the trailing period.
 488          $namespace = substr($namespace, 0, strlen($namespace) - 1);
 489  
 490          // Get a reference to the data block for this namespace.
 491          $varref = $this->generate_block_data_ref($namespace, true);
 492          // Prepend the necessary code to stick this in an echo line.
 493  
 494          // Append the variable reference.
 495          $varref .= '[\'' . $varname . '\']';
 496  
 497          $varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \'';
 498  
 499          return $varref;
 500  
 501      }
 502  
 503  
 504      /**
 505       * Generates a reference to the array of data values for the given
 506       * (possibly nested) block namespace. This is a string of the form:
 507       * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
 508       *
 509       * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
 510       * NOTE: does not expect a trailing "." on the blockname.
 511       */
 512  	function generate_block_data_ref($blockname, $include_last_iterator)
 513      {
 514          // Get an array of the blocks involved.
 515          $blocks = explode(".", $blockname);
 516          $blockcount = sizeof($blocks) - 1;
 517          $varref = '$this->_tpldata';
 518          // Build up the string with everything but the last child.
 519          for ($i = 0; $i < $blockcount; $i++)
 520          {
 521              $varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]';
 522          }
 523          // Add the block reference for the last child.
 524          $varref .= '[\'' . $blocks[$blockcount] . '.\']';
 525          // Add the iterator for the last child if requried.
 526          if ($include_last_iterator)
 527          {
 528              $varref .= '[$_' . $blocks[$blockcount] . '_i]';
 529          }
 530  
 531          return $varref;
 532      }
 533  
 534  }
 535  
 536  ?>


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