discuz 解析模板 分析 自己用

我记得我刚开始学PHP的时候,对模板解析实在是觉得很奇怪,不知道这个原理怎么实现的,后来看书看多了也明白有一个著名的Smarty在那,曾经也用过一段,不过感觉不是很好,就开始分析Discuz 的模板技术是怎么实现的了,然后我把这个模板解析的代码分离出来了,觉得很好用,用了一段时间, Discuz 的模板解析是用正则表达式替换一些模板中的规定的语言标记,然后呢,写到forumdata/templates中,再用include 引用到index, forumdisplay等等中,和smarty的原理基本上相同,只是功能没有smarty那么多,smarty内建了一个cache来着…连个User Guide都几百页…
  呵呵,不过现在基本上两个都没用过,正则表达式好是好用,不过正则的效率不是很高,以前看PHP技术文档的时候说能不用正则就尽量不要用,那东西烦 着,现在做什么项目基本上用的是框架,MVC的模式,View中的代码一般不用模板解析出来,混杂php代码在里面,也觉得不错,OOP的开发效率比较 高,很多地方重用代码是很开心的~!

  Discuz 的模板解析要分析出来只要用到两个文件:./include /global.func.php和. /include /template .func.php,global只要一个函数就够了,template 要全部的文件下面我就分开讲一下,会比较详细,大家耐心看:

Section One--./include /global.func.php---->template function

CODE:

function template ($file, $templateid = 0, $tpldir = '') {
        global $tplrefresh;

        $tpldir = $tpldir ? $tpldir : TPLDIR;
        $templateid = $templateid ? $templateid : TEMPLATEID;

        $tplfile = DISCUZ_ROOT.'./'.$tpldir.'/'.$file.'.htm';
        $objfile = DISCUZ_ROOT.'./forumdata/templates/'.$templateid.'_'.$file.'.tpl.php';
        if(TEMPLATEID != 1 && $templateid != 1 && !file_exists($tplfile)) {
                return template ($file, 1, './templates/default/');
        }
        if($tplrefresh == 1 || ($tplrefresh > 1 && substr($GLOBALS['timestamp'], -1) > $tplrefresh)) {
                if(@filemtime($tplfile) > @filemtime($objfile)) {
                        require_once DISCUZ_ROOT.'./include /template .func.php';
                        parse_template($file, $templateid, $tpldir);
                }
        }
        return $objfile;
}
这个函数一共有三个传入参数:

QUOTE:

$file 表示模板名
$templateid 表示模板id
$tpldir 表示模板目录

CODE:

global $tplrefresh; 这个是把$tplrefresh作为一个全局变量,tplrefresh表示是不是刷新模板

CODE:

$tpldir = $tpldir ? $tpldir : TPLDIR;
        $templateid = $templateid ? $templateid : TEMPLATEID;
给$tpldir和$templateid赋值,如果没有传进来就用常量TPLDIR和TEMPLATEID给它们值

CODE:

$tplfile = DISCUZ_ROOT.'./'.$tpldir.'/'.$file.'.htm';
        $objfile = DISCUZ_ROOT.'./forumdata/templates/'.$templateid.'_'.$file.'.tpl.php';
这里是把$tplfile(表示的是模板文件)和$objfile(表示的是要编译成的文件)赋值

CODE:

if(TEMPLATEID != 1 && $templateid != 1 && !file_exists($tplfile)) {
                return template ($file, 1, './templates/default/');
        }

防止TEMPLATEID不等于1且$templateid不等于1,而且模板文件不存在导致空白问题。
这里也可以算一个迭代,也可以不算,就是把1作为第二个参数再调用函数本身。

 

 技术末学 发布于2007-07-04 10:18:09

CODE:

if($tplrefresh == 1 || ($tplrefresh > 1 && substr($GLOBALS['timestamp'], -1) > $tplrefresh)) {
                if(@filemtime($tplfile) > @filemtime($objfile)) {
                        require_once DISCUZ_ROOT.'./include /template .func.php';
                        parse_template($file, $templateid, $tpldir);
                }
        }
        return $objfile;
