[轉]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

1   <p>function template($file, $templateid = 0, $tpldir = '') {</p>
2 <p>        global $tplrefresh; </p><p>        $tpldir = $tpldir ? $tpldir : TPLDIR;</p><p>        $templateid = $templateid ? $templateid : TEMPLATEID;</p><p>        $tplfile = DISCUZ_ROOT.'./'.$tpldir.'/'.$file.'.htm';</p><p>        $objfile = DISCUZ_ROOT.'./forumdata/templates/'.$templateid.'_'.$file.'.tpl.php'; </p><p>        if(TEMPLATEID != 1 && $templateid != 1 && !file_exists($tplfile)) {  </p><p>                return template($file, 1, './templates/default/'); </p><p>        } </p><p>        if($tplrefresh == 1 || ($tplrefresh > 1 && substr($GLOBALS['timestamp'], -1) > $tplrefresh)) {</p>
3                 if(@filemtime($tplfile) > @filemtime($objfile)) {
4 <p>                        require_once DISCUZ_ROOT.'./include/template.func.php';</p>                        parse_template($file, $templateid, $tpldir);
5                 }
6   <p>        } </p><p>        return $objfile;</p>

}

複製代碼

這個函數一共有三個傳入參數: 

$file 表示模板名

$templateid 表示模板id

$tpldir 表示模板目錄

global $tplrefresh;這個是把$tplrefresh作爲一個全局變量,tplrefresh表示是不是刷新模板 

CODE:

$tpldir = $tpldir ? $tpldir : TPLDIR;

        $templateid = $templateid ? $templateid : TEMPLATEID;給$tpldir和$templateid賦值,如果沒有傳進來就用常量TPLDIR和TEMPLATEID給它們值 

$tplfile = DISCUZ_ROOT.’./’.$tpldir.’/’.$file.’.htm’;

        $objfile = DISCUZ_ROOT.’./forumdata/templates/’.$templateid.’_’.$file.’.tpl.php’;這裏是把$tplfile(表示的是模板文件)和$objfile(表示的是要編譯成的文件)賦值 

if(TEMPLATEID != 1 && $templateid != 1 && !file_exists($tplfile)) {

                return template($file, 1, ‘./templates/default/’);

        } 

防止TEMPLATEID不等於1且$templateid不等於1,而且模板文件不存在導致空白問題。

這裏也可以算一個迭代,也可以不算,就是把1作爲第二個參數再調用函數本身。

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文件中函數的分析在下面:

