程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> UCenterHome1.5的模板語法解析

UCenterHome1.5的模板語法解析

編輯:關於C語言

在UCH中,模板與動態數據分離,所以在很多php文件的最後,我們會看到包含了模板文件,如cp_blog.php最後有include_once template("cp_blog");

 

在下面的代碼中,命名有規律。$tpl是沒有後綴名的,$tplfile是後綴為htm的模板文件,$objfile是後綴為php的緩存文件

 

UCH裡使用模板的流程是:

在php代碼中獲取動態數據,然後include_once template($tpl)

template函數解析模板文件$tplfile,返回緩存文件$objfile。

template函數中調用parse_template函數解析$tplfile,

$tplfile裡有UCH定義的一套語法,在parse_template函數裡可以看到,有<!-- template name--> <!—block/name-->等。這些語法在parse_template中都會被替換成對應的函數,如readtemplate blocktags等,這些函數也都位於function_template.php中。

這裡有點點糾結的就是,模板文件中可能還通過<!-- template name-->包含了其他的模板文件,所以在parse_template中要兩次調用preg_replace,第一次讀模板文件$tplfile所包含的子模板文件name,第二次是讀子模板文件name中再包含的孫子模板文件。UCH中至多有3層模板包含關系,即父親->兒子->孫子,所以不需要第三次調用preg_replace來讀取孫子模板文件可能包含的重孫模板文件了。

 

 

template函數在function_common.php中定義

function template($name) {

global $_SCONFIG, $_SGLOBAL;

 

if(strexists($name,/)) {

$tpl = $name;//$name是完整目錄的情況

} else {

$tpl = "template/$_SCONFIG[template]/$name";

/*

$name只是一個文件名的情況,$tpl類似template/default/cp_blog或者template/blue/cp_blog

默認的模板風格是default,但是如果用戶選擇了其他風格,$_SCONFIG[template]就會變成blue之類的其他值

在首頁的右下角可以選擇模板風格


*/

}

$objfile = S_ROOT../data/tpl_cache/.str_replace(/,_,$tpl)..php;

/*

緩存文件名,$objfile類似data/tpl_cache/template_default_cp_blog.php或者data/tpl_cache/template_blue_cp_blog.php

*/

if(!file_exists($objfile)) {

include_once(S_ROOT../source/function_template.php);

parse_template($tpl);

//如果緩存文件不存在,則對模板文件進行解析

}

return $objfile;

}

 

parse_template函數在function_template.php中定義

