phpcms 源碼分析七: 模板引擎實現

 此次是逆雪寒對模板引擎實現的分析:
1
/* 2 函數 template函數是在global.func.php 裏面定義的。 在前面的phpcms 的首頁 index.php 裏就見到了。 3 用法: include template() 用法很熟, 呵呵其實和 dz 的模板引擎同樣的用法。 4 但DZ的模板引擎比 PHPCMS 的簡單不少,由於沒有用到模板的標籤技術。 你們有空能夠研究下DZ的模板引擎。 5 這裏不說。 好分析下下面這個 模板的主要函數吧。 他的做用是返回編譯好的模板文件路徑。 6 也就是把模板 X.html(模板文件) 用正則替換成 x.php(編譯後的PHP文件).而後使用 include 函數。 7 懂了吧! php的模板引擎都一個鳥樣。 而後剩下的就是正則的東西了。等下再說。 8 */ 9 function template($module = 'phpcms', $template = 'index') 10 { 11 global $CONFIG; 12 13 /* 14 由於phpcms是分模塊來存放模板文件。因此 template 函數有兩個參數: 15 第一個就是模塊目錄名,第二個就是此模塊裏面的模板文件名. 16 $CONFIG['templatescachedir'] 這個是放編譯後php文件存放的目錄。 17 在config.inc.php 站點配置文件裏面定義的本身去看。 這樣就取得了模板編譯後的php文件路徑。 18 */ 19 $compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php'; 20 21 // $CONFIG['templaterefresh'] 在 config.inc.php裏面配置了。 22 // 默認是1 。是更新模板開關。若是你設置爲0 那麼模板更新了。程序也不會更新。 23 if($CONFIG['templaterefresh']) 24 { 25 /* 26 和下面那句意思差很少。$CONFIG['defaulttemplate'] 是默認模板目錄 。 27 這句是獲取你要的那個模塊和裏面的那個模板文件的路徑(@@獲取沒編譯前的模板文件) 28 */ 29 $tplfile = PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html'; 30 31 /* 32 我把文件編譯成了php文件。那麼模板改變了。 php文件總得也改變吧。 33 要不你修改了模板後。站仍是之前那個樣子沒變那有什麼意思呢。 34 首先判斷模板編譯文件是否存在。若是不存在那麼後邊那個條件不用判斷了。 35 由於編譯文件都不存在。程序確定運行不了拉。( 36 由於其實咱們主要是運行編譯後的那個php文件,模板文件是html的運行個P呀) 37 或 後邊那個 @filemtime($tplfile) > @filemtime($compiledtplfile) 38 很容易就明白: 函數 filetime() 判斷文件最近修改的時間,返回Unix 時間戳。 39 若是模板文件的修改時間 大於 編譯文件。 那麼證實 模板文件 在 編譯文件生成後 還進行了修改。 40 那麼咱們是否是還要在更新次編譯文件呀 ,那是確定的拉。 因此繼續執行下去。 41 */ 42 if(!file_exists($compiledtplfile) || @filemtime($tplfile) > @filemtime($compiledtplfile)) 43 { 44 // 加載編譯函數 45 require_once PHPCMS_ROOT.'/include/template.func.php'; 46 47 // 這個就是模板的 編譯啓動函數 ,帶動一系列的模板編譯函數來最終生成模板編譯文件。 48 template_refresh($tplfile, $compiledtplfile); 49 } 50 } 51 52 // 返回 模板編譯後的PHP文件路徑。 53 return $compiledtplfile; 54 } 55 56 defined('IN_PHPCMS') or exit('Access Denied'); 57 58 // 和上面那個同樣是編譯模板啓動函數。不過兩函數的參數不同,按照上下文意思。 59 // 這個函數是爲了配合批量編譯模板而寫的。第一個是模塊目錄名,第二是模板文件名,解釋同下。請看下面那個 60 function template_compile($module,$template) 61 { 62 global $CONFIG; 63 64 $content = file_get_contents(PHPCMS_ROOT.'/templates/' 65 . $CONFIG['defaulttemplate'].'/'.$module.'/'.$template.'.html'); 66 67 $content = template_parse($content); 68 69 $compiledtplfile = $CONFIG['templatescachedir'].$module.'_'.$template.'.tpl.php'; 70 71 $strlen = file_put_contents($compiledtplfile, $content); 72 73 @chmod($compiledtplfile, 0777); 74 75 return $strlen; 76 } 77 78 // 模板編譯啓動函數。 參數 第一個是 模板文件名 第二個是 編譯後的php文件名 79 function template_refresh($tplfile,$compiledtplfile) 80 { 81 // 使用了php5 的最爽函數:file_get_contents() 獲取文件的內容 。 82 $str = file_get_contents($tplfile); 83 84 /* 85 * 而後 使用 template_parse() 函數來對文件內容進行替換。 86 * 好比把一些咱們本身定義的語句:{if xx > xx} 87 * 正則替換成 <?php if(xx > xx){?>具體看下面 88 */ 89 $str = template_parse($str); 90 91 // 編譯完成後。把內容寫到咱們的 那個所謂的編譯PHP文件。 92 $strlen = file_put_contents($compiledtplfile, $str); 93 94 // 別忘了設置下權限。 95 @chmod($compiledtplfile, 0777); 96 97 //返回 寫到編譯文件裏的內容字大小節數,下面咱們會看下 template_parse() 函數 98 return $strlen; 99 } 100 101 // 這個頗有用。批量編譯某模塊目錄下的模板文件 102 function template_module($module) 103 { 104 global $CONFIG; 105 106 /* 107 glob 函數 取得 在此路徑下的全部 *.html 以html爲擴展名的文件列表。 具體看手冊。 108 */ 109 $files = glob(PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/'.$module.'/*.html'); 110 111 if(is_array($files)) 112 { 113 foreach($files as $tpl) 114 { 115 //開始批量 116 $template = str_replace('.html', '', basename($tpl)); 117 118 // 獲取模板文件名。以次來作編譯後的PHP文件名 119 template_compile($module, $template); 120 } 121 } 122 123 return TRUE; 124 } 125 126 // 這個是比下面那個更大批量的生成。由於 $MODULE 裏面的全部模塊 127 // $MODULE 存在於緩存文件模板。前面已經說了。本身看吧 128 function template_cache() 129 { 130 global $MODULE; 131 132 foreach($MODULE as $module=>$m) 133 { 134 template_module($module); 135 } 136 137 return TRUE; 138 } 139 140 /* 141 哇,別給它嚇到。其實都是些簡單的正則。只要知道他們是幹什麼的就好辦了。 在模板裏面咱們使用了些本身定義的標籤呀。 142 語句呀。這些東西不是PHP標準語法。因此根本不可能運行。 143 那麼怎麼辦呢。經過正則對咱們本身定義的語法 。轉變成標準的PHP語法。 144 而後寫到咱們的 PHP文件裏。因此下面正則都是對咱們本身定義的語法進行編譯。 145 下面講解下正則。按照本人水平解釋。大概的解釋了下。不過不懂正則的請本身百度學下。 146 有不對的地方。你們能夠討論下。@@ 還沒懂 preg_replace() 函數的同窗兄弟朋友姐妹。請本身看手冊。 147 */ 148 function template_parse($str) 149 { 150 // 用 \n\r 過濾掉 tab製表符, [url=file://\\1]\\1[\url] 是逆向引用了第一個括號裏面\n換行\r換頁匹配的文本 151 //(@@解釋好要口,最好本身看下正則知識 /s爲修正符。本身百度吧) 152 $str = preg_replace("/([\n\r]+)\t+/s", "[url=file://\\1]\\1", $str[\url]); 153 154 // 以 {xx} 來替換 <!--{xx}--> {xx}在下面確定還要進行第二次正則替換,要不是不能在PHP裏面運行的。 155 // .+? 和 .+ 一個是懶惰 一個是貪婪。 看名字就知道。不知道的 百度吧: 正則貪婪。 156 $str = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}",$str); 157 158 /* 159 * 把模板裏面的 {template 'xx','jj'} 編譯成PHP標準寫法:<?php include template('xx','jj') ?> 160 * 你們可能一看就明白了: include template() 這個在那裏見過。對了。這個在PHP裏也能夠運行的。由於 template() 函數不是定義了嗎。 161 */ 162 $str = preg_replace("/\{template\s+(.+)\}/","\n<?php include template([url=file://\\1]\\1[\url]); ?>\n",$str); 163 164 /* 模板裏面的 {include xx.php} 編譯成 PHP文件裏的 <?php include xx.php?>**/ 165 $str = preg_replace("/\{include\s+(.+)\}/","\n<?php include [url=file://\\1]\\1[\url]; ?>\n",$str); 166 167 /* 模板裏面的 {php xxxx} 編譯成 <?php xxxx?> 你們也應該明白了。 xxxx 確定是PHP的標準語法拉。 168 * 因此phpcms模板語句: {php } 就是用來給你在模板裏寫要運行的PHP語句。在smarty 裏也有這功能** 169 */ 170 $str = preg_replace("/\{php\s+(.+)\}/","\n<?php [url=file://\\1?]\\1?>\n",$str[\url]); 171 172 /* 這個就更簡單了。 把模板裏面的{if xxxx} 編譯成 <?php if(){?> 173 * 看這樣一步一步的把一些本身定義的語句編譯成PHP的標準語法。這個就叫模板引擎了。** 174 */ 175 $str = preg_replace("/\{if\s+(.+?)\}/","<?php if([url=file://\\1]\\1[\url]) { ?>",$str); 176 177 /* {else } 轉 <?php } else {?>**/ 178 $str = preg_replace("/\{else\}/","<?php } else { ?>",$str); 179 180 /* {elseif } 轉 <?php } elseif {?>**/ 181 $str = preg_replace("/\{elseif\s+(.+?)\}/","<?php } elseif ([url=file://\\1]\\1[\url]) { ?>",$str); 182 183 /* {/if} 轉 <?php }?> phpcms 模板語法有: {/if}的哦。你們別忘了,要不 php確定運行不了**/ 184 $str = preg_replace("/\{\/if\}/","<?php } ?>",$str); 185 186 /* 下面就是循環了。模板裏用{loop xx jj} 其實編譯成了PHP的 foreach(xx AS jj) 這樣你們都會用了吧**/ 187 $str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\}/", 188 "<?php if(is_array([url=file://\\1]\\1[\url])) 189 foreach([url=file://\\1]\\1[\url] AS [url=file://\\2]\\2[\url]) { ?>",$str); 190 191 /* 這句和上面也差很少。不過是多了個取出數組的標名 {loop xx jj yy} 成 foreach(xx as jj=> yy)**/ 192 $str = preg_replace("/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/", 193 "\n<?php if(is_array([url=file://\\1]\\1[\url])) 194 foreach([url=file://\\1]\\1[\url] AS [url=file://\\2]\\2[\url] => [url=file://\\3]\\3[\url]) { ?>",$str); 195 196 197 /* 循環結束別忘了 {/loop} 對應PHP的 <?php }?>**/ 198 $str = preg_replace("/\{\/loop\}/","\n<?php } ?>\n",$str); 199 200 /* {tag_xx} 替換爲 get_tag('xx') get_tag() 函數是本身定義的函數, 201 * 由於phpcms 的模板引擎應用了標籤功能。這個函數就是爲了調用標籤的。** 202 */ 203 $str = preg_replace("/\{tag_([^}]+)\}/e", "get_tag('\\1')", $str); 204 205 /* {xxx(jj)} 這麼個奇怪的東西。由於奇怪因此我找了下PHPCMS的模板文件。 206 * 找了幾個文件都沒發現這個怪物。你們有誰找到的說下我去看下。怕是我理解錯了正則。先謝了** 207 */ 208 $str = preg_replace("/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/", 209 "<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); 210 211 212 /* {$xxx(wwsd)} 專換成 <?php echo xxx(wwsd)?> 固然了 xxx() 是程序中定義過的函數**/ 213 $str = preg_replace("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(([^{}]*)\))\}/", 214 "<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); 215 216 /* 把{$xxjj} 轉成 <?php echo $xxjj?> 固然了是把變量輸出**/ 217 $str = preg_replace("/\{([url=file://\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/]\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", 218 "<?php[\url] echo [url=file://\\1;?]\\1;?>",$str[\url]); 219 220 /* 主要是把{$xxx['jj']} 轉成 <?php echo $xxx['jj']?> 221 * addquote() 函數本身定義的看下面,二次過濾。有代驗證,頭昏了看過久的黃色字。我昏** 222 */ 223 $str = preg_replace("/\{([url=file://\\$[a-zA-Z0-9_\[\]\]\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es[\url]", 224 "addquote('<?php echo [url=file://\\1;?]\\1;?>')",$str[\url]); 225 226 /* {XXJJ} <?php echo XXJJ?> XXJJ 是咱們定義的常量**/ 227 $str = preg_replace("/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s", 228 "<?php echo [url=file://\\1;?]\\1;?>",$str[\url]); 229 230 /* 最後別忘了在本身的每一個編譯後的文件里加上這個。之前講過了不明白找前面例子**/ 231 $str = "<?php defined('IN_PHPCMS') or exit('Access Denied'); ?>".$str; 232 233 // 最後返回過濾完成的內容 234 return $str; 235 } 236 237 // 這個函數在 下面這個編譯函數裏面看到了。 其實就是獲取對應標籤的內容,頭有點昏,下節再說標籤吧。 238 function get_tag($tagname) 239 { 240 global $tags, $html, $CONFIG; 241 242 if(!$tags) { 243 require PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/tags.php'; 244 } 245 246 if(!$html) { 247 require PHPCMS_ROOT.'/templates/'.$CONFIG['defaulttemplate'].'/html.php'; 248 } 249 250 if(!isset($tags[$tagname])) { 251 return '{tag_'.$tagname.'}'; 252 } 253 254 $code = isset($html[$tagname]) 255 ? 'tag_read('.$html[$tagname].')' 256 : $tags[$tagname]; 257 258 return "<?php echo $code;?>"; 259 } 260 261 function addquote($var) 262 { 263 return str_replace("[url=]\\\[\url]\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var)); 264 } 265 /* 266 [/php] 267 268 269 下一節講 phpcms 的模板標籤功能,講得很差.大俠就別笑我了 270
相關文章
相關標籤/搜索