001 <p>
002 </p><ul>
003     <p>//防止非法引用<br>
004      
005     if(!defined('IN_DISCUZ')) {<br>
006      
007             exit('Access Denied');<br>
008      
009     }<br>
010      
011     function parse_template($file, $templateid, $tpldir) {<br>
012      
013             global $language;<br>
014      
015             $nest = 5;<br>
016      
017             $tplfile = DISCUZ_ROOT."./$tpldir/$file.htm";<br>
018      
019             $objfile = DISCUZ_ROOT."./forumdata/templates/{$templateid}_$file.tpl.php";<br>
020      
021             if(!@$fp = fopen($tplfile, 'r')) {<br>
022      
023                     dexit("Current template file './$tpldir/$file.htm' not found or have no access!");<br>
024      
025             } elseif(!include_once language('templates', $templateid, $tpldir)) {<br>
026      
027                     dexit("<br>Current template pack do not have a necessary language file 'templates.lang.php' or have syntax error!");<br>
028      
029             }<br>
030      
031             $template = fread($fp, filesize($tplfile));<br>
032      
033             fclose($fp);<br>
034      
035             $var_regexp = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)";<br>
036      
037             $const_regexp = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";<br>
038      
039             $template = preg_replace("/([\n\r]+)\t+/s", "\\1", $template);<br>
040      
041             $template = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $template);<br>
042      
043             $template = preg_replace("/\{lang\s+(.+?)\}/ies", "languagevar('\\1')", $template);<br>
044      
045             $template = preg_replace("/\{faq\s+(.+?)\}/ies", "faqvar('\\1')", $template);<br>
046      
047             $template = str_replace("{LF}", "<?=\"\\n\"?>", $template);<br>
048      
049             $template = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/s", "<?=\\1?>", $template);<br>
050      
051             $template = preg_replace("/$var_regexp/es", "addquote('<?=\\1?>')", $template);<br>
052      
053             $template = preg_replace("/\<\?\=\<\?\=$var_regexp\?\>\?\>/es", "addquote('<?=\\1?>')", $template);<br>
054      
055             $template = "<? if(!defined('IN_DISCUZ')) exit('Access Denied'); ?>\n$template";<br>
056      
057             $template = preg_replace("/[\n\r\t]*\{template\s+([a-z0-9_]+)\}[\n\r\t]*/is", "\n<? include template('\\1'); ?>\n", $template);<br>
058      
059             $template = preg_replace("/[\n\r\t]*\{template\s+(.+?)\}[\n\r\t]*/is", "\n<? include template(\\1); ?>\n", $template);<br>
060      
061             $template = preg_replace("/[\n\r\t]*\{eval\s+(.+?)\}[\n\r\t]*/ies", "stripvtags('\n<? \\1 ?>\n','')", $template);<br>
062      
063             $template = preg_replace("/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/ies", "stripvtags('\n<? echo \\1; ?>\n','')", $template);<br>
064      
065             $template = preg_replace("/[\n\r\t]*\{elseif\s+(.+?)\}[\n\r\t]*/ies", "stripvtags('\n<? } elseif(\\1) { ?>\n','')", $template);<br>
066      
067             $template = preg_replace("/[\n\r\t]*\{else\}[\n\r\t]*/is", "\n<? } else { ?>\n", $template);<br>
068      
069             for($i = 0; $i < $nest; $i++) {<br>
070      
071                     $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);<br>
072      
073                     $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);<br>
074      
075                     $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);<br>
076      
077             }<br>
078             $template = preg_replace("/\{$const_regexp\}/s", "<?=\\1?>", $template);<br>
079      
080             $template = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $template);<br>
081      
082     <br>
083      
084             if(!@$fp = fopen($objfile, 'w')) {<br>
085      
086                     dexit("Directory './forumdata/templates/' not found or have no access!");<br>
087      
088             }<br>
089      
090     <br>
091      
092             $template = preg_replace("/\"(http)?[\w\.\/:]+\?[^\"]+?&[^\"]+?\"/e", "transamp('\\0')", $template);<br>
093      
094             $template = preg_replace("/\<script[^\>]*?src=\"(.+?)\".*?\>\s*\<\/script\>/ise", "stripscriptamp('\\1')", $template);<br>
095      
096             flock($fp, 2);<br>
097      
098             fwrite($fp, $template);<br>
099      
100             fclose($fp);<br>
101      
102     } <br>
103      
104     function transamp($str) {<br>
105      
106             $str = str_replace('&', '&', $str);<br>
107      
108             $str = str_replace('&', '&', $str);<br>
109      
110             $str = str_replace('\"', '"', $str);<br>
111      
112             return $str;<br>
113      
114     } <br>
115      
116     function addquote($var) {<br>
117      
118             return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));<br>
119      
120     }<br>
121      
122     function languagevar($var) {<br>
123      
124             if(isset($GLOBALS['language'][$var])) {<br>
125      
126                     return $GLOBALS['language'][$var];<br>
127      
128             } else {<br>
129      
130                     return "!$var!";<br>
131      
132             }<br>
133      
134     } <br>
135      
136     function faqvar($var) {<br>
137      
138             global $_DCACHE;<br>
139      
140             include_once DISCUZ_ROOT.'./forumdata/cache/cache_faqs.php';<br>
141      
142     <br>
143      
144             if(isset($_DCACHE['faqs'][$var])) {<br>
145      
146                     return '<a href="faq.php?action=message&id='.$_DCACHE['faqs'][$var]['id'].'" target="_blank">'.$_DCACHE['faqs'][$var]['keyword'].'</a>';<br>
147      
148             } else {<br>
149      
150                     return "!$var!";<br>
151      
152             }<br>
153      
154     } <br>
155     function stripvtags($expr, $statement) {<br>
156      
157             $expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr));<br>
158      
159             $statement = str_replace("\\\"", "\"", $statement);<br>
160      
161             return $expr.$statement;<br>
162      
163     } </p><p>function stripscriptamp($s) {<br>
164      
165             $s = str_replace('&', '&', $s);<br>
166      
167             return "<script src=\"$s\" type=\"text/javascript\"></script>";<br>
168      
169     }
170 </p>
171 <p></p></ul>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章