很巧妙的一段, Discuz 的 模板缓存就体现在这里,如果你没打开模板刷新的话(config.inc.php->$tplrefresh=0),这里就直接返回一 个$objfile了,而这个文件是你第一次建论坛的时候就写入的,如果你不改模板的话,关了是能提高相当一部分效率的!反之,如果你打开了模板刷新的话 就接着判断是不是模板文件的建立时间大于 forumdata/templates下的文件,是的话就引用./ include / template .func.php写入模板文件到 forumdata/templates中,否则的话还是直接返回一个已经编译好的模板文件。
关于 template .func.php文件中函数的分析在下面:

CODE:

//防止非法引用
if(!defined('IN_DISCUZ')) {
        exit('Access Denied');
}

CODE:

/**
* 这个是关键模板解析函数,通过正则表达式来替换掉模板中的相关语句,使之变成标准的php语句,写入缓存(./forumdata/template ),从而include 到页面中显示出来
* @para string $file //解析的模板名,只要文件名就可以了,会自动加上htm,如果有缓存的话就变成"模板id_文件名.tpl.php"
* @para int $templateid //模板的id
* @para string $tpldir //模板所在的目录
*
*/

function parse_template($file, $templateid, $tpldir) {
        global $language;

        $nest = 5;
        $tplfile = DISCUZ_ROOT."./$tpldir/$file.htm";
        $objfile = DISCUZ_ROOT."./forumdata/templates/{$templateid}_$file.tpl.php";

        if(!@$fp = fopen($tplfile, 'r')) {
                dexit("Current template file './$tpldir/$file.htm' not found or have no access!");
        } elseif(!include_once language('templates', $templateid, $tpldir)) {
                dexit("<br>Current template pack do not have a necessary language file 'templates.lang.php' or have syntax error!");
        }

        $template = fread($fp, filesize($tplfile));
        fclose($fp);

        $var_regexp = "((///$[a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff]*)(/[[a-zA-Z0-9_/-/./"/'/[/]/$/x7f-/xff]+/])*)";
        $const_regexp = "([a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff]*)";

        $template = preg_replace("/([/n/r]+)/t+/s", "//1", $template );
        $template = preg_replace("//</!/-/-/{(.+?)/}/-/-/>/s", "{//1}", $template );
        $template = preg_replace("//{lang/s+(.+?)/}/ies", "languagevar('//1')", $template );
        $template = preg_replace("//{faq/s+(.+?)/}/ies", "faqvar('//1')", $template );
        $template = str_replace("{LF}", "<?=/"//n/"?>", $template );

        $template = preg_replace("//{(///$[a-zA-Z0-9_/[/]/'/"/$/./x7f-/xff]+)/}/s", "<?=//1?>", $template );
        $template = preg_replace("/$var_regexp/es", "addquote('<?=//1?>')", $template );
        $template = preg_replace("//</?/=/</?/=$var_regexp/?/>/?/>/es", "addquote('<?=//1?>')", $template );

        $template = "<? if(!defined('IN_DISCUZ')) exit('Access Denied'); ?>/n$template ";
        $template = preg_replace("/[/n/r/t]*/{template /s+([a-z0-9_]+)/}[/n/r/t]*/is", "/n<? include template ('//1'); ?>/n", $template );
        $template = preg_replace("/[/n/r/t]*/{template /s+(.+?)/}[/n/r/t]*/is", "/n<? include template (//1); ?>/n", $template );
        $template = preg_replace("/[/n/r/t]*/{eval/s+(.+?)/}[/n/r/t]*/ies", "stripvtags('/n<? //1 ?>/n','')", $template );
        $template = preg_replace("/[/n/r/t]*/{echo/s+(.+?)/}[/n/r/t]*/ies", "stripvtags('/n<? echo //1; ?>/n','')", $template );
        $template = preg_replace("/[/n/r/t]*/{elseif/s+(.+?)/}[/n/r/t]*/ies", "stripvtags('/n<? } elseif(//1) { ?>/n','')", $template );
        $template = preg_replace("/[/n/r/t]*/{else/}[/n/r/t]*/is", "/n<? } else { ?>/n", $template );

        for($i = 0; $i < $nest; $i++) {
                $template = preg_replace("/[/n/r/t]*/{loop/s+(/S+)/s+(/S+)/}[/n/r]*(.+?)[/n/r]*/{//loop/}[/n/r/t]*/ies", "stripvtags('/n<? if(is_array(//1)) { foreach(//1 as //2) { ?>','/n//3/n<? } } ?>/n')", $template );
                $template = preg_replace("/[/n/r/t]*/{loop/s+(/S+)/s+(/S+)/s+(/S+)/}[/n/r/t]*(.+?)[/n/r/t]*/{//loop/}[/n/r/t]*/ies", "stripvtags('/n<? if(is_array(//1)) { foreach(//1 as //2 => //3) { ?>','/n//4/n<? } } ?>/n')", $template );
                $template = preg_replace("/[/n/r/t]*/{if/s+(.+?)/}[/n/r]*(.+?)[/n/r]*/{//if/}[/n/r/t]*/ies", "stripvtags('/n<? if(//1) { ?>','/n//2/n<? } ?>/n')", $template );
        }

        $template = preg_replace("//{$const_regexp/}/s", "<?=//1?>", $template );
        $template = preg_replace("/ /?/>[/n/r]*/</? /s", " ", $template );

        if(!@$fp = fopen($objfile, 'w')) {
                dexit("Directory './forumdata/templates/' not found or have no access!");
        }

        $template = preg_replace("//"(http)?[/w/.//:]+/?[^/"]+?&[^/"]+?/"/e", "transamp('//0')", $template );
        $template = preg_replace("//<script[^/>]*?src=/"(.+?)/".*?/>/s*/<//script/>/ise", "stripscriptamp('//1')", $template );

        flock($fp, 2);
        fwrite($fp, $template );
        fclose($fp);
}

CODE:

/**
* 几个替换,过滤掉一些东西
* @para string $str
*
* @return string
*/
      
function transamp($str) {
        $str = str_replace('&', '&', $str);
        $str = str_replace('&', '&', $str);
        $str = str_replace('/"', '"', $str);
        return $str;
}

CODE:

/**
* 从正则表达式来看是给ubb代码去掉一个/符号的,应该是为安全性着想的
* @para string $val
*
* @return string
*/

function addquote($var) {
        return str_replace("///"", "/"", preg_replace("//[([a-zA-Z0-9_/-/./x7f-/xff]+)/]/s", "['//1']", $var));
}

技术末学的个人空间 技术末学 发布于2007-07-04 10:22:56

CODE:

/**
* 把一个字符用语言包中的来替换,没有找到的话就用!string来替换
* @para string $val
*
* @return string
*/

function languagevar($var) {
        if(isset($GLOBALS['language'][$var])) {
                return $GLOBALS['language'][$var];
        } else {
                return "!$var!";
        }
}

CODE:

/**
* FAQ中把id和关建字用一个有效的链接来替换
* @para array $val
*
* @return string
*/

function faqvar($var) {
        global $_DCACHE;
        include_once DISCUZ_ROOT.'./forumdata/cache/cache_faqs.php';

        if(isset($_DCACHE['faqs'][$var])) {
                return '<a href="faq.php?action=message&id='.$_DCACHE['faqs'][$var]['id'].'" target="_blank">'.$_DCACHE['faqs'][$var]['keyword'].'</a>';
        } else {
                return "!$var!";
        }
}

CODE:

/**
* 去掉自定义的一些tag
* @para string $expr
* @para string $statement
* @return string
*/

function stripvtags($expr, $statement) {
        $expr = str_replace("///"", "/"", preg_replace("//</?/=(///$.+?)/?/>/s", "//1", $expr));
        $statement = str_replace("///"", "/"", $statement);
        return $expr.$statement;
}

CODE:

/**
* 作用是把&符号的html编码形式换成&,然后换成javascript引用的形式。
* @para string $s
*
* @return string
*/

function stripscriptamp($s) {
        $s = str_replace('&', '&', $s);
        return "<script src=/"$s/" type=/"text/javascript/"></script>";
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值