PHP模板解析类实例


Posted in PHP onJuly 09, 2015

本文实例讲述了PHP模板解析类。分享给大家供大家参考。具体如下:

<?php
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 = '';//模板完整路径 
 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();
 }
 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="www.phpddt.com"}>
  * @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;
 }
}

希望本文所述对大家的php程序设计有所帮助。

PHP 相关文章推荐
PHP加速 eAccelerator配置和使用指南
Jun 05 PHP
php利用新浪接口查询ip获取地理位置示例
Jan 20 PHP
PHP实现的英文名字全拼随机排号脚本
Jul 04 PHP
php支持中文字符串分割的函数
May 28 PHP
php文件扩展名判断及获取文件扩展名的N种方法
Sep 12 PHP
PHP strip_tags保留多个HTML标签的方法
May 22 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
Apr 19 PHP
利用Laravel生成Gravatar头像地址的优雅方法
Dec 30 PHP
设定php简写功能的方法
Nov 28 PHP
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
Apr 26 PHP
PHP 计算至少是其他数字两倍的最大数的实现代码
May 26 PHP
PHP SESSION跨页面传递失败解决方案
Dec 11 PHP
PHP多文件上传实例
Jul 09 #PHP
php判断linux下程序问题实例
Jul 09 #PHP
php实现html标签闭合检测与修复方法
Jul 09 #PHP
php可扩展的验证类实例(可对邮件、手机号、URL等验证)
Jul 09 #PHP
php类常量用法实例分析
Jul 09 #PHP
php求一个网段开始与结束IP地址的方法
Jul 09 #PHP
PHP实现全角字符转为半角方法汇总
Jul 09 #PHP
You might like
php xml实例 留言本
2009/03/20 PHP
PHP 类型转换函数intval
2009/06/20 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
2013/06/05 PHP
PHP永久登录、记住我功能实现方法和安全做法
2015/04/27 PHP
php中JSON的使用方法
2015/04/30 PHP
ThinkPHP的常用配置选项汇总
2016/03/24 PHP
PHP htmlentities()函数用法讲解
2019/02/25 PHP
laravel实现简单用户权限的示例代码
2019/05/28 PHP
CSS常用网站布局实例
2008/04/03 Javascript
Json对象替换字符串占位符实现代码
2010/11/17 Javascript
dojo随手记 gird组件引用
2011/02/24 Javascript
Jquery阻止事件冒泡 event.stopPropagation
2011/12/11 Javascript
php对mongodb的扩展(初识如故)
2012/11/11 Javascript
一个Action如何调用两个不同的方法
2014/05/22 Javascript
JQuery $.each遍历JavaScript数组对象实例
2014/09/01 Javascript
根据配置文件加载js依赖模块
2014/12/29 Javascript
js实现网页右上角滑出会自动消失大幅广告的方法
2015/02/27 Javascript
AspNet中使用JQuery上传插件Uploadify详解
2015/05/20 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
2015/09/17 Javascript
2016年最热门的15 款代码语法高亮工具,美化你的代码
2016/01/06 Javascript
如何使用Bootstrap 按钮实例详解
2017/03/29 Javascript
Vue项目中引入外部文件的方法(css、js、less)
2017/07/24 Javascript
javascript函数的节流[throttle]与防抖[debounce]
2017/11/15 Javascript
Vue中this.$router.push参数获取方法
2018/02/27 Javascript
javascript function(函数类型)使用与注意事项小结
2019/06/10 Javascript
[02:51]DOTA2 2015国际邀请赛中国区预选赛第一日战报
2015/05/27 DOTA
Python加pyGame实现的简单拼图游戏实例
2015/05/15 Python
Python 实现微信防撤回功能
2019/04/29 Python
如何把python项目部署到linux服务器
2020/08/26 Python
Python 字典一个键对应多个值的方法
2020/09/29 Python
特步官方商城:Xtep
2017/03/21 全球购物
英国最大的海报商店:GB Posters
2018/03/20 全球购物
大学四年个人的自我评价
2014/02/26 职场文书
2015年五四青年节活动总结
2015/02/10 职场文书
国家助学贷款承诺书
2015/04/30 职场文书
朋友圈早安励志语录!
2019/07/08 职场文书