PHP模板解析引擎--phpbb

转载 2006年06月18日 09:42:00
<?
/**
* Template class. By Nathan Codding of the phpBB group.
* The interface was originally inspired by PHPLib templates,
* and the template file formats are quite similar.
*
*/

class Template {
        var 
$classname "Template";

        
// variable that holds all the data we'll be substituting into
        // the compiled templates.
        // ...
        // This will end up being a multi-dimensional array like this:
        // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
        // if it's a root-level variable, it'll be like this:
        // $this->_tpldata[.][0][varname] == value
        
var $_tpldata = array();


        
// Hash of filenames for each template handle.
        
var $files = array();

        
// Root template directory.
        
var $root "";

        
// this will hash handle names to the compiled code for that handle.
        
var $compiled_code = array();

        
// This will hold the uncompiled code for that handle.
        
var $uncompiled_code = array();

        
/**
         * Constructor. Simply sets the root dir.
         *
         */
        
function Template($root ".")
        {
                
$this->set_rootdir($root);
        }

        
/**
         * Destroys this template object. Should be called when you're done with it, in order
         * to clear out the template data so you can load/parse a new template set.
         */
        
function destroy()
        {
                
$this->_tpldata = array();
        }

        
/**
         * Sets the template root directory for this Template object.
         */
        
function set_rootdir($dir)
        {
                if (!
is_dir($dir))
                {
                        return 
false;
                }

                
$this->root $dir;
                return 
true;
        }

        
/**
         * Sets the template filenames for handles. $filename_array
         * should be a hash of handle => filename pairs.
         */
        
function set_filenames($filename_array)
        {
                if (!
is_array($filename_array))
                {
                        return 
false;
                }

                
reset($filename_array);
                while(list(
$handle$filename) = each($filename_array))
                {
                        
$this->files[$handle] = $this->make_filename($filename);
                }

                return 
true;
        }


        
/**
         * Load the file for the handle, compile the file,
         * and run the compiled code. This will print out
         * the results of executing the template.
         */
        
function pparse($handle)
        {
                if (!
$this->loadfile($handle))
                {
                        die(
"Template->pparse(): Couldn't load template file for handle $handle");
                }

                
// actually compile the template now.
                
if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle]))
                {
                        
// Actually compile the code now.
                        
$this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
                }

                
// Run the compiled code.
                
eval($this->compiled_code[$handle]);
                return 
true;
        }

        
/**
         * Inserts the uncompiled code for $handle as the
         * value of $varname in the root-level. This can be used
         * to effectively include a template in the middle of another
         * template.
         * Note that all desired assignments to the variables in $handle should be done
         * BEFORE calling this function.
         */
        