function parse_template($tpl) {

global $_SGLOBAL, $_SC, $_SCONFIG;

 

//包含模板

$_SGLOBAL[sub_tpls] = array($tpl);

 

$tplfile = S_ROOT../.$tpl..htm;

/*

$tplfile類似template/default/cp_blog.htm或者template/blue/cp_blog.htm

*/

$objfile = S_ROOT../data/tpl_cache/.str_replace(/,_,$tpl)..php;

/*

$objfile類似data/tpl_cache/template_default_cp_blog.php或者data/tpl_cache/template_blue_cp_blog.php

*/

 

//read

if(!file_exists($tplfile)) {

$tplfile = str_replace(/.$_SCONFIG[template]./, /default/, $tplfile);

//如果非默認模板風格的某個模板文件不存在,那麼就改用default風格的該模板文件

}

$template = sreadfile($tplfile);

//讀入模板文件內容

if(empty($template)) {

exit("Template file : $tplfile Not found or have no access!");

}

 

//模板

$template = preg_replace("/<!--{templates+([a-z0-9_/]+)}-->/ie", "readtemplate(\1)", $template);

/*

這就是定義UCH的模板語法了,模板頁中的<!--{template name}-->

被替換成readtemplate(name),readtemplate函數也在function_template.php中定義。name就是([a-zA-Z0-9_/]+)

為什麼多了A-Z呢,因為"/<!--{templates+([a-z0-9_/]+)}-->/ie"最後的i選項表示不區分大小寫的正則匹配

python裡的正則表達式分組,似乎就是用1來表示第一組,這裡用了\1

\1為什麼又要用單引號裹起來呢,這是因為readtemplate函數的參數要是一個字符串

*/

//處理子頁面中的代碼

$template = preg_replace("/<!--{templates+([a-z0-9_/]+)}-->/ie", "readtemplate(\1)", $template);

//解析模塊調用

$template = preg_replace("/<!--{block/(.+?)}-->/ie", "blocktags(\1)", $template);

/*

<!--{block/name}-->被替換成blocktags(name)

name就是(.+?)   .匹配除換行符外的任意字符,+表示出現一次或多次

?表示懶惰匹配,不然後面的} - >都會被.+匹配掉

*/

//解析廣告

$template = preg_replace("/<!--{ad/(.+?)}-->/ie", "adtags(\1)", $template);

/*

<!--{ad/name}-->被替換成<!--adtags(name)-->

如space_doing.htm裡有一個<!--{ad/header}-->被替換成了<!--AD_TAG_1-->

*/

 

//時間處理

$template = preg_replace("/<!--{date((.+?))}-->/ie", "datetags(\1)", $template);

/*

<!--{date(name)}-->被替換成datetags(name)

如space_doing.htm裡有一個

<!--{date(m-d H:i,$basevalue[dateline],1)}-->被替換成了<!--DATE_TAG_7-->

*/

//頭像處理

$template = preg_replace("/<!--{avatar((.+?))}-->/ie", "avatartags(\1)", $template);

/*

<!--{avatar(name)}-->被替換成avatartags(name)

如space_doing.htm裡有一個<!--{avatar($_SGLOBAL[supe_uid],small)}-->被替換成了<!--AVATAR_TAG_10-->

*/

//PHP代碼

$template = preg_replace("/<!--{evals+(.+?)s*}-->/ies", "evaltags(\1)", $template);

/*

<!--{eval php_expression}-->被替換成evaltags(php_expression)

php_expression就是(.+?) 而且這裡的.匹配包括換行符在內的一切字符 這是由/ies中的s選項確定的

如space_doing.htm裡有一個<!--{eval echo formhash();}-->被替換成了<!--EVAL_TAG_16-->

*/

   

//開始處理

//變量

$var_regexp = "((\$[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)([[a-zA-Z0-9_-."\[]$x7f-xff]+])*)";

/*

上面用紅色顯示的是轉義符,沒用紅色顯示的\就還是反斜槓

但是一開始為什麼要用三個,我搞不明白。試驗了一下,\$匹配的就是$,而改成$卻沒能匹配模板文件裡的變量名。這個我還沒搞明白。

$var_regexp匹配變量名

[a-zA-Z_x7f-xff] 變量名以字母或下劃線或漢字開頭

x7f-xff這個讓人非常困惑,到底是想匹配什麼呢?難道是想匹配擴展ASCII碼嗎?0x7f-0xff確實是擴展ASCII碼表的范圍,但顯然沒人會用這些控制字符去當變量名。

我這個UCH是UTF-8版本的,從UCS-2(就是現在通用的Unicode)到UTF-8的編碼方式如下:

UCS-2編碼(16進制)
 UTF-8 字節流(二進制)
 
0000 - 007F
 0xxxxxxx
 
0080 - 07FF
 110xxxxx 10xxxxxx
 
0800 - FFFF
 1110xxxx 10xxxxxx 10xxxxxx
 

前面的0000-007F是兼容ASCII碼的

漢字的unicode編碼在0080-FFFF裡,轉換成UTF-8後的字節是

110xxxxx或10xxxxxx或1110xxxx,在0x01111111-0x11111111范圍內,也即0x7f-0xff。

更精確地,這個匹配變量名開頭的部分可以寫成[a-zA-Z_xc0-xef],因為漢字的開始字節只可能是110xxxxx或1110xxxx,范圍就是0xc0-0xdf和0xe0-0xef

[a-zA-Z0-9_x7f-xff]* 比變量名的開頭字節的允許取值范圍多了數字,和C語言是一樣的,變量名不能以數字開頭

更精確地,這裡可以寫成[a-zA-Z0-9_x80-xef]* 因為這裡漢字的字節可能是110xxxxx或1110xxxx或10xxxxxx,比0xc0-0xef多了10xxxxxx,即0x80-0xbf,合起來就是0x80-0xef

 

([[a-zA-Z0-9_-."\[]$x7f-xff]+])*

變量可能是數組形式的,如$name1[$name2],$[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*匹配了$name1,後面的[$name2]怎麼匹配呢?我一開始以為是[$[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]],因為[]裡面也應該是一個變量名。

但是變量可能是嵌套數組形式的,如$name1[$name2[$name3[$name4]]],此時用$[a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]來一個個匹配變量名明顯不可行。所以只是用[]把可能的字符都框起來,希望程序員不要寫太扯淡的變量名了。

*/

$template = preg_replace("/<!--{(.+?)}-->/s", "{\1}", $template);

/*

形如<!--{name}-->的字符串被替換成{name}

前面 解析廣告,時間處理等產生的<!--EVAL_TAG_15-->等都不匹配,仍然保留

name就是(.+?) 這裡的.匹配包括換行符在內的所有字符(有/s選項)   ?表示懶惰匹配

*/

$template = preg_replace("/([ ]+) +/s", "\1", $template);

/*

去掉換行回車後的制表符

beyondcompare中的對比效果如下


*/

$template = preg_replace("/(\$[a-zA-Z0-9_[]\"$x7f-xff]+).([a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)/s", "\1[\2]", $template);

/*

形如$name1.name2替換成$name1[name2],不要搞成了$name1[name2],\2和"\1"都是正則表達式的後向引用。可是我在模板文件中還沒找到例子

*/

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

/*

形如{$name1}替換成<?=$name1?>

如space_doing.htm裡有{$_SN[$space[uid]]}被換成了

<?=$_SN[$space[uid]]?>

*/

$template = preg_replace("/$var_regexp/es", "addquote(<?=\1?>)", $template);

/*

將沒有被{}包裹的變量名替換成addquote(<?=\1?>)

addquote的作用是將類似[name]轉換成[‘name’]

如space_doing.htm裡有{if $space}被替換成了{if <?=$space?>}

但是這樣也有副作用,比如space_doing.htm裡有{$_SN[$space[uid]]},在上一條語句中被替換成了<?=$_SN[$space[uid]]?>,在這又被替換成了<?=<?=$_SN[$space[uid]]?>?>

*/

$template = preg_replace("/<?=<?=$var_regexp?>?>/es", "addquote(<?=\1?>)", $template);

/*

消除上一條語句的副作用,將<?=<?=$_SN[$space[uid]]?>?>換成<?=$_SN[$space[uid]]?>

*/

//邏輯

$template = preg_replace("/{elseifs+(.+?)}/ies", "stripvtags(<?php } elseif(\1) { ?>,)", $template);

/*

{elseif expression1} 替換成stripvtags(<?php } elseif(expression1) { ?>,)

stripvtags的作用是將類似<?=$name?>替換成$name

*/

$template = preg_replace("/{else}/is", "<?php } else { ?>", $template);

/*

{else} 替換成<?php } else { ?>

*/

//循環

for($i = 0; $i < 5; $i++) {

$template = preg_replace("/{loops+(S+)s+(S+)}(.+?){/loop}/ies", "stripvtags(<?php if(is_array(\1)) { foreach(\1 as \2) { ?>,\3<?php } } ?>)", $template);

/*

解析loop

將類似{loop array1 key1} expression1 {/loop}替換成

stripvtags(

<’?php if(is_array(array1)) {foreach (array1 as key1){?>’,

‘expression1<?php } } ?>’

如space_doing.htm裡將

<title>{if <?=$_TPL[titles]?>}{loop <?=$_TPL[titles]?> <?=$value?>}{if <?=$value?>}<?=$value?> - {/if}{/loop}{/if}{if <?=$space?>}<?=$_SN[$space[uid]]?> - {/if}<?=$_SCONFIG[sitename]?>

替換成了

<title>{if <?=$_TPL[titles]?>}<?php if(is_array($_TPL[titles])) { foreach($_TPL[titles] as $value) { ?>{if <?=$value?>}<?=$value?> - {/if}<?php } } ?>{/if}{if <?=$space?>}<?=$_SN[$space[uid]]?> - {/if}<?=$_SCONFIG[sitename]?>

*/

$template = preg_replace("/{loops+(S+)s+(S+)s+(S+)}(.+?){/loop}/ies", "stripvtags(<?php if(is_array(\1)) { foreach(\1 as \2 => \3) { ?>,\4<?php } } ?>)", $template);

/*

解析loop

將類似{loop array1 key1 value1} expression1 {/loop}替換成

stripvtags(

<’?php if(is_array(array1)) {foreach (array1 as key1=>value1){?>’,

‘expression1<?php } } ?>’

如space_doing.htm裡將

{loop <?=$moodlist?> <?=$key?> <?=$value?>}

<li>

<div class="avatar48"><a href="space.php?uid=<?=$value[uid]?>&do=doing"><img src="<!--AVATAR_TAG_14-->" alt="<?=$_SN[$value[uid]]?>" /></a></div>

<p><a href="space.php?uid=<?=$value[uid]?>" title="<?=$_SN[$value[uid]]?>"><?=$_SN[$value[uid]]?></a></p>

<p class="time"><!--DATE_TAG_9--></p>

</li>

{/loop}

替換成了

<?php if(is_array($moodlist)) { foreach($moodlist as $key => $value) { ?>

<li>

<div class="avatar48"><a href="space.php?uid=<?=$value[uid]?>&do=doing"><img src="<!--AVATAR_TAG_14-->" alt="<?=$_SN[$value[uid]]?>" /></a></div>

<p><a href="space.php?uid=<?=$value[uid]?>" title="<?=$_SN[$value[uid]]?>"><?=$_SN[$value[uid]]?></a></p>

<p class="time"><!--DATE_TAG_9--></p>

</li>

<?php } } ?>

*/

$template = preg_replace("/{ifs+(.+?)}(.+?){/if}/ies", "stripvtags(<?php if(\1) { ?>,\2<?php } ?>)", $template);

/*

解析if

將類似

{if name1} expression1 {/if}

替換成

stripvtags(

<’?php if(name1) { ?>’,

‘expression1<?php } ?>’

)

如space_doing.htm裡將

{if empty(<?=$_SGLOBAL[inajax]?>)}

替換成

<?php if(empty($_SGLOBAL[inajax])) { ?>

*/

}/*for循環結束*/

/*

為什麼要有for循環呢?因為可能存在循環語句嵌套的情況。

比如space_doing.htm裡有這麼一段代碼

{loop <?=$list?> <?=$basevalue?>}

                 ………                                       

                 ………                                       

{loop <?=$clist[$basevalue[doid]]?> <?=$value?>}

                 ………                                       

{/loop}

                 ………                                       

{/loop}

$i=0時,

$template = preg_replace("/{loops+(S+)s+(S+)}(.+?){/loop}/ies", "stripvtags(<?php if(is_array(\1)) { foreach(\1 as \2) { ?>,\3<?php } } ?>)", $template);

只替換掉了外層的loop,內層的loop被(.+?)所匹配

?表示懶惰匹配,否則後面的{/loop}都會被(.+)所匹配

但是既然是懶惰匹配,為什麼(.+?)不是匹配到內層的{/loop}就停止呢?

因為正則表達式有另一條規則,比懶惰/貪婪規則的優先級更高:最先開始的匹配擁有最高的優先權——The match that begins earliest wins。

$i=1時,內層的loop也將被替換掉

從這個for循環我們也可以看出,UCH的模板中最多允許5層嵌套循環,當然這已經足夠了

*/

//常量

$template = preg_replace("/{([a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)}/s", "<?=\1?>", $template);

/*

比變量名少了一開始的$,也不考慮數組形式的常量

*/

//替換

if(!empty($_SGLOBAL[block_search])) {

$template = str_replace($_SGLOBAL[block_search], $_SGLOBAL[block_replace], $template);

}

 

//換行

$template = preg_replace("/ ?>[ ]*<? /s", " ", $template);

/*

?>

 

<?

前一段php代碼的結尾和下一段php代碼的開始都被以空格代替了

*/

//附加處理

$template = "<?php if(!defined(IN_UCHOME)) exit(Access Denied);?><?php subtplcheck(".implode(|, $_SGLOBAL[sub_tpls]).", $_SGLOBAL[timestamp], $tpl);?>$template<?php ob_out();?>";

 

//write

if(!swritefile($objfile, $template)) {

exit("File: $objfile can not be write!");

}

/*

寫入緩存文件

所以在template函數最後,無論$objfile一開始是否存在,最後都是返回$objfile

*/

}

 

 

function readtemplate($name) {

global $_SGLOBAL, $_SCONFIG;

 

$tpl = strexists($name,/)?$name:"template/$_SCONFIG[template]/$name";

$tplfile = S_ROOT../.$tpl..htm;

 

$_SGLOBAL[sub_tpls][] = $tpl;

 

if(!file_exists($tplfile)) {

$tplfile = str_replace(/.$_SCONFIG[template]./, /default/, $tplfile);

}

/*

如果$_SCONFIG[template]風格的模板文件不存在,則改用default風格的模板文件

*/

$content = sreadfile($tplfile);

//讀入模板文件的內容

return $content;

}

 

function addquote($var) {

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

/*

這個preg_replace感覺沒什麼用啊,[name1]替換成[name1]?

str_replace將\"替換成"

*/

}

 

 function blocktags($parameter) {

global $_SGLOBAL;

 

$_SGLOBAL[i]++;

$search = "<!--BLOCK_TAG_{$_SGLOBAL[i]}-->";

/*

按廣告出現的次序,依次將{block/name}替換成BLOCK_TAG_1 BLOCK_TAG_2等等

*/

$_SGLOBAL[block_search][$_SGLOBAL[i]] = $search;

$_SGLOBAL[block_replace][$_SGLOBAL[i]] = "<?php block("$parameter"); ?>";

return $search;

}

 

function adtags($pagetype) {

global $_SGLOBAL;

 

$_SGLOBAL[i]++;

$search = "<!--AD_TAG_{$_SGLOBAL[i]}-->";

/*

按廣告出現的次序,依次將{ad/name}替換成AD_TAG_3 AD_TAG_4等等

這個編號是跟著前面的BLOCK_TAG來的

*/

$_SGLOBAL[block_search][$_SGLOBAL[i]] = $search;

$_SGLOBAL[block_replace][$_SGLOBAL[i]] = "<?php adshow($pagetype); ?>";

return $search;

}

 

function datetags($parameter) {

global $_SGLOBAL;

 

$_SGLOBAL[i]++;

$search = "<!--DATE_TAG_{$_SGLOBAL[i]}-->";

/*

按date模板方法出現的次序,依次將{date(name)}替換成DATE_TAG_7 DATE_TAG_8等等

注意這裡的編號是跟著前面的AD_TAG來的

*/

$_SGLOBAL[block_search][$_SGLOBAL[i]] = $search;

$_SGLOBAL[block_replace][$_SGLOBAL[i]] = "<?php echo sgmdate($parameter); ?>";

return $search;

}

 

function avatartags($parameter) {

global $_SGLOBAL;

 

$_SGLOBAL[i]++;

$search = "<!--AVATAR_TAG_{$_SGLOBAL[i]}-->";

/*

按avatar模板方法出現的次序,依次將{avatar(name)}替換成AVATAR_TAG_9 AVATAR_TAG_10等等

注意這裡的編號是跟著前面的DATE_TAG來的

*/

$_SGLOBAL[block_search][$_SGLOBAL[i]] = $search;

$_SGLOBAL[block_replace][$_SGLOBAL[i]] = "<?php echo avatar($parameter); ?>";

return $search;

}

 

function evaltags($php) {

global $_SGLOBAL;

 

$_SGLOBAL[i]++;

$search = "<!--EVAL_TAG_{$_SGLOBAL[i]}-->";

/*

按eval模板方法出現的次序,依次將{eval php_expression}替換成EVAL_TAG_16 EVAL_TAG_17等等

注意這裡的編號是跟著前面的AVATAR_TAG來的

*/

$_SGLOBAL[block_search][$_SGLOBAL[i]] = $search;

$_SGLOBAL[block_replace][$_SGLOBAL[i]] = "<?php ".stripvtags($php)." ?>";

 

return $search;

}

 

 

 

function addquote($var) {

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

/*

preg_replace將類似[name]轉換成[‘name’]

str_replace將\轉換成   不過我還沒找到例子

*/

}

 

function stripvtags($expr, $statement=) {

    $expr = str_replace("\"", """, preg_replace("/<?=(\$.+?)?>/s", "\1", $expr));

/*

preg_replace將<?=$name?>替換成$name

*/

    $statement = str_replace("\"", """, $statement);

    return $expr.$statement;

}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved