Discuz 模版解析代码剥离
虽说Discuz的毛病居多,但是有些东西还是值得赞扬的。
比如说模版解析那套代码,检测到修改过模版后,程序会再次生成此文件包含的所有文件的缓存。
Discuz的模板解析原理是用正则表达式替换一些模板中的规定的语言标记,然后写到cache目录中,再用include引用到index, forumdisplay等等中,和smarty的原理基本上相同,但是没有smarty强大的功能。
但是呢,我们做的是一个小小的网站,用不着去用smarty这样大型的模版框架,维护起来还很麻烦,而且,你不觉得每次都要赋值和display页面很烦么。。
我看了一下网上有人提取过出来,但是版本都已经是很老的了,所以就想在新版本把模版解析的代码剥离开来。
function checktplrefresh($maintpl, $subtpl, $timecompare, $cachefile, $tpldir, $file) {
if(empty($timecompare) || filemtime($subtpl) > $timecompare) {
$this->template = new template();
$this->template->parse_template($maintpl, 0, $tpldir, $file, $cachefile);
unset($maintpl, $subtpl, $timecompare, $cachefile, $tpldir, $file);
return TRUE;
}
return FALSE;
}
function display($file) {
$oldfile = $file;
$tpldir = TPL.THEME.'/';
$filebak = $file;
if(!$tpldir) {
$tpldir = TPL.THEME.'/';
}
$tplfile = $tpldir.$file.'.php';
$cachefile = TPL_CACHE.str_replace('/', '_', THEME.'/'.$file).'.tpl.php';
if(file_exists($cachefile)) {
$timecompare = filemtime($cachefile);
} else {
$timecompare = NULL;
}
$this->checktplrefresh($tplfile, $tplfile, $timecompare, $cachefile, $tpldir, $file);
unset($oldfile, $filebak, $tplfile, $tplfile, $timecompare, $tpldir, $file);
return $cachefile;
}
在上面的代码中,TPL
和THEME
为分别为你的模版路径和主题名称,你可以写在你的全局设置中
要注意的是,这里的模版路径为.tpl.php,如果你想要以html结尾,你可以自己修改这里。
下面就是模版的类了。在这里,使用了正则表达式来替换特定的代码串。
<?php
(!defined('INAPP') || INAPP !== TRUE) && die('Access deny.');
class template {
private $subtemplates = array();
private $replacecode = array('search' => array(), 'replace' => array());
private $language = array();
private $file = '';
public function parse_template($tplfile, $templateid, $tpldir, $file, $cachefile) {
$this->file = $file;
if($fp = fopen($tplfile, 'r')) {
$template = fread($fp, filesize($tplfile));
fclose($fp);
} else {
$this->error('template_notfound', $tplfile);
}
$var_regexp = "(($[a-zA-Z_x7f-xff][a-zA-Z0-9_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]*)";
$headerexists = preg_match("/{(sub)?templates+[w/]+?header}/", $template);
$template = str_ireplace("", '', $template);
$template = preg_replace("/([nr]+)t+/s", "1", $template);
$template = preg_replace("/{C}/s", "{1}", $template);
$template = preg_replace("/{langs+(.+?)}/ies", "$this->languagevar('1')", $template);
$template = preg_replace("/[nrt]*{ad/(.+?)}[nrt]*/ie", "$this->adtags('1')", $template);
$template = preg_replace("/[nrt]*{ads+([a-zA-Z0-9_[]]+)/(.+?)}[nrt]*/ie", "$this->adtags('2', '1')", $template);
$template = preg_replace("/[nrt]*{date((.+?))}[nrt]*/ie", "$this->datetags('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", "template::addquote('=1?>')", $template);
$template = preg_replace("/==$var_regexp?>?>/es", "$this->addquote('=1?>')", $template);
$template = preg_replace("/[nrt]*{templates+([a-z0-9_:/]+)}[nrt]*/ies", "$this->stripvtags(' include template('1'); ?>')", $template);
$template = preg_replace("/[nrt]*{templates+(.+?)}[nrt]*/ies", "$this->stripvtags(' include template('1'); ?>')", $template);
$template = preg_replace("/[nrt]*{echos+(.+?)}[nrt]*/ies", "$this->stripvtags(' echo 1; ?>')", $template);
$template = preg_replace("/([nrt]*){ifs+(.+?)}([nrt]*)/ies", "$this->stripvtags('1 if(2) { ?>3')", $template);
$template = preg_replace("/([nrt]*){elseifs+(.+?)}([nrt]*)/ies", "$this->stripvtags('1 } elseif(2) { ?>3')", $template);
$template = preg_replace("/{else}/i", " } else { ?>", $template);
$template = preg_replace("/{/if}/i", " } ?>", $template);
$template = preg_replace("/[nrt]*{loops+(S+)s+(S+)}[nrt]*/ies", "$this->stripvtags(' if(is_array(1)) foreach(1 as 2) { ?>')", $template);
$template = preg_replace("/[nrt]*{loops+(S+)s+(S+)s+(S+)}[nrt]*/ies", "$this->stripvtags(' if(is_array(1)) foreach(1 as 2 => 3) { ?>')", $template);
$template = preg_replace("/{/loop}/i", " } ?>", $template);
$template = preg_replace("/{$const_regexp}/s", "=1?>", $template);
if(!empty($this->replacecode)) {
$template = str_replace($this->replacecode['search'], $this->replacecode['replace'], $template);
}
$template = preg_replace("/ ?>[nr]* /s", " ", $template);
$template = preg_replace("/"(http)?[w./:]+?[^"]+?&[^"]+?"/e", "$this->transamp('')", $template);
$template = preg_replace("//ies", "$this->stripscriptamp('1', '2')", $template);
$template = preg_replace("/(s{1})/is", "/is", "", $template);
$headeradd = '';
$this->subtemplates = array();
for($i = 1; $i <= 3; $i++) {
if($this->strexists($template, '{subtemplate')) {
$template = preg_replace("/[nrt]*({C})?[nrt]*/ies", "$this->loadsubtemplate('2')", $template);
}
}
if(!empty($this->subtemplates)) {
$headeradd .= "n0n";
foreach($this->subtemplates as $fname) {
$headeradd .= '|| $this->checktplrefresh("'.$tplfile.'", "'.$fname.'", '.time().', "'.$cachefile.'", "'.$tpldir.'", "'.$file.'")'."n";
}
$headeradd .= ';';
}
$template = "n$template";
if(!$fp = fopen($cachefile, 'w')) {
$this->error('directory_notfound', dirname($cachefile));
}
flock($fp, 2);
fwrite($fp, $template);
fclose($fp);
}
private function languagevar($var) {
if(isset($langvar[$var])) {
return $langvar[$var];
} else {
return '!'.$var.'!';
}
}
private function adtags($parameter, $varname = '') {
$parameter = stripslashes($parameter);
$i = count($this->replacecode['search']);
$this->replacecode['search'][$i] = $search = "{C}";
$this->replacecode['replace'][$i] = "";
return $search;
}
private function datetags($parameter) {
$parameter = stripslashes($parameter);
$i = count($this->replacecode['search']);
$this->replacecode['search'][$i] = $search = "{C}";
$this->replacecode['replace'][$i] = "";
return $search;
}
private function stripphpcode($type, $code) {
$this->phpcode[$type][] = $code;
return '{phpcode:'.$type.'/'.(count($this->phpcode[$type]) - 1).'}';
}
private function loadsubtemplate($file) {
$tplfile = $this->display($file, 0, '', 1);
$filename = $tplfile;
if(($content = implode('', file($filename))) || ($content = $this->getphptemplate(implode('', file(substr($filename, 0, -4).'.php'))))) {
$this->subtemplates[] = $tplfile;
return $content;
} else {
return '';
}
}
private function getphptemplate($content) {
$pos = strpos($content, "n");
return $pos !== false ? substr($content, $pos + 1) : $content;
}
private function transamp($str) {
$str = str_replace('&', '&', $str);
$str = str_replace('&', '&', $str);
$str = str_replace('"', '"', $str);
return $str;
}
private function addquote($var) {
return str_replace(""", """, preg_replace("/[([a-zA-Z0-9_-.x7f-xff]+)]/s", "['1']", $var));
}
private function stripvtags($expr, $statement = '') {
$expr = str_replace(""", """, preg_replace("/=($.+?)?>/s", "1", $expr));
$statement = str_replace(""", """, $statement);
return $expr.$statement;
}
private function stripscriptamp($s, $extra) {
$extra = str_replace('"', '"', $extra);
$s = str_replace('&', '&', $s);
return "";
}
private function strexists($string, $find) {
return !(strpos($string, $find) === FALSE);
}
private function error($message, $tplname) {
exit($message);
}
}
以上代码已经能正常使用,模版的话,请参考一下discuz的模版的写法。都是一样的。
不过要注意的是,我去掉了一些比如钩子、diy相关的东西。这些东西一般都不会用得到,所以代码的量就减少了很多。
剩下的,就自己组织把。记得cache目录需要写入权限~~
【声明】本文 Discuz 模版解析代码剥离 为柠之漠然原创文章,转载请注明出自
枫之落叶
并保留本文有效链接:https://blog.shiniv.com/2013/12/discuz-template-separation/ , 转载请保留本声明!