function assign_var_from_handle($varname$handle)
        {
                if (!
$this->loadfile($handle))
                {
                        die(
"Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
                }

                
// Compile it, with the "no echo statements" option on.
                
$_str "";
                
$code $this->compile($this->uncompiled_code[$handle], true'_str');

                
// evaluate the variable assignment.
                
eval($code);
                
// assign the value of the generated variable to the given varname.
                
$this->assign_var($varname$_str);

                return 
true;
        }

        
/**
         * Block-level variable assignment. Adds a new block iteration with the given
         * variable assignments. Note that this should only be called once per block
         * iteration.
         */
        
function assign_block_vars($blockname$vararray)
        {
                if (
strstr($blockname'.'))
                {
                        
// Nested block.
                        
$blocks explode('.'$blockname);
                        
$blockcount sizeof($blocks) - 1;
                        
$str '$this->_tpldata';
                        for (
$i 0$i $blockcount$i++)
                        {
                                
$str .= '['' . $blocks[$i] . '.']';
                                eval(
'$lastiteration = sizeof(' $str ') - 1;');
                                
$str .= '[' $lastiteration ']';
                        }
                        
// Now we add the block that we're actually assigning to.
                        // We're adding a new iteration to this block with the given
                        // variable assignments.
                        
$str .= '['' . $blocks[$blockcount] . '.'][] = $vararray;';

                        
// Now we evaluate this assignment we've built up.
                        
eval($str);
                }
                else
                {
                        
// Top-level block.
                        // Add a new iteration to this block with the variable assignments
                        // we were given.
                        
$this->_tpldata[$blockname '.'][] = $vararray;
                }

                return 
true;
        }

        
/**
         * Root-level variable assignment. Adds to current assignments, overriding
         * any existing variable assignment with the same name.
         */
        
function assign_vars($vararray)
        {
                
reset ($vararray);
                while (list(
$key$val) = each($vararray))
                {
                        
$this->_tpldata['.'][0][$key] = $val;
                }

                return 
true;
        }

        
/**
         * Root-level variable assignment. Adds to current assignments, overriding
         * any existing variable assignment with the same name.
         */
        
function assign_var($varname$varval)
        {
                
$this->_tpldata['.'][0][$varname] = $varval;

                return 
true;
        }


        
/**
         * Generates a full path+filename for the given filename, which can either
         * be an absolute name, or a name relative to the rootdir for this Template
         * object.
         */
        
function make_filename($filename)
        {
                
// Check if it's an absolute or relative path.
                
if (substr($filename01) != '/')
                {
                        
$filename $this->root '/' $filename;
                }

                if (!
file_exists($filename))
                {
                        die(
"Template->make_filename(): Error - file $filename does not exist");
                }

                return 
$filename;
        }


        
/**
         * If not already done, load the file for the given handle and populate
         * the uncompiled_code[] hash with its code. Do not compile.
         */
        
function loadfile($handle)
        {
                
// If the file for this handle is already loaded and compiled, do nothing.
                
if (isset($this->uncompiled_code[$handle]) && !empty($this->uncompiled_code[$handle]))
                {
                        return 
true;
                }

                
// If we don't have a file assigned to this handle, die.
                
if (!isset($this->files[$handle]))
                {
                        die(
"Template->loadfile(): No file specified for handle $handle");
                }

                
$filename $this->files[$handle];

                
$str implode("", @file($filename));
                if (empty(
$str))
                {
                        die(
"Template->loadfile(): File $filename for handle $handle is empty");
                }

                
$this->uncompiled_code[$handle] = $str;

                return 
true;
        }



        
/**
         * Compiles the given string of code, and returns
         * the result in a string.
         * If "do_not_echo" is true, the returned code will not be directly
         * executable, but can be used as part of a variable assignment
         * for use in assign_code_from_handle().
         */
        
function compile($code$do_not_echo false$retvar '')
        {
                
// replace  with / and then ' with '.
                
$code str_replace('/', '', $code);
                $code = str_replace('''
'/''$code);

                
// change template varrefs into PHP varrefs

                // This one will handle varrefs WITH namespaces
                
$varrefs = array();
                
preg_match_all('#{(([a-z0-9-_]+?.)+?)([a-z0-9-_]+?)}#is'$code$varrefs);
                
$varcount sizeof($varrefs[1]);
                for (
$i 0$i $varcount$i++)
                {
                        
$namespace $varrefs[1][$i];
                        
$varname $varrefs[3][$i];
                        
$new $this->generate_block_varref($namespace$varname);

                        
$code str_replace($varrefs[0][$i], $new$code);
                }

                
// This will handle the remaining root-level varrefs
                
$code preg_replace('#{([a-z0-9-_]*?)}#is''' . ( ( isset($this->_tpldata['.'][0]['1']) ) ? $this->_tpldata['.'][0]['1'] : '' ) . ''$code);

                
// Break it up into lines.
                
$code_lines explode("n"$code);

                
$block_nesting_level 0;
                
$block_names = array();
                
$block_names[0] = ".";

                
// Second: prepend echo ', append ' . "n"; to each line.
                
$line_count sizeof($code_lines);
                for (
$i 0$i $line_count$i++)
                {
                        
$code_lines[$i] = chop($code_lines[$i]);
                        if (
preg_match('#<!-- BEGIN (.*?) -->#'$code_lines[$i], $m))
                        {
                                
$n[0] = $m[0];
                                
$n[1] = $m[1];

                                
// Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. 
                                
if ( preg_match('#<!-- END (.*?) -->#'$code_lines[$i], $n) )
                                {
                                        
$block_nesting_level++;
                                        
$block_names[$block_nesting_level] = $m[1];
                                        if (
$block_nesting_level 2)
                                        {
                                                
// Block is not nested.
                                                
$code_lines[$i] = '$_' $a[1] . '_count = ( isset($this->_tpldata['' . $n[1] . '.']) ) ?  sizeof($this->_tpldata['' . $n[1] . '.']) : 0;';
                                                
$code_lines[$i] .= "n" 'for ($_' $n[1] . '_i = 0; $_' $n[1] . '_i < $_' $n[1] . '_count; $_' $n[1] . '_i++)';
                                                
$code_lines[$i] .= "n" '{';
                                        }
                                        else
                                        {
                                                
// This block is nested.

                                                // Generate a namespace string for this block.
                                                
$namespace implode('.'$block_names);
                                                
// strip leading period from root level..
                                                
$namespace substr($namespace2);
                                                
// Get a reference to the data array for this block that depends on the
                                                // current indices of all parent blocks.
                                                
$varref $this->generate_block_data_ref($namespacefalse);
                                                
// Create the for loop code to iterate over this block.
                                                
$code_lines[$i] = '$_' $a[1] . '_count = ( isset(' $varref ') ) ? sizeof(' $varref ') : 0;';
                                                
$code_lines[$i] .= "n" 'for ($_' $n[1] . '_i = 0; $_' $n[1] . '_i < $_' $n[1] . '_count; $_' $n[1] . '_i++)';
                                                
$code_lines[$i] .= "n" '{';
                                        }

                                        
// We have the end of a block.
                                        
unset($block_names[$block_nesting_level]);
                                        
$block_nesting_level--;
                                        
$code_lines[$i] .= '} // END ' $n[1];
                                        
$m[0] = $n[0];
                                        
$m[1] = $n[1];
                                }
                                else
                                {
                                        
// We have the start of a block.
                                        
$block_nesting_level++;
                                        
$block_names[$block_nesting_level] = $m[1];
                                        if (
$block_nesting_level 2)
                                        {
                                                
// Block is not nested.
                                                
$code_lines[$i] = '$_' $m[1] . '_count = ( isset($this->_tpldata['' . $m[1] . '.']) ) ? sizeof($this->_tpldata['' . $m[1] . '.']) : 0;';
                                                
$code_lines[$i] .= "n" 'for ($_' $m[1] . '_i = 0; $_' $m[1] . '_i < $_' $m[1] . '_count; $_' $m[1] . '_i++)';
                                                
$code_lines[$i] .= "n" '{';
                                        }
                                        else
                                        {
                                                
// This block is nested.

                                                // Generate a namespace string for this block.
                                                
$namespace implode('.'$block_names);
                                                
// strip leading period from root level..
                                                
$namespace substr($namespace2);
                                                
// Get a reference to the data array for this block that depends on the
                                                // current indices of all parent blocks.
                                                
$varref $this->generate_block_data_ref($namespacefalse);
                                                
// Create the for loop code to iterate over this block.
                                                
$code_lines[$i] = '$_' $m[1] . '_count = ( isset(' $varref ') ) ? sizeof(' $varref ') : 0;';
                                                
$code_lines[$i] .= "n" 'for ($_' $m[1] . '_i = 0; $_' $m[1] . '_i < $_' $m[1] . '_count; $_' $m[1] . '_i++)';
                                                
$code_lines[$i] .= "n" '{';
                                        }
                                }
                        }
                        else if (
preg_match('#<!-- END (.*?) -->#'$code_lines[$i], $m))
                        {
                                
// We have the end of a block.
                                
unset($block_names[$block_nesting_level]);
                                
$block_nesting_level--;
                                
$code_lines[$i] = '} // END ' $m[1];
                        }
                        else
                        {
                                
// We have an ordinary line of code.
                                
if (!$do_not_echo)
                                {
                                        
$code_lines[$i] = 'echo '' . $code_lines[$i] . '' . "/n";';
                                }
                                else
                                {
                                        
$code_lines[$i] = '$' $retvar '.= '' . $code_lines[$i] . '' . "/n";'
                                }
                        }
                }

                
// Bring it back into a single string of lines of code.
                
$code implode("n"$code_lines);
                return 
$code        ;

        }


        
/**
         * Generates a reference to the given variable inside the given (possibly nested)
         * block namespace. This is a string of the form:
         * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
         * It's ready to be inserted into an "echo" line in one of the templates.
         * NOTE: expects a trailing "." on the namespace.
         */
        
function generate_block_varref($namespace$varname)
        {
                
// Strip the trailing period.
                
$namespace substr($namespace0strlen($namespace) - 1);

                
// Get a reference to the data block for this namespace.
                
$varref $this->generate_block_data_ref($namespacetrue);
                
// Prepend the necessary code to stick this in an echo line.

                // Append the variable reference.
                
$varref .= '['' . $varname . '']';

                
$varref '' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' '' ) . '';

                return 
$varref;

        }


        
/**
         * Generates a reference to the array of data values for the given
         * (possibly nested) block namespace. This is a string of the form:
         * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
         *
         * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
         * NOTE: does not expect a trailing "." on the blockname.
         */
        
function generate_block_data_ref($blockname$include_last_iterator)
        {
                
// Get an array of the blocks involved.
                
$blocks explode("."$blockname);
                
$blockcount sizeof($blocks) - 1;
                
$varref '$this->_tpldata';
                
// Build up the string with everything but the last child.
                
for ($i 0$i $blockcount$i++)
                {
                        
$varref .= '['' . $blocks[$i] . '.'][$_' $blocks[$i] . '_i]';
                }
                
// Add the block reference for the last child.
                
$varref .= '['' . $blocks[$blockcount] . '.']';
                
// Add the iterator for the last child if requried.
                
if ($include_last_iterator)
                {
                        
$varref .= '[$_' $blocks[$blockcount] . '_i]';
                }

                return 
$varref;
        }

}        
?>

phpBB3风格的模板文件列表

英文原文:Knowledge Base - phpBB3 Styles' files list作者:TheIlluminative译者:greatboy描述:一个关于 phpBB3 样式风格里使用的所...
  • yzc509
  • yzc509
  • 2011年06月03日 08:49
  • 1489

自定义php模板引擎

模板引擎的思想是来源于MVC(Model View Controller)模型,即模型层、视图层、控制器层。     在Web端,模型层为数据库的操作;视图层就是模板,也就是Web前端;Contro...
  • czrzchao
  • czrzchao
  • 2016年08月03日 22:40
  • 2201

php学习笔记(三十三)php自定义模板引擎的实现

自己实现简单的模板引擎:方面php的逻辑与页面进行分离 模板类: 调用的页面: ...
  • devilzy2656
  • devilzy2656
  • 2013年01月06日 16:32
  • 709

25个顶级PHP模板引擎

为了找到一个好的模板引擎,我在互联网上进行搜索,目前已经整理出了以下名单: Smarty Smarty的特点是将模板编译成PHP脚本,然后执行这些脚本。很快,非常灵活。 ...
  • dreamboycx
  • dreamboycx
  • 2017年02月07日 10:51
  • 476

phpbb3结合自己网站实现session登陆

又是新的一年了,2013,在这里祝大家元旦快乐!! 正题,phpbb3是一个很不错的php论坛,界面也很不错,性能也好 但我想让它和我的网站整合在一起,用户数据完全就用论坛的数据,怎么弄呢 去谷...
  • backgarden_straw
  • backgarden_straw
  • 2013年01月01日 04:21
  • 2123

