home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 April / PCWorld_2005-04_cd.bin / akce / web / phpnuke / PHP-Nuke-7.5.exe / html / includes / template.php < prev    next >
PHP Script  |  2004-07-22  |  23KB  |  520 lines

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