本帖不仅仅是分析文件,还把Discuz中模板解析这一原理分析了一下。转自
www.discuz.net 作者:郭鑫
我记得我刚开始学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>";
}
我来说两句
标题 (可选)
内容
验证
提交评论
<script language="javascript" type="text/javascript">
<!---->
</script>
标题搜索
日历
|
日 |
一 |
二 |
三 |
四 |
五 |
六 |
|
|
|
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
|
数据统计
- 访问量: 430
- 日志数: 27
- 建立时间: 2007-06-21
- 更新时间: 2007-07-06
分享到:
相关推荐
#./configure --host=arm-hisiv400-linux --cache-file=arm-hisiv400-linux.cache --enable-inputapi=no --prefix=$(pwd)/arm-hisiv400-linux-target ./configure --host=arm-hisiv400-linux-gnueabi --cache-file=...
游客不能浏览帖子里的链接插件理论上支持很多版本。7.1和7.2亲测过没有问题。 其他版本的,只要找到..../include/discuzcode.func.php ./templates/default/discuzcode.htm ./templates/default/templates.lang.php
《Discuz代码分析——深入理解`global.func.php`》 Discuz是一款广泛应用于社区论坛建设的开源软件,其强大的功能和灵活的扩展性深受开发者喜爱。在深入学习和使用Discuz的过程中,对核心代码的理解至关重要,尤其...
- 使用template.func.php中的parse_template()函数,将HTML模板中的标签转换为PHP代码,实现多样式风格输出。 6. 语言处理: - 中英文语言通过定义语言变量在模板中输入,语言包存储于模板目录的*.lang.php文件中...
./configure --prefix=/home/duancp/mytslib/ --host=arm-linux ac_cv_func_malloc_0_nonnull=yes make make install-strip ``` 4. **配置 ARM 版本**: ```bash cd /usr/local/qt/qt-embedded-linux-open...
在编译触摸屏驱动之前,需要下载触摸屏源代码,然后运行 `./autogen.sh` 命令来生成 configure 脚本。接下来,需要配置触摸屏的编译器以及目标系统。可以使用以下命令来配置: ``` ./configure CC=/home/zhangh/Qt...
会话 用于会话管理的Gin中间件,具有多后端支持:用法开始使用它下载并安装: $ go get github.com/gin-contrib/sessions 将其导入您的代码中: import "github.com/gin-contrib/sessions"基本范例单节package main...
3. **源代码**:获取 Bluez 及其依赖库的源代码包。 #### 三、具体步骤 ##### 1. 配置与编译 Linux 内核支持 - **解压 Linux 内核源码**: ```bash tar zxf linux.2.6.* ``` - **清理旧的编译结果**: ```...
4. 支持缓存。 5. 支持根据数据库自动生成xorm的结构体。 6. 支持记录版本(即乐观锁)。 7. 内置SQLBuilder。 8. 通过EngineGroup支持读写分离和负载均衡。 xorm支持的数据库驱动包括: - Mysql: ***/go-sql-...
discuz系统被认为php的入门学习的经典系统;对初学者而言整个系统源码似乎有点难度;现将DISCUZ里几个重要、核心php文件的解析传上(附带php文件)。
$ go get github.com/gin-contrib/cors 将其导入您的代码中: import "github.com/gin-contrib/cors"规范示例: package mainimport ("time""github.com/gin-contrib/cors""github.com/gin-gonic/gin")func main ()...
CollabNet 官方提供的用于 linux 的 Subversion 客户端。 安装目录是在 /opt/CollabNet_Subversion 下。 建议为 svn 创建软连接: ...M /etc/asterisk/func_odbc.conf M /etc/asterisk/extensions.conf
ubuntu,linux的安装talib,TA-lib时必须如果报错func.c:256:28: fatal error: ...compilation terminated.,则只能使用源代码安装,无法使用pip install ta-lib安装,下载这个包总容易被qiang,所以放在这方便大家下载
本教程将围绕“(0129)-iOS/iPhone/iPAD/iPod源代码-进度条(Progress)-Colored ProgressView”这一主题,详细讲解如何自定义UIProgressView的颜色,以便让进度条更加符合你的应用设计。 首先,我们需要了解...
## kratosv2 nacos 例子 package server import ( "github.... ".../internal/conf" ) // NewHTTPServer new a HTTP server. func NewNacosServer(c *conf.Data) (naming_client.INamingClient, error) {
你需要编辑 `./include/nasmlib.h` 文件,注释掉引发错误的行 `void pure_func seg_init(void);`,然后重新编译并安装。 - 安装完成后,使用 `nasm -version` 检查 NASM 是否安装成功。 3. **安装 YASM**: YASM ...
本资源“(0065)-iOS/iPhone/iPad/iPod源代码-列表(Table)-Badged TableView”着重讲解如何自定义UITableViewCell,实现一个带有徽章(badge)效果的列表视图。这个功能通常用于显示未读消息数量、通知标志或...
Go中的morse Morse代码库下载并使用go get -u -v github....= nil {return} //莫尔斯电码是:-.-。--- ...-。...--/-.... .. ... /---- /---- ......。fmt.Printf (“摩尔斯码是:%s \ n”,字符串(m
查找/include/discuzcode.func.php /include/js/common.js 覆盖即可 4.后台按钮添加 后台:Discuz! 代码 新增标签: emule 图标文件: bb_emule.gif 例 子: [emule][/emule] 解 释: 电驴下载 将按钮的...
4. 修改`./tests/ts_calibrate.c`文件中的两行,以解决权限问题: ``` vi ./tests/ts_calibrate.c ``` 在第227行,将`O_CREAT | O_RDWR`改为`O_CREAT | O_RDWR, 0777`; 在第229行,将`"/etc/pointercal"`改为`...