PHP模板解析类实例
本文实例讲述了PHP模板解析类。分享给大家供大家参考。具体如下:
<?php classtemplate{ 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');//目前只支持读取模板默认路径 publicfunction__construct($conf){ $this->conf=&$conf; $this->template_c=$this->conf['template_config']['template_c'];//编译目录 $this->_tpl_suffix=$this->tpl_suffix(); } privatefunctionstr_replace($search,$replace,$content){ if(empty($search)||empty($replace)||empty($content))returnfalse; returnstr_replace($search,$replace,$content); } /** *preg_match_all *@param$pattern正则 *@param$content内容 *@returnarray */ privatefunctionpreg_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; } /** *模板文件后缀 */ publicfunctiontpl_suffix(){ $tpl_suffix=empty($this->conf['template_config']['template_suffix'])? $this->tpl_suffix: $this->conf['template_config']['template_suffix']; return$tpl_suffix; } /** *此处不解释了 *@return */ publicfunctionassign($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 */ publicfunctiondisplay($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 */ privatefunctioncompile(){ $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; } } /** *读取当前项目配置文件 */ protectedfunctionread_config(){ if(file_exists(SYSTEM_PATH.'conf/config.php')){ @includeSYSTEM_PATH.'conf/config.php'; return$config; } returnfalse; } /** *解析模板语法 *@param$str内容 *@param$compile_dirpath模版编译目录 *@param$vars_template_c_name模版编译文件名 *@return编译过的PHP模板文件名 */ privatefunctiontemplate_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-dH:i:s',$tpl_filemtime).'<br/>'; //echo$compile_filemtime.'=='.date('Y-m-dH:i:s',$compile_filemtime); //如果文件过期编译当模板标签有include并且有修改时也重新编译 //<{includefile="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; } /** *模板文件主体 *@paramstring$str内容 *@returnhtml */ privatefunctionbody_content($str){ //解析 $str=$this->parse($str); $header_comment="CreateOn##".time()."|Compiledfrom##".$this->template_path.$this->template_name; $content="<?if(!defined('IS_HEARTPHP'))exit('AccessDenied');/*{$header_comment}*/?>\r\n$str"; return$content; } /** *开始解析相关模板标签 *@param$content模板内容 */ privatefunctionparse($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']}>转成<?phpecho$config['domain']?> */ privatefunctionparse_echo($content){ } /** *转换为PHP *@param$contenthtml模板内容 *@returnhtml替换好的HTML */ privatefunctionparse_php($content){ if(empty($content))returnfalse; $content=preg_replace("/".$this->template_tag_left."(.+?)".$this->template_tag_right."/is","<?php$1?>",$content); return$content; } /** *if判断语句 *<{ifempty($zhang)}> *zhang *<{elseifempty($liang)}> *liang *<{else}> *zhangliang *<{/if}> */ privatefunctionparse_if($content){ if(empty($content))returnfalse; //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],"<?phpif({$v}){?>",$content); } return$content; } privatefunctionparse_elseif($content){ if(empty($content))returnfalse; //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; } /** *解析includeinclude标签不是实时更新的当主体文件更新的时候才更新标签内容,所以想include生效请修改一下主体文件 *记录一下有时间开发一个当DEBUG模式的时候每次执行删除模版编译文件 *使用方法<{includefile="www.phpddt.com"}> *@param$content模板内容 *@returnhtml */ privatefunctionparse_include($content){ if(empty($content))returnfalse; //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($aas$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],'<?phpinclude("'.$include_file.'")?>',$content); } return$content; } /** *解析foreach *使用方法<{foreachfrom=$listsitem=valuekey=kk}> *@param$content模板内容 *@returnhtml解析后的内容 */ privatefunctionparse_foreach($content){ if(empty($content))returnfalse; //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($splitas$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='<?phpforeach('.$from.'as'.$key.'$'.$item.'){?>'; $content=$this->str_replace($match[0][$match_key],$s,$content); } return$content; } /** *匹配结束字符串 */ privatefunctionparse_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; } /** *检查编译目录如果没有创建则递归创建目录 *@paramstring$path文件完整路径 *@return模板内容 */ privatefunctioncheck_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; } /** *读文件 *@paramstring$path文件完整路径 *@return模板内容 */ privatefunctionread_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; } /** *写文件 *@paramstring$filename文件名 *@paramstring$content模板内容 *@return文件名 */ privatefunctioncompile_file($filename,$content,$dir){ if(empty($filename))core::show_error("{$filename}Creationfailed"); $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] */ publicfunctioncheck_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'){//checkwirteandread if(!is_writable($path)||!is_readable($path)){ core::show_error("{$path}<br/>没有写入或读取权限,请检查"); } } } /** *读取编译后模板的第一行并分析成数组 *@paramstring$filepath文件路径 *@paramnumber$line行数 *@return返回指定行数的字符串 */ /* privatefunctionget_compile_header($filepath,$line=0){ if(($file_arr=@file($filepath))===false){ core::show_error($filepath.'<br/>读取文件失败,请检查文件权限!'); } return$file_arr[0]; } */ /** *分析头部注释的日期 *@paramstring$cotnent编译文件头部第一行 *@return返回上一次日期 */ /* privatefunctionget_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]; } */ /** *获取模板完整路径并返回已存在文件 *@paramstring$filename文件名 *@paramstring$view_path模板路径 *@return */ privatefunctionget_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; returntrue; }else{ core::show_error($filename.$this->_tpl_suffix.'模板不存在'); } } } /** *获取模板路径 *@paramstring$path主目录 *@returnURLD和M的拼接路径 */ privatefunctionget_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.'/'; } /** *创建目录 *@paramstring$path目录 *@return */ privatefunctioncreate_dir($path,$mode=0777){ if(is_dir($path))returnfalse; $dir_arr=explode('/',$path); $dir_arr=array_filter($dir_arr); $allpath=''; $newdir=$this->template_c; foreach($dir_arras$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; } } returntrue; } publicfunction__destruct(){ $this->vars=null; $this->view_path_param=null; } }
希望本文所述对大家的php程序设计有所帮助。