>백엔드 개발 >PHP 튜토리얼 >PHP 템플릿 구문 분석 클래스

PHP 템플릿 구문 분석 클래스

WBOY
WBOY원래의
2016-07-25 08:50:461193검색
};};
PHP模板解析類別
  1. class template {
  2. private $vars = array();
  3. private $conf = '';
  4. private $tpl_name = 'index';//如果模板不存在會查找當前controller預設index模板
  5. private $tpl_suffix = '.html';//如果CONFIG沒配置預設後綴則顯示
  6. private $tpl_compile_suffix = '.tpl.php';//編譯模板路徑
  7. private $template_tag_left = ' private $template_tag_right = '}>';//模板右標籤
  8. private $template_c = '';//編譯目錄
  9. private $template_path = '';//模板完整路徑
  10. private $template_name = '';//模板名稱index.html
  11. //定義每個模板的標籤的元素
  12. private $tag_foreach = array('from', 'item', 'key');
  13. private $tag_include = array('file');//目前只支援讀取模板預設路徑
  14. public function __construct($conf) {
  15. $this->conf = &$conf;
  16. $this->template_c = $this- >conf['template_config']['template_c'];//編譯目錄
  17. $this->_tpl_suffix = $this->tpl_suffix();
  18. }
  19. private function str_replace($search, $replace, $content) {
  20. if(empty($search) || empty($replace) || empty($content)) return false;
  21. return str_replace($search , $replace, $content);
  22. }
  23. /**
  24. * preg_match_all
  25. * @param $pattern 正規
  26. * @param $content 內容
  27. * @return array
  28. */
  29. private function preg_match_all($pattern, $content) {
  30. if(empty( $pattern) || empty($content)) core::show_error('查找模板標籤失敗!');
  31. preg_match_all("/".$this->template_tag_left.$pattern.$this->template_tag_right." /is", $content, $match);
  32. return $match;
  33. }
  34. /**
  35. * 範本檔案後綴
  36. */
  37. public function tpl_suffix() {
  38. $tpl_suffix = empty( $this->conf['template_config']['template_suffix']) ?
  39. $this->tpl_suffix :
  40. $this->conf['template_config']['template_suffix'] ;
  41. return $'template_config']['template_suffix'] ;
  42. return $ tpl_suffix;
  43. }
  44. /**
  45. * 此處不解釋了
  46. * @return
  47. */
  48. public function assign($key, $value) {
  49. $this->vars[$key] = $value;
  50. }
  51. /**
  52. * 渲染頁面
  53. * @param
  54. * 使用方法1
  55. * $this->view->display('error', 'comm/');
  56. * 預設是指向TPL模版的跟目錄,所以comm/就是tpl/comm/error.html
  57. * 使用方法2
  58. * $this->view->display('errorfile');
  59. * 預設指向控制器固定的資料夾
  60. * 例如你的網域是http://heartphp/admin/index, 那麼正確路徑就是tpl/admin/index/errorfile.html
  61. * @return
  62. */
  63. public function display($filename = '', $view_path = '') {
  64. $tpl_path_arr = $this->get_tpl( $filename, $view_path);//取得TPL完整路徑並且向指標傳送路徑以及名稱
  65. if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.'模板不存在');
  66. //編譯開始
  67. $this->view_path_param = $view_path;//使用者傳遞過來的模版跟目錄
  68. $this->compile();
  69. }
  70. /**
  71. * 編譯控制器
  72. * @param
  73. * @return
  74. */
  75. private function compile() {
  76. $filepath = $this->template_this.$this->template_name;
  77. $compile_dirpath = $path.> check_temp_compile();
  78. $vars_template_c_name = str_replace($this->_tpl_suffix, '', $this->template_name);
  79. $include_name = $this-this-_replace( read_file($filepath), $compile_dirpath, $vars_template_c_name);//解析
  80. if($include_file) {
  81. $this->read_config() && $config = $this->read_config();
  82. extract($this->vars, EXTR_SKIP);
  83. [url=home.php?mod=space&uid=48608]@include[/url] $include_file;
  84. }
  85. }
  86. /**
  87. * 讀取目前專案設定檔
  88. */
  89. protected function read_config() {
  90. if(file_exists(SYSTEM_PATH.'conf/config.php')) {
  91. @include SYSTEM_PATH.'conf/config.php')) {
  92. @include SYSTEM_PATH.'conf/config.php')) {
  93. @include SYSTEM_PATH.'conf/config.php' ;
  94. return $config; } return false; }
  95. /**
  96. * 구문 분석 템플릿 구문
  97. * @param $str 콘텐츠
  98. * @param $compile_dirpath 템플릿 컴파일 디렉터리
  99. * @param $vars_template_c_name 템플릿 컴파일 파일 이름
  100. * @return 컴파일된 PHP 템플릿 파일 이름
  101. */
  102. 비공개 함수 template_replace($str, $compile_dirpath, $vars_template_c_name) {
  103. if(empty($str)) core::show_error('템플릿 내용이 비어 있습니다. !');
  104. //컴파일 헤더 처리
  105. $compile_path = $compile_dirpath.$vars_template_c_name.$this->tpl_compile_suffix;//파일 컴파일
  106. if(is_file($compile_path )) {
  107. //$header_content = $this->get_compile_header($compile_path);
  108. //$compile_date = $this->get_compile_header_comment($header_content);
  109. $tpl_filemtime = filemtime($this->template_path.$this->template_name);
  110. $compile_filemtime = filemtime($compile_path);
  111. //echo $tpl_filemtime.'=='.date('Y-m-d H:i:s', $tpl_filemtime).'
    ';
  112. //echo $compile_filemtime.'=='.date('Y-m-d H:i:s', $compile_filemtime);
  113. //파일이 만료된 경우 템플릿 태그에 include가 있고 수정되면 다시 컴파일합니다.
  114. //<{include file="public/left.html"}> DEBUG가 아닙니다. 모드에서 메인 파일을 변경하지 않으면 현재 include에 있는 파일이 다시 컴파일되지 않습니다. 저도 변경할지 고민 중인데 아직 생각해본 적은 없습니다. 당분간은 개발 단계에서 DEBUG=1 모드를 켜야 합니다. 그렇지 않으면 포함 파일 수정이 무효화됩니다.有點囉嗦,不知道表達清楚沒
  115. if($tpl_filemtime > $compile_filemtime || DEBUG) {
  116. $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpathpath); else {
  117. $ret_file = $compile_path;
  118. }
  119. } else {//編譯檔不存在建立他
  120. $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dir, $compile_dir) ;
  121. }
  122. return $ret_file;
  123. }
  124. /**
  125. * 範本檔案主體
  126. * @param string $str 內容
  127. * @return html
  128. */
  129. private function body_content($str) {
  130. //解析
  131. $str = $this->parse($str);
  132. $header_comment = "Create On##".time()."|Compiled from##".$this- >template_path.$this->template_name;
  133. $content = " if(!defined('IS_HEARTPHP')) exit('Access Denied');/*{$header_comment}*/?>rn$str" ;
  134. return $content;
  135. }
  136. /**
  137. * 開始解析相關範本標籤
  138. * @param $content 範本內容
  139. */
  140. private function parse($content) {
  141. //foreach
  142. $ content = $this->parse_foreach($content);
  143. //include
  144. $content = $this->parse_include($content);
  145. //if
  146. $ content = $this->parse_if($content);
  147. //elseif
  148. $content = $this->parse_elseif($content);
  149. //範本標籤公用部分
  150. $content = $this->parse_comm($content);
  151. //轉為php程式碼
  152. $content = $this->parse_php($content);
  153. return $content;
  154. }
  155. /**
  156. * echo 如果預設直接 轉成
  157. */
  158. private function parse_echo($content) {
  159. }
  160. /**
  161. /**
  162. * 轉換為PHP
  163. * @param $content html 範本內容
  164. * @return html 取代好的HTML
  165. */
  166. private function parse_php($content){
  167. if(empty($content)) return false;
  168. $content = preg_replace("/".$this->template_tag_left."(. ?)". $this->template_tag_right."/is", "", $content);
  169. return $content;
  170. }
  171. /**
  172. * if判斷語句
  173. *
  174. * zhang
  175. *
  176. * liang
  177. *
  178. * 張亮
  179. *
  180. */
  181. private function parse_if($content) {
  182. if(empty($content)) return false;
  183. //preg_match_all("/".$this->template_tag_left."ifs (.*?)". $this->template_tag_right."/is", $content, $match);
  184. $match = $this->preg_match_all("ifs (.*?)", $content);
  185. if (!isset($match[1]) || !is_array($match[1])) return $content;
  186. foreach($match[1] as $k => $v) {
  187. //$s = preg_split("/s /is", $v);
  188. //$s = array_filter($s);
  189. $content = str_replace($match[0][$k] , "", $content);
  190. }
  191. return $content;
  192. }
  193. private function parse_elseif($ content) {
  194. if(empty($content)) return false;
  195. //preg_match_all("/".$this->template_tag_left."elseifs (.*?)".$this->template_tag_right." /is", $content, $match);
  196. $match = $this->preg_match_all("elseifs (.*?)", $content);
  197. if(!isset($match[1]) || !is_array($match[1])) return $content;
  198. foreach($match[1] as $k => $v) {
  199. //$s = preg_split("/ s /is", $v);
  200. //$s = array_filter($s);
  201. $content = str_replace($match[0][$k], "", $content);
  202. }
  203. return $content;
  204. }
  205. /**
  206. * 解析include include標籤不是即時更新的當主體檔案更新的時候才更新標籤內容,所以想include生效請修改一下主體檔案
  207. * 記錄一下有時間開發一個當DEBUG模式的時候每次執行刪除模版編譯檔案
  208. * 使用方法
  209. * @param $content 範本內容
  210. * @return html
  211. */
  212. private function parse_include($content) {
  213. if(empty($content)) return false;
  214. //preg_match_all("/".$this->template_tag_left."includes (.*?)".$this->template_tag_right."/is", $content, $match);
  215. $match = $this->preg_match_all("includes (.*?)", $content);
  216. if(!isset($match[1]) || !is_array($match[1])) return $content;
  217. foreach($match[1] as $match_key => $match_value) {
  218. $a = preg_split("/s /is", $match_value);
  219. $new_tag = $new_tag array();
  220. // 分析元素
  221. foreach($a as $t) {
  222. $b =explode('=', $t);
  223. if(in_array ($b[0 ], $this->tag_include)) {
  224. if(!empty($b[1])) {
  225. $new_tag[$b[0]] = str_replace(""" , "", $b [1]);
  226. } else {
  227. core::show_error('模板路徑不存在!');
  228. }
  229. }
  230. }
  231. extract($new_tag );
  232. // 查詢範本檔案
  233. foreach($this->conf['view_path'] as $v){
  234. $conf_view_tpl = $v.$file;/ /include 範本檔案
  235. if(is_file($conf_view_tpl)) {
  236. $c = $this->read_file($conf_view_tpl);
  237. $inc_file = str_replace($this- >_tpl_suffix, '', name($this-d $file));
  238. $this->view_path_param = dirname($file).'/';
  239. $compile_dirpath = $this->check_temp_compile( );
  240. $include. $this->template_replace($c, $compile_dirpath, $inc_file);//解析
  241. break;
  242. } else {
  243. core: :show_error('模板檔案不存在,請仔細檢查檔案:'. $conf_view_tpl);
  244. }
  245. }
  246. $content = str_replace($match[0][$match_key], '', $content);
  247. }
  248. return $content;
  249. }
  250. /**
  251. * 解析foreach
  252. * 使用方法
  253. * @param $content 模板內容
  254. * @return html 解析後的內容
  255. */
  256. 私有函數parse_foreach($ content) {
  257. if(empty($content)) return false;
  258. //preg_match_all("/".$this->template_tag_left."foreachs (.*?)".$this-> ; template_tag_right."/is", $content, $match);
  259. $match = $this->preg_match_all("foreachs (.*?)", $content);
  260. if(!isset($match ) [1]) || !is_array($match[1])) return $content;
  261. foreach($match[1] as $match_key => $value) {
  262. $ split = preg_split("/s /is", $value);
  263. $split = array_filter($split);
  264. $new_tag = array();
  265. foreach($split as $v ) {
  266. $a =explode("=", $v);
  267. if(in_array($a[0], $this->tag_foreach)) {//此處過濾標籤不存在過濾
  268. $new_tag[$a[0]] = $a[1];
  269. }
  270. }
  271. $key = '';
  272. extract($new_tag);
  273. $鍵=($鍵)? '$'.$鍵。 ' =>' : '' ;
  274. $s = '';
  275. $ content = $this->str_replace($match[0][$match_key], $s, $content);
  276. }
  277. return $content;
  278. }
  279. /**
  280. * 匹配結束 字串
  281. */
  282. 私人函數parse_comm($content) {
  283. $search = array(
  284. "/".$this->template_tag_left."/foreach".$this- >template_tag_right."/is",
  285. "/".$this->template_tag_left."/if".$this->template_tag_right."/is",
  286. "/".$this- >template_tag_left. "else".$this->template_tag_right."/is",
  287. );
  288. $replace = array(
  289. " ;",
  290. "",
  291. ""
  292. );
  293. $content = preg_replace($search, $replace , $content);
  294. 回傳$ content;
  295. }
  296. /**
  297. * 檢查編譯目錄 如果沒有建立 則遞歸建立目錄
  298. * @param string $path 檔案完整路徑
  299. * @return 範本內容
  300. */
  301. private function check_temp_compile() {
  302. //$paht = $this->template_c.
  303. $tpl_path = ($this->;路徑參數)? $this->view_path_param : $this->get_tpl_path() ;
  304. $all_tpl_apth = $this->template_c.$tpl_path;
  305. if(!is_dir($all_tpl_apth)) >> ->create_dir($tpl_path);
  306. }
  307. return $all_tpl_apth;
  308. }
  309. /**
  310. * 讀取檔案
  311. * @param string $path 檔案完整路徑
  312. * @return 範本內容
  313. */
  314. private function read //$this->check_file_limits($path, 'r');
  315. if(($r = @fopen($path, 'r')) === false) {
  316. core ::show_error('模版檔案沒有讀取或執行權限,請檢查!');
  317. }
  318. $content = fread($r, filesize($path));
  319. fclose($r) ;
  320. return $content;
  321. }
  322. /**
  323. * 寫入檔案
  324. * @param string $filename 檔案名稱
  325. * @param string $content 範本內容
  326. * @return 檔案名稱
  327. */
  328. 私人函數compile_file($filename, $content, $dir) {
  329. if(empty( $filename)) core::show_error("{$filename} 建立失敗");
  330. $content = $this->body_content($content);//對檔案內容運算
  331. //echo '開始編譯了=====';
  332. $f = $dir.$filename.$this->tpl_compile_suffix;
  333. //$this->check_file_limits ($f, 'w') ;
  334. if(($fp = @fopen($f, 'wb')) === false) {
  335. core::show_error($f.'
    編譯文件失敗,請檢查文件權限。 ($fp, LOCK_UN LOCK_NB);
  336. fclose($fp);
  337. return $f;
  338. }
  339. /**
  340. * 這個檢查檔案權限函數 暫時廢棄了
  341. * @param [$path] [路徑]
  342. * @param [status] [w=write, r=read]
  343. */
  344. check_file_limits($path , $status = 'rw') {
  345. clearstatcache();
  346. if(!is_writable($path) && $status == 'w') {
  347. core::show_error(" {$path}
    沒有寫入權限,請檢查。 ");
  348. } elseif(!is_read($path) && $status == 'r ') {
  349. core::show_error("{$path}
    沒有讀取權限,請檢查。 ");
  350. } elseif($status == 'rw') {//檢查寫入並讀取
  351. if(!is_writable($path) || !is_read($path)) {
  352. core::show_error("{$path}
    >沒有讀取或讀取權限,請檢查");
  353. }
  354. }
  355. }
  356. /**
  357. * 讀取編譯後範本的第一行並分析成陣列
  358. * @param string $filepath 檔案路徑
  359. * @param number $line 行數
  360. * @return 傳回指定行數的字串
  361. */
  362. /*
  363. 私有函數get_compile_header($filepath, $line = 0) {
  364. if (($file_arr = @file($filepath)) === false) {
  365. core::show_error($filepath.'
    >讀取檔案失敗,請檢查檔案權限!');
  366. }
  367. return $file_arr[0];
  368. }
  369. */
  370. /**
  371. * 分析頭部註解的日期
  372. * @param string $cotnent 編譯檔案頭部第一行
  373. * @return 回傳上一次日期
  374. */
  375. /*
  376. private function get_compile_header_comment($content) {
  377. preg_match("//*(.*?)*//", $content, $match);
  378. if(!isset($match[1]) || empty( $match[1])) core::show_error('編譯錯誤!');
  379. $arr = explode('|', $match[1]);
  380. $arr_date = explode('##' , $arr[0]);
  381. return $arr_date[1];
  382. }
  383. */
  384. /**
  385. * 取得範本完整路徑 並傳回已存在檔案
  386. * @param string $filename 檔案名稱
  387. * @param string $view_path 範本路徑
  388. * @return
  389. */
  390. private function get_tpl($filename , $view_path) {
  391. empty($filename) && $filename = $this->tpl_name;
  392. //遍歷範本路徑
  393. foreach($this->conf['view_path'] as $path) {
  394. if($view_path) {//直接從tpl跟目錄找檔案
  395. $tpl_path = $path.$view_path;
  396. $view_file_path = $tpl_path.$filename.$this-> _tpl_suffix;
  397. } else {//根據目錄,控制器,方法開始找檔案
  398. $view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this- >_tpl_suffix : exit(0);
  399. }
  400. if(is_file($view_file_path)) {
  401. //傳送模板路徑和模板名稱給指標tpl_path;//
  402. $this->template_name = $filename.$this->_tpl_suffix;
  403. return true;
  404. } else {
  405. core::show_error($filename.$this->_tpl_suffix .'模板不存在');
  406. }
  407. }
  408. }
  409. /**
  410. * 取得範本路徑
  411. * @param string $path 主目錄
  412. * @return URL D和M的拼接路徑
  413. */
  414. private function get_tpl_path($path = '') {
  415. core::get_directory_name() && $path_arr[0] = core::get_directory_name();
  416. core::get_controller_name() && $path_arr[1] = core::get_controller_name();
  417. (is_array( $path_arr)) ? $newpath = implode('/', $path_arr) : core::show_error('取得範本路徑失敗!') ;
  418. return $path.$newpath.'/';
  419. }
  420. /**
  421. * 建立目錄
  422. * @param string $path 目錄
  423. * @return
  424. */
  425. private function create_dir($path, $mode = 0777){
  426. if(is_dir($path)) return false> $dir_arr = explode('/', $path);
  427. $dir_arr = array_filter($dir_arr);
  428. $allpath = '';
  429. $newdir = $this-this> template_c;
  430. foreach($dir_arr as $dir) {
  431. $allpath = $newdir.'/'.$dir;
  432. if(!is_dir($allpath)) {
  433. if(!is_dir($allpath)) {
  434. $newdir = $allpath;
  435. if(!@mkdir($allpath, $mode)) {
  436. core::show_error( $allpath.'
    建立目錄失敗,請檢查是否有可都寫權限! ');
  437. }
  438. chmod($allpath, $mode);
  439. }
  440. chmod($allpath, $mode);
  441. } else {
  442. $newdir = $allpath;
  443. }
  444. }
  445. return true;
  446. }
  447. }
  448. return true;
  449. }
  450. public function __destruct(){
$this->vars = null;
$this->view_path_param = null; }
};
};};
};
};
};
};
};
};};};};};};};};};};};};};複製程式碼
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.