php 编写一个简单的模板引擎

php web开发中广泛采取mvc的设计模式,controller传递给view层的数据,必须通过模板引擎才能解析出来。实现一个简单的仅仅包含if,foreach标签,解析$foo变量的模板引擎。...
  • u012371137
  • u012371137
  • 2016年07月22日 17:07
  • 2140

PHP搭建自己的web框架-视图/模板引擎

视图,MVC中的V,View,如何将数据通过合适的格式展现给用户或调用方。当然使用什么格式展现由控制器直接控制,但根本原因由人或系统决定。本文主要描述的是如何在web框架中输出网页视图,也就是HTML...
  • rariki
  • rariki
  • 2016年05月03日 01:28
  • 1318

一个自己写的PHP模板引擎

这是一个自己写的编译型的模板引擎(不包括缓存部分)贴上代码。有问题可以随时跟帖。 单文件版:JTemplate.class.php   1 2 3...
  • judyge
  • judyge
  • 2016年06月25日 22:19
  • 408

smarty模板引擎--php高级最详细教程

Smarty(模板引擎) 原创 一、什么是模板引擎? Smarty是一个php模板引擎。更准确的说,它分开了逻辑程序和外在的内容,提供了一种易于管理的方法。可以描述为应用程序员和美工扮演了不同...
  • wulove52
  • wulove52
  • 2016年08月30日 22:30
  • 6695

可以免费做商业网站的CMS讨论

目前国内使用过PHPCMS   DEDECMS织梦    科讯CMS  帝国、Discuz、Ecshop等,但是他们都是个人非盈利免费,商业、政府、机构授权收费。 使用什么CMS可以免费做商业网站呢...
  • bjash
  • bjash
  • 2013年01月09日 15:53
  • 11226
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:PHP模板解析引擎--phpbb
举报原因:
原因补充:

(最多只允许输入30个字)