Created
February 13, 2015 09:42
-
-
Save forthxu/f9a94d9dfe8a8f8d2853 to your computer and use it in GitHub Desktop.
yaf基础模板类
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Util; | |
| class YafTemplate implements \Yaf\View_Interface{ | |
| private $style = ''; //当前生效的风格,用于缓存目录 | |
| private $mConfig = array( | |
| 'path' => '', //模板目录,绝对地址即在当前地址上加模块目录, | |
| 'suffix' => 'html', //模板后缀 | |
| 'divide' => '/', //模板分割符,控制器和方法中间的分割符, | |
| 'compile_suffix'=> '.php', //编译后缀 | |
| 'ismd5' => 1, //编译时是否使用Md5加密缓存文件名 | |
| 'style' => '', //模板风格 通常用于设置WAP风格,没有的时候返回默认风格 | |
| 'defaultstyle' => '', //模板默认风格目录,不存在将报错 | |
| 'tag_left' => '{', //左标签 | |
| 'tag_right' => '}', //右标签 | |
| 'cache_path' => '#runtime/cache' , //缓存目录 | |
| 'isviewfilter' => 1, //是否对变量进行转换 | |
| //如果写到相对目录是什么情况? | |
| ); | |
| /** | |
| * 构造函数 | |
| * @param object $config 设置参数 | |
| */ | |
| public function __construct($rConfig='') { | |
| if(!$rConfig){ | |
| $rConfig = \base::config('application.view')->toArray(); | |
| if($cache_path=\base::config('application.path.cache')) | |
| $this->mConfig['cache_path'] = $cache_path.'/template'; | |
| } | |
| if($rConfig['ext']) $this->mConfig['suffix'] = $rConfig['ext']; | |
| if($rConfig['divide']) $this->mConfig['divide'] = $rConfig['divide']; | |
| if($rConfig['path']) $this->mConfig['path'] = $rConfig['path']; | |
| if($rConfig['defaultstyle']) $this->mConfig['defaultstyle'] = $rConfig['defaultstyle']; | |
| if($rConfig['style']) $this->mConfig['style'] = $rConfig['style']; | |
| } | |
| /** | |
| * 引入模板,模板中使用 {template "文件","模块"} | |
| * @param | |
| */ | |
| public function Template($name,$m='') { | |
| $template_file_name = $this->getTemplateFile($name,$m); | |
| $cache_file_name = $this->getCacheFile($name,$m); | |
| if( !file_exists($cache_file_name) || | |
| ( | |
| file_exists($template_file_name) && | |
| filemtime($template_file_name) > filemtime($cache_file_name) | |
| ) | |
| ) { | |
| $this->cache_template($template_file_name, $cache_file_name); | |
| } | |
| return $cache_file_name; | |
| } | |
| /** | |
| * 设置视图模板的目录 该类继承 Yaf_View_Interface 必须存在 | |
| * @param string $template_path | |
| */ | |
| public function setScriptPath($template_path){ | |
| $this->mConfig['path'] = $template_path; | |
| } | |
| /** | |
| * 获取视图模板的目录 该类继承 Yaf_View_Interface 必须存在 | |
| * @return string | |
| */ | |
| public function getScriptPath(){ | |
| return $this->mConfig['path']; | |
| } | |
| /** | |
| * 自动实例化模版 该类继承 Yaf_View_Interface 必须存在 | |
| * @param string $template | |
| */ | |
| public function render($template,$value=null) { | |
| //去除自动渲染模版带上后缀问题 | |
| $template = preg_replace('/.'.$this->mConfig['suffix'].'/', '', $template); | |
| //生成模板路径 | |
| $template = $this->Template($template); | |
| //获取当前可用变量, | |
| $tVar = \base::registry('','Template'); | |
| //对模板变量进行过滤 | |
| if ($this->mConfig['isviewfilter']) $this->out_put($tVar); | |
| foreach ($tVar as $key => $value) { | |
| $$key = $value; | |
| } | |
| include $template ; | |
| } | |
| /** | |
| * 手动显示视图,和render自动调用不一样,本方法被调用即关闭自动视图功能, | |
| * 使用方法:$this->view->display(); | |
| * @param string $template | |
| * @return array | |
| */ | |
| public function display($template='', $value = null) { | |
| \YAF\Dispatcher::getInstance()->autoRender(FALSE); | |
| if(empty($template)){ | |
| $mca = \base::registry('Trigger','Route'); | |
| $template = strtolower($mca['controller']).'/'.$mca['action']; | |
| } | |
| if(!empty($value)) $this->tVar = $value; | |
| $this->render($template); | |
| } | |
| /** | |
| * 设置模板变量 | |
| * 模板赋值核心函数,$key => $value , 模板变量名称 => 控制器中变量 | |
| * Controller中使用方法:$this->view->assign($key, $value); | |
| * @param string $key | |
| * @param string $value | |
| */ | |
| public function assign($name, $value = null){ | |
| \base::registry(array($name=>$value),'Template'); | |
| } | |
| /** | |
| * 模板编译-缓存模板 | |
| * @param string $template_file_name 源文件名称 | |
| * @param string $cache_file_name 目标文件 | |
| * @return void | |
| */ | |
| private function cache_template($template_file_name, $cache_file_name) { | |
| if(is_dir($path = dirname($cache_file_name)) == false){ //判断目录是否存在 | |
| $this->create_dir($path); | |
| } | |
| if(!file_exists($template_file_name)) \base::error($template_file_name . ' 文件不存在!'); | |
| //得到文件 | |
| $str = @file_get_contents($template_file_name); | |
| //替换标签 | |
| $str = $this->replace_tag($str); | |
| //写入缓存文件 | |
| $ret = @file_put_contents($cache_file_name, $str); | |
| if ($ret == false) { | |
| \base::error($cache_file_name . ' 写入失败!'); | |
| } | |
| } | |
| /** | |
| * 模板编译-标签正则替换 | |
| * @param string $str 模板文件数据 | |
| * @return string | |
| */ | |
| private function replace_tag($str) { | |
| return $this->simple($str, $this->mConfig['tag_left'], $this->mConfig['tag_right']); //编译 | |
| } | |
| /** | |
| * 得到模板文件 | |
| * @param object $config 设置参数 | |
| */ | |
| public function getTemplateFile($name,$m='') { | |
| //分隔符的转换 | |
| if(!empty($this->mConfig['divide']) && $this->mConfig['divide'] !=DS){ | |
| $name = str_replace (DS,$this->mConfig['divide'],$name); | |
| }else if(empty($this->mConfig['divide'])){ | |
| //如果没有分隔符,是不是应该去掉控制器呢? | |
| } | |
| $file_name = $name.'.'.$this->mConfig['suffix']; | |
| //获取当前模块 | |
| if(empty($m)) $m = \base::registry('Trigger.Module','Route'); | |
| //模板目录是相对目录,模板文件位于模块下的风格目录中 | |
| if(!is_dir($this->mConfig['path'])){ | |
| $models_path = \base::config('application.path.modules'); | |
| $path = $models_path.DS.$m.DS.$this->mConfig['path']; | |
| $path = str_replace ('/',DS,$path); | |
| }else{ //模板目录是绝对目录,文件位于模板目录下的风格包中的模块文件里 | |
| $path = $this->mConfig['path']; | |
| $file_name = $m.DS.$file_name; | |
| } | |
| $style = ''; | |
| //判断风格目录文件是否存在 | |
| if(!empty($this->mConfig['style'])){ | |
| $template_path = $path.DS.$this->mConfig['style'].DS.$file_name; | |
| if(is_file($template_path)){ | |
| $style = $this->mConfig['style']; | |
| } | |
| } | |
| if(empty($style) && !empty($this->mConfig['defaultstyle'])){ | |
| $template_path = $path.DS.$this->mConfig['defaultstyle'].DS.$file_name; | |
| if(is_file($template_path)){ | |
| $style = $this->mConfig['defaultstyle']; | |
| } | |
| }else{ | |
| //风格获取失败,生成默认的模板(不带风格的) | |
| if(empty($style)) $template_path = $path .DS.$file_name; | |
| } | |
| if(!is_file($template_path)){ | |
| \base::error($name.'模板文件不存在'); | |
| } | |
| $this->style = $style; | |
| return $template_path; | |
| } | |
| /** | |
| * 得到缓存文件路径 | |
| */ | |
| public function getCacheFile($name,$m='') { | |
| $cache_path = $this->mConfig['cache_path']; | |
| if(!empty($this->style)){ | |
| $cache_path .= '/'.$this->style; | |
| } | |
| //获取当前模块 | |
| if(empty($m)) $m = \base::registry('Trigger.Module','Route'); | |
| $name = "$m/$name"; | |
| if($this->mConfig['ismd5']){ | |
| //MD5的模板不需要分目录.全扔到一个风格目录下就行了 | |
| $name = md5($cache_path.$name); | |
| } | |
| $path = $cache_path.'/'.$name.$this->mConfig['compile_suffix']; | |
| // $path = str_replace ('/',DS,$path); | |
| $this->create_dir(dirname($path)); | |
| return $path; | |
| } | |
| /** | |
| * 创建目录 | |
| * @param string $path 目录 | |
| * @return | |
| */ | |
| private function create_dir($path) { | |
| if (is_dir($path)) return true; | |
| $this->create_dir(dirname($path)); | |
| @mkdir($path); | |
| @chmod($path, 0777); | |
| return true; | |
| } | |
| /** | |
| * 模板驱动-简单的驱动 | |
| * @param string $str 模板文件数据 | |
| * @return string | |
| */ | |
| private function simple($str, $left, $right) { | |
| $pregs = array( | |
| //规则,替换值,修饰符,修饰符在更高级的PHP环境中,需要再来处理一次 TODO | |
| array('\/\*(.+?)\*\/','','s'), //清除注释 | |
| array('\/\/(.+?)','',''), | |
| array(':(.+?)','<?php echo \1;?>',''), //函数 {:func()} | |
| //变量 | |
| array('(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_$\x7f-\xff\[\]\'\']*)','<?php echo \1;?>','s'), | |
| //全局变量 | |
| array('([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)','<?php echo \1;?>',''), | |
| //循环 | |
| array('loop((\w+)?)\s+(\S+)\s+(\S+)','<?php $n\2=1;if(is_array(\3)) foreach(\3 AS \4) { ?>',''), | |
| array('loop((\w+)?)\s+(\S+)\s+(\S+)\s+(\S+)','<?php $n\2=1; if(is_array(\3)) foreach(\3 AS \4 => \5) { ?>',''), | |
| array('\/loop((\w+)?)','<?php $n\2++;}unset($n\2); ?>',''), | |
| array('if\s+(.+?)','<?php if(\1) { ?>',''), | |
| array('else','<?php } else { ?>',''), | |
| array('elseif\s+(.+?)','<?php } elseif (\1) { ?>',''), | |
| array('\/if','<?php } ?>',''), | |
| //PHP代码 | |
| array('php\s+(.+)','<?php \\1?>',''), | |
| //调用模板 | |
| array('template\s+(.+)','<?php include $this->Template(\1); ?>',''), | |
| //引用文件, | |
| array('include\s+(.+)','<?php include \1; ?>',''), | |
| ); | |
| //代码块 | |
| $str = preg_replace ( "/\<php\>(.+?)\<\/php\>/s", "<?php \\1?>", $str); | |
| foreach ($pregs as $value) { | |
| $key = "/".$left.$value[0].$right.'/'.$value[2]; | |
| $str = preg_replace($key,$value[1],$str); | |
| } | |
| //合并多行PHP代码 | |
| $str = preg_replace ( "/\?>((\s+)?)<\?php/", "", $str); | |
| //压缩代码 | |
| $str = $this->compress_html($str); | |
| return $str; | |
| } | |
| /** | |
| * 模板-模板变量输出过滤 | |
| * @param array $arr 视图存放器数组 | |
| * @return array | |
| */ | |
| private function out_put(&$value) { | |
| $value = (array) $value; | |
| foreach ($value as $key => $val) { | |
| if (is_array($val)) { | |
| $this->out_put($value[$key]); | |
| } elseif (is_object($val)) { | |
| $value[$key] = $val; | |
| } else { | |
| if (function_exists('htmlspecialchars')) { | |
| $value[$key] = htmlspecialchars($val); | |
| } else { | |
| $value[$key] = str_replace(array("&", '"', "'", "<", ">", "%3C", "%3E"), array("&", """, "'", "<", ">", "<", ">"), $val); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * 压缩html : 清除换行符,清除制表符,去掉多余空格 | |
| * @param $string | |
| * @return 压缩后的$string | |
| * */ | |
| function compress_html($string) { | |
| $string = str_replace("\r\n", '', $string); //清除换行符 | |
| $string = str_replace("\n", '', $string); //清除换行符 | |
| $string = str_replace("\t", '', $string); //清除制表符 | |
| $pattern = array ( | |
| "/>\s+</Um", | |
| "/>(\s+\n|\r)/", | |
| "/[\s]+/", | |
| ); | |
| $replace = array ('><', '>', ' '); | |
| return preg_replace($pattern, $replace, $string); | |
| } | |
| //更安全的压缩 | |
| //启城 2015-1-28 1:32:33 未完成的压缩,,丢失了 /HTML | |
| function compress_html2($html) { | |
| $segments = preg_split("/(<[^>]+?>)/si",$html, -1,PREG_SPLIT_NO_EMPTY| PREG_SPLIT_DELIM_CAPTURE); | |
| $compressed = array(); | |
| $stack = array(); | |
| $tag = ''; | |
| $half_open = array('meta','input','link','img','br'); | |
| $cannot_compress = array('pre','code','script'); | |
| // P($segments); | |
| foreach($segments as $seg) | |
| { | |
| if(trim($seg) === '') | |
| { | |
| continue; | |
| } | |
| //<.../> | |
| if(preg_match("!<([a-z0-9]+)[^>]*?/>!si",$seg, $match)) | |
| { | |
| //$tag = self::format_tag($match[1]); | |
| $this->format_tag($match[1]); | |
| $compressed[] = $seg; | |
| } | |
| else if(preg_match("!</([a-z0-9]+)[^>]*?>!si",$seg,$match))//</..> | |
| { | |
| $tag = $this->format_tag($match[1]); | |
| if(count($stack) > 0 && $stack[count($stack)-1] == $tag) | |
| { | |
| array_pop($stack); | |
| $compressed[] = $seg; | |
| } | |
| //这里再最好加一段判断,可以用于修复错误的html | |
| //... | |
| } | |
| else if(preg_match("!<([a-z0-9]+)[^>]*?>!si",$seg,$match))//<> | |
| { | |
| $tag = $this->format_tag($match[1]); | |
| //半闭合标签不需要入栈,如<br/>,<img/> | |
| if(!in_array($tag, $half_open)) | |
| { | |
| array_push($stack,$tag); | |
| } | |
| // P($seg);die; | |
| $compressed[] = $seg; | |
| } | |
| else if(preg_match("~<![^>]*>~", $seg)) | |
| { | |
| //文档声明和注释,注释也不能删除,如<!--ie条件--> | |
| $compressed[] = $seg; | |
| } | |
| else if(preg_match("/[^<\?php](.*)\?>/", $seg)) | |
| { | |
| //php 代码不可以删除 | |
| $compressed[] = $seg; | |
| } | |
| else | |
| { | |
| // P($tag); | |
| $compressed[] = in_array($tag, $cannot_compress) ? $seg : preg_replace('!\s!', '', $seg); | |
| } | |
| } | |
| // P($compressed);die; | |
| $html = join('',$compressed); | |
| return $html; | |
| } | |
| function format_tag($tag) | |
| { | |
| return trim(strtolower($tag)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment