PHP模板解析類(lèi)實(shí)例
本文實(shí)例講述了PHP模板解析類(lèi)。分享給大家供大家參考。具體如下:
<?php
class template {
private $vars = array();
private $conf = '';
private $tpl_name = 'index';
//如果模板不存在 會(huì)查找當(dāng)前 controller默認(rèn)index模板
private $tpl_suffix = '.html';//如果CONFIG沒(méi)配置默認(rèn)后綴 則顯示
private $tpl_compile_suffix= '.tpl.php';//編譯模板路徑
private $template_tag_left = '<{';//模板左標(biāo)簽
private $template_tag_right = '}>';//模板右標(biāo)簽
private $template_c = '';//編譯目錄
private $template_path = '';//模板完整路徑
private $template_name = '';//模板名稱(chēng) index.html
//定義每個(gè)模板的標(biāo)簽的元素
private $tag_foreach = array('from', 'item', 'key');
private $tag_include = array('file');//目前只支持讀取模板默認(rèn)路徑
public function __construct($conf) {
$this->conf = &$conf;
$this->template_c = $this->conf['template_config']['template_c'];//編譯目錄
$this->_tpl_suffix = $this->tpl_suffix();
}
private function str_replace($search, $replace, $content) {
if(empty($search) || empty($replace) || empty($content)) return false;
return str_replace($search, $replace, $content);
}
/**
* preg_match_all
* @param $pattern 正則
* @param $content 內(nèi)容
* @return array
*/
private function preg_match_all($pattern, $content) {
if(empty($pattern) || empty($content)) core::show_error('查找模板標(biāo)簽失敗!');
preg_match_all("/".$this->template_tag_left.$pattern.$this->template_tag_right."/is", $content, $match);
return $match;
}
/**
* 模板文件后綴
*/
public function tpl_suffix() {
$tpl_suffix = empty($this->conf['template_config']['template_suffix']) ?
$this->tpl_suffix :
$this->conf['template_config']['template_suffix'] ;
return $tpl_suffix;
}
/**
* 此處不解釋了
* @return
*/
public function assign($key, $value) {
$this->vars[$key] = $value;
}
/**
* 渲染頁(yè)面
* @param
* 使用方法 1
* $this->view->display('error', 'comm/');
* 默認(rèn)是指向TPL模版的跟目錄,所以comm/就是 tpl/comm/error.html
* 使用方法 2
* $this->view->display('errorfile');
* 默認(rèn)指向控制器固定的文件夾
* 例如你的域名是 http://heartphp/admin/index, 那么正確路徑就是tpl/admin/index/errorfile.html
* @return
*/
public function display($filename = '', $view_path = '') {
$tpl_path_arr = $this->get_tpl($filename, $view_path);//獲取TPL完整路徑 并且向指針傳送路徑以及名稱(chēng)
if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.'模板不存在');
//編譯開(kāi)始
$this->view_path_param = $view_path;//用戶(hù)傳遞過(guò)來(lái)的模版跟目錄
$this->compile();
}
/**
* 編譯控制器
* @param
* @return
*/
private function compile() {
$filepath = $this->template_path.$this->template_name;
$compile_dirpath = $this->check_temp_compile();
$vars_template_c_name = str_replace($this->_tpl_suffix, '', $this->template_name);
$include_file = $this->template_replace($this->read_file($filepath), $compile_dirpath, $vars_template_c_name);//解析
if($include_file) {
$this->read_config() && $config = $this->read_config();
extract($this->vars, EXTR_SKIP);
[url=home.php?mod=space&uid=48608]@include[/url] $include_file;
}
}
/**
* 讀取當(dāng)前項(xiàng)目配置文件
*/
protected function read_config() {
if(file_exists(SYSTEM_PATH.'conf/config.php')) {
@include SYSTEM_PATH.'conf/config.php';
return $config;
}
return false;
}
/**
* 解析模板語(yǔ)法
* @param $str 內(nèi)容
* @param $compile_dirpath 模版編譯目錄
* @param $vars_template_c_name 模版編譯文件名
* @return 編譯過(guò)的PHP模板文件名
*/
private function template_replace($str, $compile_dirpath, $vars_template_c_name) {
if(empty($str)) core::show_error('模板內(nèi)容為空!');
//處理編譯頭部
$compile_path = $compile_dirpath.$vars_template_c_name.$this->tpl_compile_suffix;//編譯文件
if(is_file($compile_path)) {
//$header_content = $this->get_compile_header($compile_path);
//$compile_date = $this->get_compile_header_comment($header_content);
$tpl_filemtime = filemtime($this->template_path.$this->template_name);
$compile_filemtime = filemtime($compile_path);
//echo $tpl_filemtime.'=='.date('Y-m-d H:i:s', $tpl_filemtime).'<br/>';
//echo $compile_filemtime.'=='.date('Y-m-d H:i:s', $compile_filemtime);
//如果文件過(guò)期編譯 當(dāng)模板標(biāo)簽有include并且有修改時(shí) 也重新編譯
//<{include file="public/left.html"}> 當(dāng)修改include里的文件,非DEBUG模式時(shí) 如果不更改主文件 目前是不重新編譯include里的文件,我在考慮是否也要更改,沒(méi)想好,暫時(shí)這樣,所以在開(kāi)發(fā)階段一定要開(kāi)啟DEBUG=1模式 要不然修改include文件無(wú)效 。 有點(diǎn)羅嗦,不知道表述清楚沒(méi)
if($tpl_filemtime > $compile_filemtime || DEBUG) {
$ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);
} else {
$ret_file = $compile_path;
}
} else {//編譯文件不存在 創(chuàng)建他
$ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);
}
return $ret_file;
}
/**
* 模板文件主體
* @param string $str 內(nèi)容
* @return html
*/
private function body_content($str) {
//解析
$str = $this->parse($str);
$header_comment = "Create On##".time()."|Compiled from##".$this->template_path.$this->template_name;
$content = "<? if(!defined('IS_HEARTPHP')) exit('Access Denied');/*{$header_comment}*/?>\r\n$str";
return $content;
}
/**
* 開(kāi)始解析相關(guān)模板標(biāo)簽
* @param $content 模板內(nèi)容
*/
private function parse($content) {
//foreach
$content = $this->parse_foreach($content);
//include
$content = $this->parse_include($content);
//if
$content = $this->parse_if($content);
//elseif
$content = $this->parse_elseif($content);
//模板標(biāo)簽公用部分
$content = $this->parse_comm($content);
//轉(zhuǎn)為PHP代碼
$content = $this->parse_php($content);
return $content;
}
/**
* echo 如果默認(rèn)直接<{$config['domain']}> 轉(zhuǎn)成 <?php echo $config['domain']?>
*/
private function parse_echo($content) {
}
/**
* 轉(zhuǎn)換為PHP
* @param $content html 模板內(nèi)容
* @return html 替換好的HTML
*/
private function parse_php($content){
if(empty($content)) return false;
$content = preg_replace("/".$this->template_tag_left."(.+?)".$this->template_tag_right."/is", "<?php $1 ?>", $content);
return $content;
}
/**
* if判斷語(yǔ)句
* <{if empty($zhang)}>
* zhang
* <{elseif empty($liang)}>
* liang
* <{else}>
* zhangliang
* <{/if}>
*/
private function parse_if($content) {
if(empty($content)) return false;
//preg_match_all("/".$this->template_tag_left."if\s+(.*?)".$this->template_tag_right."/is", $content, $match);
$match = $this->preg_match_all("if\s+(.*?)", $content);
if(!isset($match[1]) || !is_array($match[1])) return $content;
foreach($match[1] as $k => $v) {
//$s = preg_split("/\s+/is", $v);
//$s = array_filter($s);
$content = str_replace($match[0][$k], "<?php if({$v}) { ?>", $content);
}
return $content;
}
private function parse_elseif($content) {
if(empty($content)) return false;
//preg_match_all("/".$this->template_tag_left."elseif\s+(.*?)".$this->template_tag_right."/is", $content, $match);
$match = $this->preg_match_all("elseif\s+(.*?)", $content);
if(!isset($match[1]) || !is_array($match[1])) return $content;
foreach($match[1] as $k => $v) {
//$s = preg_split("/\s+/is", $v);
//$s = array_filter($s);
$content = str_replace($match[0][$k], "<?php } elseif ({$v}) { ?>", $content);
}
return $content;
}
/**
* 解析 include include標(biāo)簽不是實(shí)時(shí)更新的 當(dāng)主體文件更新的時(shí)候 才更新標(biāo)簽內(nèi)容,所以想include生效 請(qǐng)修改一下主體文件
* 記錄一下 有時(shí)間開(kāi)發(fā)一個(gè)當(dāng)DEBUG模式的時(shí)候 每次執(zhí)行刪除模版編譯文件
* 使用方法 <{include file="www.phpddt.com"}>
* @param $content 模板內(nèi)容
* @return html
*/
private function parse_include($content) {
if(empty($content)) return false;
//preg_match_all("/".$this->template_tag_left."include\s+(.*?)".$this->template_tag_right."/is", $content, $match);
$match = $this->preg_match_all("include\s+(.*?)", $content);
if(!isset($match[1]) || !is_array($match[1])) return $content;
foreach($match[1] as $match_key => $match_value) {
$a = preg_split("/\s+/is", $match_value);
$new_tag = array();
//分析元素
foreach($a as $t) {
$b = explode('=', $t);
if(in_array($b[0], $this->tag_include)) {
if(!empty($b[1])) {
$new_tag[$b[0]] = str_replace("\"", "", $b[1]);
} else {
core::show_error('模板路徑不存在!');
}
}
}
extract($new_tag);
//查詢(xún)模板文件
foreach($this->conf['view_path'] as $v){
$conf_view_tpl = $v.$file;//include 模板文件
if(is_file($conf_view_tpl)) {
$c = $this->read_file($conf_view_tpl);
$inc_file = str_replace($this->_tpl_suffix, '', basename($file));
$this->view_path_param = dirname($file).'/';
$compile_dirpath = $this->check_temp_compile();
$include_file = $this->template_replace($c, $compile_dirpath, $inc_file);//解析
break;
} else {
core::show_error('模板文件不存在,請(qǐng)仔細(xì)檢查 文件:'. $conf_view_tpl);
}
}
$content = str_replace($match[0][$match_key], '<?php include("'.$include_file.'")?>', $content);
}
return $content;
}
/**
* 解析 foreach
* 使用方法 <{foreach from=$lists item=value key=kk}>
* @param $content 模板內(nèi)容
* @return html 解析后的內(nèi)容
*/
private function parse_foreach($content) {
if(empty($content)) return false;
//preg_match_all("/".$this->template_tag_left."foreach\s+(.*?)".$this->template_tag_right."/is", $content, $match);
$match = $this->preg_match_all("foreach\s+(.*?)", $content);
if(!isset($match[1]) || !is_array($match[1])) return $content;
foreach($match[1] as $match_key => $value) {
$split = preg_split("/\s+/is", $value);
$split = array_filter($split);
$new_tag = array();
foreach($split as $v) {
$a = explode("=", $v);
if(in_array($a[0], $this->tag_foreach)) {//此處過(guò)濾標(biāo)簽 不存在過(guò)濾
$new_tag[$a[0]] = $a[1];
}
}
$key = '';
extract($new_tag);
$key = ($key) ? '$'.$key.' =>' : '' ;
$s = '<?php foreach('.$from.' as '.$key.' $'.$item.') { ?>';
$content = $this->str_replace($match[0][$match_key], $s, $content);
}
return $content;
}
/**
* 匹配結(jié)束 字符串
*/
private function parse_comm($content) {
$search = array(
"/".$this->template_tag_left."\/foreach".$this->template_tag_right."/is",
"/".$this->template_tag_left."\/if".$this->template_tag_right."/is",
"/".$this->template_tag_left."else".$this->template_tag_right."/is",
);
$replace = array(
"<?php } ?>",
"<?php } ?>",
"<?php } else { ?>"
);
$content = preg_replace($search, $replace, $content);
return $content;
}
/**
* 檢查編譯目錄 如果沒(méi)有創(chuàng)建 則遞歸創(chuàng)建目錄
* @param string $path 文件完整路徑
* @return 模板內(nèi)容
*/
private function check_temp_compile() {
//$paht = $this->template_c.
$tpl_path = ($this->view_path_param) ? $this->view_path_param : $this->get_tpl_path() ;
$all_tpl_apth = $this->template_c.$tpl_path;
if(!is_dir($all_tpl_apth)) {
$this->create_dir($tpl_path);
}
return $all_tpl_apth;
}
/**
* 讀文件
* @param string $path 文件完整路徑
* @return 模板內(nèi)容
*/
private function read_file($path) {
//$this->check_file_limits($path, 'r');
if(($r = @fopen($path, 'r')) === false) {
core::show_error('模版文件沒(méi)有讀取或執(zhí)行權(quán)限,請(qǐng)檢查!');
}
$content = fread($r, filesize($path));
fclose($r);
return $content;
}
/**
* 寫(xiě)文件
* @param string $filename 文件名
* @param string $content 模板內(nèi)容
* @return 文件名
*/
private function compile_file($filename, $content, $dir) {
if(empty($filename)) core::show_error("{$filename} Creation failed");
$content = $this->body_content($content);//對(duì)文件內(nèi)容操作
//echo '開(kāi)始編譯了=====';
$f = $dir.$filename.$this->tpl_compile_suffix;
//$this->check_file_limits($f, 'w');
if(($fp = @fopen($f, 'wb')) === false) {
core::show_error($f.'<br/>編譯文件失敗,請(qǐng)檢查文件權(quán)限.');
}
//開(kāi)啟flock
flock($fp, LOCK_EX + LOCK_NB);
fwrite($fp, $content, strlen($content));
flock($fp, LOCK_UN + LOCK_NB);
fclose($fp);
return $f;
}
/**
* 這個(gè)檢查文件權(quán)限函數(shù) 暫時(shí)廢棄了
* @param [$path] [路徑]
* @param [status] [w=write, r=read]
*/
public function check_file_limits($path , $status = 'rw') {
clearstatcache();
if(!is_writable($path) && $status == 'w') {
core::show_error("{$path}<br/>沒(méi)有寫(xiě)入權(quán)限,請(qǐng)檢查.");
} elseif(!is_readable($path) && $status == 'r') {
core::show_error("{$path}<br/>沒(méi)有讀取權(quán)限,請(qǐng)檢查.");
} elseif($status == 'rw') {//check wirte and read
if(!is_writable($path) || !is_readable($path)) {
core::show_error("{$path}<br/>沒(méi)有寫(xiě)入或讀取權(quán)限,請(qǐng)檢查");
}
}
}
/**
* 讀取編譯后模板的第一行 并分析成數(shù)組
* @param string $filepath 文件路徑
* @param number $line 行數(shù)
* @return 返回指定行數(shù)的字符串
*/
/*
private function get_compile_header($filepath, $line = 0) {
if(($file_arr = @file($filepath)) === false) {
core::show_error($filepath.'<br/>讀取文件失敗,請(qǐng)檢查文件權(quán)限!');
}
return $file_arr[0];
}
*/
/**
* 分析頭部注釋的日期
* @param string $cotnent 編譯文件頭部第一行
* @return 返回上一次日期
*/
/*
private function get_compile_header_comment($content) {
preg_match("/\/\*(.*?)\*\//", $content, $match);
if(!isset($match[1]) || empty($match[1])) core::show_error('編譯錯(cuò)誤!');
$arr = explode('|', $match[1]);
$arr_date = explode('##', $arr[0]);
return $arr_date[1];
}
*/
/**
* 獲取模板完整路徑 并返回已存在文件
* @param string $filename 文件名
* @param string $view_path 模板路徑
* @return
*/
private function get_tpl($filename, $view_path) {
empty($filename) && $filename = $this->tpl_name;
//遍歷模板路徑
foreach($this->conf['view_path'] as $path) {
if($view_path) {//直接從tpl跟目錄找文件
$tpl_path = $path.$view_path;
$view_file_path = $tpl_path.$filename.$this->_tpl_suffix;
} else {//根據(jù)目錄,控制器,方法開(kāi)始找文件
$view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this->_tpl_suffix : exit(0);
}
if(is_file($view_file_path)) {
//向指針傳送模板路徑和模板名稱(chēng)
$this->template_path = $tpl_path;//
$this->template_name = $filename.$this->_tpl_suffix;
return true;
} else {
core::show_error($filename.$this->_tpl_suffix.'模板不存在');
}
}
}
/**
* 獲取模板路徑
* @param string $path 主目錄
* @return URL D和M的拼接路徑
*/
private function get_tpl_path($path = '') {
core::get_directory_name() && $path_arr[0] = core::get_directory_name();
core::get_controller_name() && $path_arr[1] = core::get_controller_name();
(is_array($path_arr)) ? $newpath = implode('/', $path_arr) : core::show_error('獲取模板路徑失敗!') ;
return $path.$newpath.'/';
}
/**
* 創(chuàng)建目錄
* @param string $path 目錄
* @return
*/
private function create_dir($path, $mode = 0777){
if(is_dir($path)) return false;
$dir_arr = explode('/', $path);
$dir_arr = array_filter($dir_arr);
$allpath = '';
$newdir = $this->template_c;
foreach($dir_arr as $dir) {
$allpath = $newdir.'/'.$dir;
if(!is_dir($allpath)) {
$newdir = $allpath;
if(!@mkdir($allpath, $mode)) {
core::show_error( $allpath.'<br/>創(chuàng)建目錄失敗,請(qǐng)檢查是否有可都寫(xiě)權(quán)限!');
}
chmod($allpath, $mode);
} else {
$newdir = $allpath;
}
}
return true;
}
public function __destruct(){
$this->vars = null;
$this->view_path_param = null;
}
}
希望本文所述對(duì)大家的php程序設(shè)計(jì)有所幫助。
相關(guān)文章
支持中文字母數(shù)字、自定義字體php驗(yàn)證碼代碼
支持中文字母數(shù)字、自定義字體php驗(yàn)證碼代碼,需要的朋友可以參考下2012-02-02
php使用array_rand()函數(shù)從數(shù)組中隨機(jī)選擇一個(gè)或多個(gè)元素
這篇文章主要介紹了php使用array_rand()函數(shù)從數(shù)組中隨機(jī)選擇一個(gè)或多個(gè)元素,需要的朋友可以參考下2014-04-04
關(guān)于使用coreseek并為其做分頁(yè)的介紹
本篇文章是對(duì)使用coreseek并為其做分頁(yè)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
phpmyadmin里面導(dǎo)入sql語(yǔ)句格式的大量數(shù)據(jù)的方法
phpmyadmin里面導(dǎo)入sql語(yǔ)句格式的大量數(shù)據(jù)的方法2010-06-06
PHP實(shí)現(xiàn)異步調(diào)用方法研究與分享
瀏覽器和服務(wù)器之間只一種面向無(wú)連接的HTTP協(xié)議進(jìn)行通訊的,面向無(wú)連接的程序的特點(diǎn)是客戶(hù)端請(qǐng)求服務(wù)端,服務(wù)端根據(jù)請(qǐng)求輸出相應(yīng)的程序,不能保持持久連接2011-10-10
PHP基于方差和標(biāo)準(zhǔn)差計(jì)算學(xué)生成績(jī)的穩(wěn)定性示例
這篇文章主要介紹了PHP基于方差和標(biāo)準(zhǔn)差計(jì)算學(xué)生成績(jī)的穩(wěn)定性操作,涉及PHP數(shù)學(xué)運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
zend framework配置操作數(shù)據(jù)庫(kù)實(shí)例分析
zend framework項(xiàng)目建立后,看了下zend framework配置操作數(shù)據(jù)庫(kù),本文將詳細(xì)介紹,需要了解的朋友可以參考下2012-12-12
一些php項(xiàng)目中比較通用的php自建函數(shù)的詳解
本篇文章是對(duì)一些php項(xiàng)目中比較通用的php自建函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06

