<?php
if(!defined('IS_HEARTPHP')) exit('Access Denied');
/** *  template.class.php   模板解析类 * * @copyright           (C) 20013-2015 HeartPHP * @author              zhangxiaoliang  <[email]zl8762385@163.com[/email]> <qq:979314>   * @lastmodify          2013.04.19 * * 您可以自由使用该源码,但是在使用过程中,请保留作者信息。尊重他人劳动成果就是尊重自己 */class template { private $vars = array(); private $conf = ''; private $tpl_name = 'index';//如果模板不存在 会查找当前 controller默认index模板 private $tpl_suffix = '.html';//如果CONFIG没配置默认后缀 则显示 private $tpl_compile_suffix= '.tpl.php';//编译模板路径 private $template_tag_left = '<{';//模板左标签 private $template_tag_right = '}>';//模板右标签 private $template_c = '';//编译目录 private $template_path = '';//模板完整路径 D:/PHPnow/htdocs/heartphp/tpl/ad/index/ private $template_name = '';//模板名称 index.html //定义每个模板的标签的元素 private $tag_foreach = array('from', 'item', 'key'); private $tag_include = array('file');//目前只支持读取模板默认路径 public function __construct($conf) { $this->conf = &$conf; $this->template_c = $this->conf['template_config']['template_c'];//编译目录 $this->_tpl_suffix = $this->tpl_suffix(); } /** * 重构str_replace * @param $search 搜索字符串 * @param $replace 替换字符串 * @param $content 内容 * [url=home.php?mod=space&uid=987628]@Return[/url] html */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 内容 * @return array */private function preg_match_all($pattern, $content) { if(empty($pattern) || empty($content)) core::show_error('查找模板标签失败!'); 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; } /** *  渲染页面 *  @param  *  使用方法 1 *  $this->view->display('error', 'comm/'); *  默认是指向TPL模版的跟目录,所以comm/就是 tpl/comm/error.html *  使用方法 2 *  $this->view->display('errorfile');  *  默认指向控制器固定的文件夹 *  例如你的域名是 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完整路径 并且向指针传送路径以及名称 if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.'模板不存在'); //编译开始 $this->view_path_param = $view_path;//用户传递过来的模版跟目录 $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; } } /** * 读取当前项目配置文件 */protected function read_config() { if(file_exists(SYSTEM_PATH.'conf/config.php')) { @include SYSTEM_PATH.'conf/config.php';  return $config; } return false; } /** *  解析模板语法 *  @param $str 内容 *  @param $compile_dirpath 模版编译目录 *  @param $vars_template_c_name 模版编译文件名 *  @return 编译过的PHP模板文件名 */ private function template_replace($str, $compile_dirpath, $vars_template_c_name) { if(empty($str)) core::show_error('模板内容为空!'); //处理编译头部 $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); //如果文件过期编译   当模板标签有include并且有修改时 也重新编译 //<{include file="public/left.html"}> 当修改include里的文件,非DEBUG模式时  如果不更改主文件 目前是不重新编译include里的文件,我在考虑是否也要更改,没想好,暂时这样,所以在开发阶段一定要开启DEBUG=1模式 要不然修改include文件无效 。 有点罗嗦,不知道表述清楚没 if($tpl_filemtime > $compile_filemtime || DEBUG) { $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath); } else { $ret_file = $compile_path; } } else {//编译文件不存在 创建他 $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath); } return $ret_file; } /** *  模板文件主体 *  @param  string  $str    内容 *  @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; } /** *  开始解析相关模板标签 * @param $content 模板内容 */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); //模板标签公用部分 $content = $this->parse_comm($content);   //转为PHP代码 $content = $this->parse_php($content); return $content; } /** * echo 如果默认直接<{$config['domain']}> 转成 <?php echo $config['domain']?> */private function parse_echo($content) { } /** * 转换为PHP * @param $content html 模板内容 * @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判断语句 * <{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标签不是实时更新的  当主体文件更新的时候 才更新标签内容,所以想include生效 请修改一下主体文件 * 记录一下 有时间开发一个当DEBUG模式的时候 每次执行删除模版编译文件 * 使用方法 <{include file=""}> * @param $content 模板内容 * @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); //查询模板文件 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('模板文件不存在,请仔细检查 文件:'. $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 模板内容 * @return html 解析后的内容 */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)) {//此处过滤标签 不存在过滤 $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; } /** * 匹配结束 字符串 */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; } /** *  检查编译目录  如果没有创建 则递归创建目录 *  @param  string  $path   文件完整路径 *  @return 模板内容 */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 模板内容 */private function read_file($path) { //$this->check_file_limits($path, 'r'); if(($r = @fopen($path, 'r')) === false) { core::show_error('模版文件没有读取或执行权限,请检查!'); } $content = fread($r, filesize($path)); fclose($r); return $content; } /** *  写文件 *  @param  string  $filename   文件名 *  @param  string  $content    模板内容 *  @return 文件名 */private function compile_file($filename, $content, $dir) { if(empty($filename)) core::show_error("{$filename} Creation failed"); $content = $this->body_content($content);//对文件内容操作 //echo '开始编译了====='; $f = $dir.$filename.$this->tpl_compile_suffix; //$this->check_file_limits($f, 'w'); if(($fp = @fopen($f, 'wb')) === false) { core::show_error($f.'<br/>编译文件失败,请检查文件权限.'); } //开启flock flock($fp, LOCK_EX + LOCK_NB); fwrite($fp, $content, strlen($content)); flock($fp, LOCK_UN + LOCK_NB); fclose($fp); return $f; } /** * 这个检查文件权限函数 暂时废弃了 * @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/>没有写入权限,请检查."); } elseif(!is_readable($path) && $status == 'r') { core::show_error("{$path}<br/>没有读取权限,请检查."); } elseif($status == 'rw') {//check wirte and read if(!is_writable($path) || !is_readable($path)) { core::show_error("{$path}<br/>没有写入或读取权限,请检查"); } } } /** *  读取编译后模板的第一行 并分析成数组 *  @param  string  $filepath  文件路径 *  @param  number  $line        行数 *  @return 返回指定行数的字符串  *//* private function get_compile_header($filepath, $line = 0) { if(($file_arr = @file($filepath)) === false) { core::show_error($filepath.'<br/>读取文件失败,请检查文件权限!'); } 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('编译错误!');     $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 {//根据目录,控制器,方法开始找文件 $view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this->_tpl_suffix  : exit(0); } if(is_file($view_file_path)) { //向指针传送模板路径和模板名称 $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.'/'; } /** *  创建目录 *  @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/>创建目录失败,请检查是否有可都写权限!'); } chmod($allpath, $mode); } else { $newdir = $allpath; } } return true; } public function __destruct(){ $this->vars = null; $this->view_path_param = null; } };

转载于:https://www.cnblogs.com/hubing/p/3415837.html

自己用的框架写了一个PHP模版解析类相关推荐

  1. 自研!东鸽用 Go 语言写了一个能够自动解析新闻网页的算法

    这是「进击的Coder」的第 593 篇技术分享 作者:韦世东 来源:NightTeam " 阅读本文大概需要 8 分钟. " 输入网页文本(不需要输入 xpath),自动结构化输 ...

  2. 一个CUE文件解析类

    网络上的APE文件通常附带一个CUE文件,该文件包含了此CD碟片的作者,曲目等信息,要能支持对APE文件的选曲以及必要信息的显示,必须实现CUE文件的解析.这是实现初步功能的CUE文件解析类,还有待完 ...

  3. 使用Bootstrap框架写的一个小实例

    今天学习了一下Bootstrap框架,,写一个小实例练练手,感受一下bootstrap兼容三端的强大. <!doctype html> <html lang="zh-CN& ...

  4. 使用golang iris框架写了一个PDF电子书分享网站 免费给大家提供PDF电子书下载啦

    最近在学习golang iris web开发框架,正想着写个什么作品来练练手呢. 正好前几天群友发了一个PDF电子书列表,大多数是IT方面的电子书,但是电子书是按照日期归档的,查找起来很不方便.我就把 ...

  5. 如何写出Android框架,结合android当前著名框架写的一个项目--学Android

    简介 学Android 主要是采用 MVP + RxJava2 + Retrofit + Multimodule 等架构设计.利用开源的api获取有关android知识的数据,非常感谢张鸿洋老师提供的 ...

  6. 写了一个UUE编码的类.

    前段时间翻了翻以前收集的一些文档,看见了这个东西,于是想写个类封装一下. 这个东西在电子邮件中用的比较多,详细的情况自己搜索一下吧. 头文件部分: /**//*-------------------- ...

  7. 用C#写的一个注册表操作类

    该类实现了注册表读取.写入.删除.查找等功能. 实现代码: using System; using System.Collections.Generic; using System.Linq; usi ...

  8. java五子棋的算法_初学java,写了一个五子棋算法的类,请大家多多指教.

    //五子棋算法类, /*看了一下QQ上面五子棋,直到有五子连珠才给出谁胜 *俺也这么做 *开始分析,先只考虑实现,不考虑效益,然后再对算法进行优化 *========================= ...

  9. setpagecache.php_一个PHP页面缓存类 修改后可作Emlog缓存插件

    最近,细细看了许多关于缓存的文章,有程序级的.非程序级的.内存缓存.文件缓存等等,感觉获益良多,于是为巩固知识,强化记忆,自己也多动动手去写写关于缓存面的程序. 这是自己写的一个PHP文件缓存类,此类 ...

最新文章

  1. java 状态机_Yarn的状态机机制
  2. Java面试题 简述jvm内存模型?
  3. [Python从零到壹] 十一.数据分析之Numpy、Pandas、Matplotlib和Sklearn入门知识万字详解(1)
  4. springboot系列四、配置模板引擎、配置热部署
  5. SpringMVC防止XSS攻击
  6. 线上python课程一般多少钱-python培训班一般多少钱?一篇文章告诉你
  7. 46多项式01——一元多项式和运算
  8. 全军覆没!麻省理工零录取中国学生,斯坦福取消中国大陆面试! 这是怎么了?...
  9. Linux状态监控在root下可用,监控linux状态
  10. IDE已破解,不用预热,马上进入「微信小程序」开发
  11. oracle 导入性能,EXP,EXPDP数据导入本地性能测试的一点心得
  12. 使用you-get下载blbl视频
  13. 这本Python入门畅销书《“笨办法”学python 3》,不仅仅是一本书
  14. 三星s9Android9内测申请链接,Galaxy S9/S9+国行版进行安卓9.0内测
  15. 虚拟试衣APP软件一站式开发
  16. u盘被隐藏的文件怎么恢复
  17. oracle excel导入卡死 新解决办法
  18. 如何写简历才能够突显自己的厉害之处?
  19. 如何用循环执行玩转自定义企业微信机器人?
  20. python第三方库——xlrd和xlwt操作Excel文件学习

热门文章

  1. 欢迎您到威斯康星大学的CSE人工智能网站
  2. MYSQL中建议使用NOT NULL原因
  3. 2009最新网络歌曲《孟婆的碗》夏鸣专辑里的故事
  4. 网络安全-网络漏洞分类
  5. android解锁动画效果,Android开发学习——Day24(火焰燃烧和蒙眼解锁界面动画:关键帧动画和补间动画)...
  6. 在移动平台上打造60fps的3A游戏
  7. HTML-表单控件语法汇总及其案例
  8. 福禄克DSX-5000 官方授权代理
  9. 【C语言】关键字const详解 - 变量守护者
  10. 算法部分---分割网络杂项检测