Home  >  Article  >  Backend Development  >  PHP template parsing class

PHP template parsing class

WBOY
WBOYOriginal
2016-07-25 08:50:461135browse
PHP template parsing class
  1. class template {
  2. private $vars = array();
  3. private $conf = '';
  4. private $tpl_name = 'index';//If the template does not exist, the current controller will be searched Default index template
  5. private $tpl_suffix = '.html';//If CONFIG is not configured with a default suffix, it will be displayed
  6. private $tpl_compile_suffix= '.tpl.php';//Compile template path
  7. private $template_tag_left = '<{' ;//Template left tag
  8. private $template_tag_right = '}>';//Template right tag
  9. private $template_c = '';//Compilation directory
  10. private $template_path = '';//Template full path
  11. private $ template_name = '';//Template name index.html
  12. //Elements that define the tags of each template
  13. private $tag_foreach = array('from', 'item', 'key');
  14. private $tag_include = array('file');//Currently only supports reading the default path of the template
  15. public function __construct($conf) {
  16. $this->conf = &$conf;
  17. $this->template_c = $this ->conf['template_config']['template_c'];//Compilation directory
  18. $this->_tpl_suffix = $this->tpl_suffix();
  19. }
  20. private function str_replace($search, $ replace, $content) {
  21. if(empty($search) || empty($replace) || empty($content)) return false;
  22. return str_replace($search, $replace, $content);
  23. }
  24. /**
  25. * preg_match_all
  26. * @param $pattern regular
  27. * @param $content content
  28. * @return array
  29. */
  30. private function preg_match_all($pattern, $content) {
  31. if(empty($pattern) || empty($content)) core::show_error('Failed to find template tag!') ;
  32. preg_match_all("/".$this->template_tag_left.$pattern.$this->template_tag_right."/is", $content, $match);
  33. return $match;
  34. }
  35. /**
  36. * Template file suffix
  37. */
  38. public function tpl_suffix() {
  39. $tpl_suffix = empty($this->conf['template_config']['template_suffix']) ?
  40. $this->tpl_suffix :
  41. $this->conf[ 'template_config']['template_suffix'] ;
  42. return $tpl_suffix;
  43. }
  44. /**
  45. * No explanation here
  46. * @return
  47. */
  48. public function assign($key, $value) {
  49. $this->vars[$key] = $value;
  50. }
  51. /**
  52. * Render page
  53. * @param
  54. * Usage method 1
  55. * $this->view->display('error', 'comm/');
  56. * The default is to point to the following directory of the TPL template, so comm/ It is tpl/comm/error.html
  57. * Usage method 2
  58. * $this->view->display('errorfile');
  59. * By default, it points to the folder fixed by the controller
  60. * For example, your domain name is http: //heartphp/admin/index, then the correct path is 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 );//Get the TPL full path and transfer the path and name to the pointer
  65. if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.'Template does not exist');
  66. //Compilation starts
  67. $this->view_path_param = $view_path;//The template and directory passed by the user
  68. $this->compile();
  69. }
  70. /**
  71. * Compile controller
  72. * @param
  73. * @return
  74. */
  75. private function compile() {
  76. $filepath = $this->template_path.$this->template_name;
  77. $compile_dirpath = $this->check_temp_compile();
  78. $vars_template_c_name = str_replace($this->_tpl_suffix, '', $this- >template_name);
  79. $include_file = $this->template_replace($this->read_file($filepath), $compile_dirpath, $vars_template_c_name);//Parse
  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. * Read the current project configuration file
  88. */
  89. protected function read_config() {
  90. if(file_exists(SYSTEM_PATH.'conf/config.php')) {
  91. @include SYSTEM_PATH.'conf/ config.php';
  92. return $config;
  93. }
  94. return false;
  95. }
  96. /**
  97. * Parse template syntax
  98. * @param $str content
  99. * @param $compile_dirpath template compilation directory
  100. * @param $vars_template_c_name template compilation file name
  101. * @return compiled PHP template file name
  102. */
  103. private function template_replace($str, $compile_dirpath, $vars_template_c_name) {
  104. if(empty($str)) core::show_error('Template content is empty!');
  105. / /Process compilation header
  106. $compile_path = $compile_dirpath.$vars_template_c_name.$this->tpl_compile_suffix;//Compile file
  107. if(is_file($compile_path)) {
  108. //$header_content = $this->get_compile_header( $compile_path);
  109. //$compile_date = $this->get_compile_header_comment($header_content);
  110. $tpl_filemtime = filemtime($this->template_path.$this->template_name);
  111. $compile_filemtime = filemtime($ compile_path);
  112. //echo $tpl_filemtime.'=='.date('Y-m-d H:i:s', $tpl_filemtime).'
    ';
  113. //echo $compile_filemtime.'== '.date('Y-m-d H:i:s', $compile_filemtime);
  114. //If the file expires, compile and the template tag has include and is modified. Also recompile
  115. //<{include file="public/left. html"}> When modifying the files in the include, in non-DEBUG mode, if the main file is not changed, the files in the include are not recompiled at present. I am considering whether to change it as well. I haven't thought about it. This is the case for the time being, so in the development stage Be sure to turn on DEBUG=1 mode, otherwise modifying the include file will be invalid.有点罗嗦,不知道表述清楚没
  116. if($tpl_filemtime > $compile_filemtime || DEBUG) {
  117. $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);
  118. } else {
  119. $ret_file = $compile_path;
  120. }
  121. } else {//编译文件不存在 创建他
  122. $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);
  123. }
  124. return $ret_file;
  125. }
  126. /**
  127. * Template file body
  128. * @param string $str content
  129. * @return html
  130. */
  131. private function body_content($str) {
  132. //解析
  133. $str = $this->parse($str);
  134. $header_comment = "Create On##".time()."|Compiled from##".$this->template_path.$this->template_name;
  135. $content = "rn$str";
  136. return $content;
  137. }
  138. /**
  139. * Start parsing related template tags
  140. * @param $content template content
  141. */
  142. private function parse($content) {
  143. //foreach
  144. $content = $this->parse_foreach($content);
  145. //include
  146. $content = $this->parse_include($content);
  147. //if
  148. $content = $this->parse_if($content);
  149. //elseif
  150. $content = $this->parse_elseif($content);
  151. //模板标签公用部分
  152. $content = $this->parse_comm($content);
  153. //转为php代码
  154. $content = $this->parse_php($content);
  155. return $content;
  156. }
  157. /**
  158. * If echo is directly <{$config['domain']}> by default, it will be converted to
  159. */
  160. private function parse_echo($content) {
  161. }
  162. /**
  163. * Convert to PHP
  164. * @param $content html template content
  165. * @return html Replaced HTML
  166. */
  167. private function parse_php($content){
  168. if(empty($content)) return false;
  169. $content = preg_replace("/".$this->template_tag_left."(.+?)".$this->template_tag_right."/is", "", $content);
  170. return $content;
  171. }
  172. /**
  173. * if判断语句
  174. * <{if empty($zhang)}>
  175. * zhang
  176. * <{elseif empty($liang)}>
  177. * liang
  178. * <{else}>
  179. * zhangliang
  180. * <{/if}>
  181. */
  182. private function parse_if($content) {
  183. if(empty($content)) return false;
  184. //preg_match_all("/".$this->template_tag_left."ifs+(.*?)".$this->template_tag_right."/is", $content, $match);
  185. $match = $this->preg_match_all("ifs+(.*?)", $content);
  186. if(!isset($match[1]) || !is_array($match[1])) return $content;
  187. foreach($match[1] as $k => $v) {
  188. //$s = preg_split("/s+/is", $v);
  189. //$s = array_filter($s);
  190. $content = str_replace($match[0][$k], "", $content);
  191. }
  192. return $content;
  193. }
  194. private function parse_elseif($content) {
  195. if(empty($content)) return false;
  196. //preg_match_all("/".$this->template_tag_left."elseifs+(.*?)".$this->template_tag_right."/is", $content, $match);
  197. $match = $this->preg_match_all("elseifs+(.*?)", $content);
  198. if(!isset($match[1]) || !is_array($match[1])) return $content;
  199. foreach($match[1] as $k => $v) {
  200. //$s = preg_split("/s+/is", $v);
  201. //$s = array_filter($s);
  202. $content = str_replace($match[0][$k], "", $content);
  203. }
  204. return $content;
  205. }
  206. /**
  207. * 解析 include include标签不是实时更新的 当主体文件更新的时候 才更新标签内容,所以想include生效 请修改一下主体文件
  208. * 记录一下 有时间开发一个当DEBUG模式的时候 每次执行删除模版编译文件
  209. * 使用方法 <{include file="www.phpddt.com"}>
  210. * @param $content 模板内容
  211. * @return html
  212. */
  213. private function parse_include($content) {
  214. if(empty($content)) return false;
  215. //preg_match_all("/".$this->template_tag_left."includes+(.*?)".$this->template_tag_right."/is", $content, $match);
  216. $match = $this->preg_match_all("includes+(.*?)", $content);
  217. if(!isset($match[1]) || !is_array($match[1])) return $content;
  218. foreach($match[1] as $match_key => $match_value) {
  219. $a = preg_split("/s+/is", $match_value);
  220. $new_tag = array();
  221. //分析元素
  222. foreach($a as $t) {
  223. $b = explode('=', $t);
  224. if(in_array($b[0], $this->tag_include)) {
  225. if(!empty($b[1])) {
  226. $new_tag[$b[0]] = str_replace(""", "", $b[1]);
  227. } else {
  228. core::show_error('模板路径不存在!');
  229. }
  230. }
  231. }
  232. extract($new_tag);
  233. //查询模板文件
  234. foreach($this->conf['view_path'] as $v){
  235. $conf_view_tpl = $v.$file;//include 模板文件
  236. if(is_file($conf_view_tpl)) {
  237. $c = $this->read_file($conf_view_tpl);
  238. $inc_file = str_replace($this->_tpl_suffix, '', basename($file));
  239. $this->view_path_param = dirname($file).'/';
  240. $compile_dirpath = $this->check_temp_compile();
  241. $include_file = $this->template_replace($c, $compile_dirpath, $inc_file);//解析
  242. break;
  243. } else {
  244. core::show_error('模板文件不存在,请仔细检查 文件:'. $conf_view_tpl);
  245. }
  246. }
  247. $content = str_replace($match[0][$match_key], '', $content);
  248. }
  249. return $content;
  250. }
  251. /**
  252. * Parse foreach
  253. * Usage method <{foreach from=$lists item=value key=kk}>
  254. * @param $content template content
  255. * @return html parsed content
  256. */
  257. private function parse_foreach($content) {
  258. if(empty($content)) return false;
  259. //preg_match_all("/".$this->template_tag_left."foreachs+(.*?)".$this->template_tag_right."/is", $content, $match);
  260. $match = $this->preg_match_all("foreachs+(.*?)", $content);
  261. if(!isset($match[1]) || !is_array($match[1])) return $content;
  262. foreach($match[1] as $match_key => $value) {
  263. $split = preg_split("/s+/is", $value);
  264. $split = array_filter($split);
  265. $new_tag = array();
  266. foreach($split as $v) {
  267. $a = explode("=", $v);
  268. if(in_array($a[0], $this->tag_foreach)) {//此处过滤标签 不存在过滤
  269. $new_tag[$a[0]] = $a[1];
  270. }
  271. }
  272. $key = '';
  273. extract($new_tag);
  274. $key = ($key) ? '$'.$key.' =>' : '' ;
  275. $s = '';
  276. $content = $this->str_replace($match[0][$match_key], $s, $content);
  277. }
  278. return $content;
  279. }
  280. /**
  281. * End of match string
  282. */
  283. private function parse_comm($content) {
  284. $search = array(
  285. "/".$this->template_tag_left."/foreach".$this->template_tag_right."/is",
  286. "/".$this->template_tag_left."/if".$this->template_tag_right."/is",
  287. "/".$this->template_tag_left."else".$this->template_tag_right."/is",
  288. );
  289. $replace = array(
  290. "",
  291. "",
  292. ""
  293. );
  294. $content = preg_replace($search, $replace, $content);
  295. return $content;
  296. }
  297. /**
  298. * Check the compilation directory. If it is not created, create the directory recursively
  299. * @param string $path The full path of the file
  300. * @return Template content
  301. */
  302. private function check_temp_compile() {
  303. //$paht = $this->template_c.
  304. $tpl_path = ($this->view_path_param) ? $this->view_path_param : $this->get_tpl_path() ;
  305. $all_tpl_apth = $this->template_c.$tpl_path;
  306. if(!is_dir($all_tpl_apth)) {
  307. $this->create_dir($tpl_path);
  308. }
  309. return $all_tpl_apth;
  310. }
  311. /**
  312. * Read file
  313. * @param string $path The full path of the file
  314. * @return Template content
  315. */
  316. private function read_file($path) {
  317. //$this->check_file_limits($path, 'r');
  318. if(($r = @fopen($path, 'r')) === false) {
  319. core::show_error('模版文件没有读取或执行权限,请检查!');
  320. }
  321. $content = fread($r, filesize($path));
  322. fclose($r);
  323. return $content;
  324. }
  325. /**
  326. * Write file
  327. * @param string $filename file name
  328. * @param string $content template content
  329. * @return file name
  330. */
  331. private function compile_file($filename, $content, $dir) {
  332. if(empty($filename)) core::show_error("{$filename} Creation failed");
  333. $content = $this->body_content($content);//对文件内容操作
  334. //echo '开始编译了=====';
  335. $f = $dir.$filename.$this->tpl_compile_suffix;
  336. //$this->check_file_limits($f, 'w');
  337. if(($fp = @fopen($f, 'wb')) === false) {
  338. core::show_error($f.'
    编译文件失败,请检查文件权限.');
  339. }
  340. //开启flock
  341. flock($fp, LOCK_EX + LOCK_NB);
  342. fwrite($fp, $content, strlen($content));
  343. flock($fp, LOCK_UN + LOCK_NB);
  344. fclose($fp);
  345. return $f;
  346. }
  347. /**
  348. * This function to check file permissions is temporarily abandoned
  349. * @param [$path] [path]
  350. * @param [status] [w=write, r=read]
  351. */
  352. public function check_file_limits($path , $status = 'rw') {
  353. clearstatcache();
  354. if(!is_writable($path) && $status == 'w') {
  355. core::show_error("{$path}
    没有写入权限,请检查.");
  356. } elseif(!is_readable($path) && $status == 'r') {
  357. core::show_error("{$path}
    没有读取权限,请检查.");
  358. } elseif($status == 'rw') {//check wirte and read
  359. if(!is_writable($path) || !is_readable($path)) {
  360. core::show_error("{$path}
    没有写入或读取权限,请检查");
  361. }
  362. }
  363. }
  364. /**
  365. * Read the first line of the compiled template and analyze it into an array
  366. * @param string $filepath file path
  367. * @param number $line number of lines
  368. * @return returns a string with the specified number of lines
  369. */
  370. /*
  371. private function get_compile_header($filepath, $line = 0) {
  372. if(($file_arr = @file($filepath)) === false) {
  373. core::show_error($filepath.'
    读取文件失败,请检查文件权限!');
  374. }
  375. return $file_arr[0];
  376. }
  377. */
  378. /**
  379. * Date of analysis of header comments
  380. * @param string $cotnent The first line of the header of the compiled file
  381. * @return Returns the last date
  382. */
  383. /*
  384. private function get_compile_header_comment($content) {
  385. preg_match("//*(.* ?)*//", $content, $match);
  386. if(!isset($match[1]) || empty($match[1])) core::show_error('Compilation error!');
  387. $arr = explode('|', $match[1]);
  388. $arr_date = explode('##', $arr[0]);
  389. return $arr_date[1];
  390. }
  391. */
  392. / **
  393. * Get the full path of the template and return the existing file
  394. * @param string $filename file name
  395. * @param string $view_path template path
  396. * @return
  397. */
  398. private function get_tpl($filename, $view_path) {
  399. empty($filename) && $filename = $this->tpl_name;
  400. //Traverse the template path
  401. foreach($this-> ;conf['view_path'] as $path) {
  402. if($view_path) {//Find files directly from tpl and directory
  403. $tpl_path = $path.$view_path;
  404. $view_file_path = $tpl_path.$filename.$this ->_tpl_suffix;
  405. } else {//Start looking for files based on the directory, controller, and method
  406. $view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this- >_tpl_suffix : exit(0);
  407. }
  408. if(is_file($view_file_path)) {
  409. //Transfer template path and template name to the pointer
  410. $this->template_path = $tpl_path;//
  411. $this- >template_name = $filename.$this->_tpl_suffix;
  412. return true;
  413. } else {
  414. core::show_error($filename.$this->_tpl_suffix.'Template does not exist');
  415. }
  416. }
  417. }
  418. /**
  419. * Get the template path
  420. * @param string $path Home directory
  421. * @return URL The splicing path of D and M
  422. */
  423. private function get_tpl_path($path = '') {
  424. core::get_directory_name() && $path_arr[0] = core::get_directory_name();
  425. core::get_controller_name( ) && $path_arr[1] = core::get_controller_name();
  426. (is_array($path_arr)) ? $newpath = implode('/', $path_arr) : core::show_error('Failed to get template path!') ;
  427. return $path.$newpath.'/';
  428. }
  429. /**
  430. * Create directory
  431. * @param string $path directory
  432. * @return
  433. */
  434. private function create_dir($path, $mode = 0777){
  435. if(is_dir($path)) return false;
  436. $dir_arr = explode('/', $path);
  437. $dir_arr = array_filter($dir_arr);
  438. $allpath = '';
  439. $newdir = $this->template_c;
  440. foreach( $dir_arr as $dir) {
  441. $allpath = $newdir.'/'.$dir;
  442. if(!is_dir($allpath)) {
  443. $newdir = $allpath;
  444. if(!@mkdir($allpath , $mode)) {
  445. core::show_error( $allpath.'
    Failed to create the directory, please check whether you have write permissions! ');
  446. }
  447. chmod($allpath, $mode);
  448. } else {
  449. $newdir = $allpath;
  450. }
  451. }
  452. return true;
  453. }
  454. public function __destruct(){
  455. $this-> vars = null;
  456. $this->view_path_param = null;
  457. }
  458. };
Copy code


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn