你现在的位置:首页 > PHP网站建设知识库 > phpcms > 正文

phpcms代码分析:模板代码和机制

总体来讲,就是正则替换之后生成标准的php文件,然后include该文件


1.模板配置 include/config.inc.php


<?php  
//模板相关配置  
define('TPL_ROOT', PHPCMS_ROOT.'templates/'); //模板保存物理路径  
define('TPL_NAME', 'default'); //当前模板方案目录  
define('TPL_CSS', 'default'); //当前样式目录  
define('TPL_CACHEPATH', PHPCMS_ROOT.'data/cache_template/'); //模板缓存物理路径  
define('TPL_REFRESH', 1); //是否开启模板缓存自动刷新  
 

2.模板函数 global.func.php

 
<?php  
/** 
 * 获取指定模块编译后的模板内容 
 * 
 * @param string      模块英文名,可选参数,默认为phpcms 
 * @param string      模板英文名称,可选参数,默认为index 
 * @param int 是否为标签模板,可选参数,默认为0 
 * @return 返回模板html代码 
 */  
function template($module = 'phpcms', $template = 'index', $istag = 0)  
{  
    $compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php'; //得到生成后的模板文件  
    //如果模板缓存设置为自动刷新,且(模板文件不存在或模板修改时间大于生成后模板时间或tag模板时间大于生成后的模板时间,则重新生成。  
    if(TPL_REFRESH && (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html') > @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/tag.inc.php') > @filemtime($compiledtplfile)))  
    {  
        require_once PHPCMS_ROOT.'include/template.func.php'; //加载include/template.func.php 模板函数  
        template_compile($module, $template, $istag);   //解释模板,并生成可执行的php 文件  
    }  
    return $compiledtplfile; //返回生成后模板文件(可执行的php文件)  
}  
/** 
 * 得到模板内容 
 * 
 * @param string 模块名 
 * @param string 文件名 
 * @return 模板内容 
 */  
function tpl_data($module = 'phpcms', $template = 'index')  
{  
    @extract($GLOBALS, EXTR_SKIP); //将$GLOBAL数组围成变量  
    ob_start();   //开始缓存  
    include template($module, $template);  //得到解释后可执行的php模板文件  
    $data = ob_get_contents();  //得到缓存数据,即php模板内容  
    ob_clean();  
    return $data;    
}  


3.模板解释函数 (include/template.func.php)

 


<?php  
/** 
 * 模板编译 
 * 
 * @param string 模块名 
 * @param string 模板名 
 * @param int 是否含有tag 
 * @return 模板的字数 
 */  
function template_compile($module, $template, $istag = 0)  
{  
    $tplfile = TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html';  //获取模板路径  
    $content = @file_get_contents($tplfile);  //得到模板内容  
    if($content === false) showmessage("$tplfile is not exists!");  //模板不存存  
    $compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php'; //编译后的模板文件  
    $content = ($istag || substr($template, 0, 4) == 'tag_') ? '<?php function _tag_'.$module.'_'.$template.'($data, $number, $rows, $count, $page, $pages, $setting){ global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?>'.template_parse($content, 1).'<?php } ?>' : template_parse($content);  //如果含有tag_,则加载tag函数  
    $strlen = file_put_contents($compiledtplfile, $content);  //将编译后的内容放在php文件中  
    @chmod($compiledtplfile, 0777);  
    return $strlen;  
}  
/** 
 * 更新编译后的模板内容 
 * 
 * @param string 模板路径 
 * @param string 编译后的模板路径 
 * @return 编译后的模板内容长度 
 */  
function template_refresh($tplfile, $compiledtplfile)  
{  
    $str = file_get_contents($tplfile);  
    $str = template_parse($str);  
    $strlen = file_put_contents($compiledtplfile, $str);  
    @chmod($compiledtplfile, 0777);  
    return $strlen;  
}  
/** 
 * 生成某一个模块的模板内容 
 * 
 * @param string 模块名 
 * @return bool 
 */  
function template_module($module)  
{  
    $files = glob(TPL_ROOT.TPL_NAME.'/'.$module.'/*.html');  
    if(is_array($files))  
    {  
        foreach($files as $tpl)  
        {  
            $template = str_replace('.html', '', basename($tpl));  
            template_compile($module, $template);  
        }  
    }  
    return TRUE;  
}  
/**  
 * 更新所有模块的模板  
 *  
 * @return bool  
 */  
function template_cache()  
{  
    global $MODULE;  
    foreach($MODULE as $module=>$m)  
    {  
        template_module($module);  
    }  
    return TRUE;  
}  
function template_block($blockid)  
{  
    $tplfile = TPL_ROOT.TPL_NAME.'/phpcms/block/'.$blockid.'.html';  
    $compiledtplfile = TPL_CACHEPATH.'phpcms_block_'.$blockid.'.tpl.php';  
    if(TPL_REFRESH && (!file_exists($compiledtplfile) || @filemtime($tplfile) > @filemtime($compiledtplfile)))  
    {  
        template_refresh($tplfile, $compiledtplfile);  
    }  
    return $compiledtplfile;  
}  
/** 
 * 模板解释 
 * 
 * @param string $str 
 * @param int $istag 
 * @return string 
 * @link 
 */  
function template_parse($str, $istag = 0)  
{  
    $str = preg_replace("/([/n/r]+)/t+/s","//1",$str);  //用 /n/r 过滤掉 tab制表符,  //1 是逆向引用了第一个括号里面/n换行/r换页匹配的文本   
    $str = preg_replace("//</!/-/-/{(.+?)/}/-/-/>/s", "{//1}",$str);// 以 {xx} 来替换 <!--{xx}--> {xx}在下面肯定还要进行第二次正则替换,要不是不能在PHP里面运行的。  .+? 和 .+ 一个是懒惰 一个是贪婪。  看名字就知道。  
    $str = preg_replace("//{template/s+(.+)/}/","<?php include template(//1); ?>",$str);/*把模板里面的 {template 'xx','jj'} 编译成PHP标准写法:<?php include template('xx','jj') ?>   大家可能一看就明白了: include template()  这个在那里见过。对了。这个在PHP里也可以运行的。因为 template() 函数不是定义了吗。*/  
    $str = preg_replace("//{include/s+(.+)/}/","<?php include //1; ?>",$str);/* 模板里面的 {include xx.php} 编译成 PHP文件里的 <?php include xx.php?>**/  
    $str = preg_replace("//{php/s+(.+)/}/","<?php //1?>",$str);/* 模板里面的 {php xxxx} 编译成 <?php xxxx?>  大家也应该明白了。 xxxx 肯定是PHP的标准语法拉。 所以phpcms模板语句: {php } 就是用来给你在模板里写要运行的PHP语句。在smarty 里也有这功能**/  
    $str = preg_replace("//{if/s+(.+?)/}/","<?php if(//1) { ?>",$str);/* 这个就更简单了。 把模板里面的{if xxxx}  编译成 <?php if(){?>  看这样一步一步的把一些自己定义的语句编译成PHP的标准语法。这个就叫模板引擎了。**/  
    $str = preg_replace("//{else/}/","<?php } else { ?>",$str); /* {else } 转 <?php } else {?>**/  
    $str = preg_replace("//{elseif/s+(.+?)/}/","<?php } elseif (//1) { ?>",$str); /* {elseif } 转 <?php } elseif {?>**/  
    $str = preg_replace("//{//if/}/","<?php } ?>",$str);/* {/if} 转 <?php }?>  phpcms 模板语法有: {/if}的哦。大家别忘了,要不 php肯定运行不了**/  
    $str = preg_replace("//{loop/s+(/S+)/s+(/S+)/}/","<?php if(is_array(//1)) foreach(//1 AS //2) { ?>",$str);/* 下面就是循环了。模板里用{loop xx jj} 其实编译成了PHP的 foreach(xx AS jj) 这样大家都会用了吧**/  
    $str = preg_replace("//{loop/s+(/S+)/s+(/S+)/s+(/S+)/}/","<?php if(is_array(//1)) foreach(//1 AS //2 => //3) { ?>",$str);/* 这句和上面也差不多。不过是多了个取出数组的标名  {loop xx jj yy}  成 foreach(xx as jj=> yy)**/  
    $str = preg_replace("//{//loop/}/","<?php } ?>",$str); /* 循环结束别忘了 {/loop}  对应PHP的 <?php }?>**/  
    $str = preg_replace("//{//get/}/","<?php } unset(/$DATA); ?>",$str);  
    $str = preg_replace("//{tag_([^}]+)/}/e", "get_tag('//1')", $str);/* {tag_xx}  替换为 get_tag('xx')  get_tag()  函数是自己定义的函数,因为phpcms 的模板引擎应用了标签功能。这个函数就是为了调用标签的。**/  
    $str = preg_replace("//{get/s+([^}]+)/}/e", "get_parse('//1')", $str);  
    $str = preg_replace("//{([a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff:]*/(([^{}]*)/))/}/","<?php echo //1;?>",$str);/* {xxx(jj)}  这么个奇怪的东西。因为奇怪所以我找了下PHPCMS的模板文件。找了几个文件都没发现这个怪物。大家有谁找到的说下我去看下。怕是我理解错了正则。先谢了**/  
    $str = preg_replace("//{//$([a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff:]*/(([^{}]*)/))/}/","<?php echo //1;?>",$str);/* {$xxx(wwsd)} 专换成 <?php echo xxx(wwsd)?>   当然了 xxx() 是程序中定义过的函数**/  
    $str = preg_replace("//{(//$[a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff]*)/}/","<?php echo //1;?>",$str);/* 把{$xxjj} 转成 <?php echo $xxjj?>  当然了是把变量输出**/  
    $str = preg_replace("//{(//$[a-zA-Z0-9_/[/]/'/"/$/x7f-/xff]+)/}/es", "addquote('<?php echo //1;?>')",$str);/* 主要是把{$xxx['jj']} 转成 <?php echo $xxx['jj']?>  addquote() 函数自己定义的看下面,二次过滤。有代验证,头昏了看太久的黄色字。我昏**/  
    $str = preg_replace("//{([A-Z_/x7f-/xff][A-Z0-9_/x7f-/xff]*)/}/s", "<?php echo //1;?>",$str);/* {XXJJ}  <?php echo XXJJ?>  XXJJ 是我们定义的常量**/  
    if(!$istag) $str = "<?php defined('IN_PHPCMS') or exit('Access Denied'); ?>".$str;  
    return $str;  
}  
////这个函数在  上面这个编译函数里面看到了。 其实就是获取对应标签的内容,头有点昏,下节再说标签吧。  
function get_tag($tagname)  
{  
    global $TAG;  
    if(!isset($TAG)) $TAG = cache_read('tag.inc.php', TPL_ROOT.TPL_NAME.'/');  
    return isset($TAG[$tagname]) ? '<?php echo '.$TAG[$tagname].';?>' : '{tag_'.$tagname.'}';  
}  
function addquote($var)  
{  
    return str_replace("///"", "/"", preg_replace("//[([a-zA-Z0-9_/-/./x7f-/xff]+)/]/s", "['//1']", $var));  
}  
function get_parse($str)  
{  
    preg_match_all("/([a-z]+)/=/"([^/"]+)/"/i", stripslashes($str), $matches, PREG_SET_ORDER);  
    foreach($matches as $v)  
    {  
        $r[$v[1]] = $v[2];  
    }  
    extract($r);  
    if(!isset($dbsource)) $dbsource = '';  
    if(!isset($dbname)) $dbname = '';  
    if(!isset($sql)) $sql = '';  
    if(!isset($rows)) $rows = 0;  
    if(!isset($urlrule)) $urlrule = '';  
    if(!isset($catid)) $catid = 0;  
    if(!isset($distinctfield)) $distinctfield = '';  
    if(!isset($return) || !preg_match("/^/w+$/i", $return)) $return = 'r';  
    if(isset($page))  
    {  
        $str = "<?php /$ARRAY = get(/"$sql/", $rows, $page, /"$dbname/", /"$dbsource/", /"$urlrule/",/"$distinctfield/",/"$catid/");/$DATA=/$ARRAY['data'];/$total=/$ARRAY['total'];/$count=/$ARRAY['count'];/$pages=/$ARRAY['pages'];unset(/$ARRAY);foreach(/$DATA AS /$n=>/${$return}){/$n++;?>";  
    }  
    else  
    {  
        $str = substr($str, -1) == '/' ? "<?php /${$return} = get(/"$sql/", -1, 0, /"$dbname/", /"$dbsource/");?>" : "<?php /$DATA = get(/"$sql/", $rows, 0, /"$dbname/", /"$dbsource/");foreach(/$DATA AS /$n => /${$return}) { /$n++;?>";  
    }  
    return $str;  
}  
?>