CodeIgniter使用phpcms模板引擎


Posted in PHP onNovember 12, 2013

CodeIgniter很适合小站点应用开发,但是它自带的view功能可能会给不懂PHP的前端人员带来麻烦。 相比之下phpcms的view模板解析就强大多了,所以这里就把PHPCMS的模板解析功能剥离出来,加到PHPCMS上。
首先在CodeIgniter libraries中 增加 template_cache.php

<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); 
/**
 *  模板解析缓存
 */
final class template_cache {    public $cache_path;
    public function __construct()
    {
        //$CI =& get_instance();
        $this->cache_path = APPPATH.'views';
    }
    /**
     * 编译模板
     *
     * @param $module    模块名称
     * @param $template    模板文件名
     * @param $istag    是否为标签模板
     * @return unknown
     */
    public function template_compile($module, $template, $style = 'default') {
        $tplfile= APPPATH.'views'.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.$template.'.php';
        if (! file_exists ( $tplfile )) {
            show_error($tplfile ,  500 ,  'Template does not exist(1)');
        }
        $content = @file_get_contents ( $tplfile );

        $filepath = $this->cache_path.DIRECTORY_SEPARATOR.'caches_template'.DIRECTORY_SEPARATOR.$style.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR;
        
        if(!is_dir($filepath)) {
            mkdir($filepath, 0777, true);
        }
        $compiledtplfile = $filepath.$template.'.php';
        $content = $this->template_parse($content);
        $strlen = file_put_contents ( $compiledtplfile, $content );
        chmod ( $compiledtplfile, 0777 );
        return $strlen;
    }
    /**
     * 更新模板缓存
     *
     * @param $tplfile    模板原文件路径
     * @param $compiledtplfile    编译完成后,写入文件名
     * @return $strlen 长度
     */
    public function template_refresh($tplfile, $compiledtplfile) {
        $str = @file_get_contents ($tplfile);
        $str = $this->template_parse ($str);
        $strlen = file_put_contents ($compiledtplfile, $str );
        chmod ($compiledtplfile, 0777);
        return $strlen;
    }
    
    /**
     * 解析模板
     *
     * @param $str    模板内容
     * @return ture
     */
    public function template_parse($str) {
        $str = preg_replace ( "/\{template\s+(.+)\}/", "<?php include template(\\1); ?>", $str );
        $str = preg_replace ( "/\{include\s+(.+)\}/", "<?php include \\1; ?>", $str );
        $str = preg_replace ( "/\{view\s+(.+)\}/", "<?php \$this->load->view(\\1); ?>", $str );
        $str = preg_replace ( "/\{php\s+(.+)\}/", "<?php \\1?>", $str );
        //alex fix
        $str = preg_replace ( "/\{{if\s+(.+?)\}}/", "``if \\1``", $str );
        $str = preg_replace ( "/\{{else\}}/", "``else``", $str );
        $str = preg_replace ( "/\{{\/if\}}/", "``/if``", $str );
        $str = preg_replace ( "/\{if\s+(.+?)\}/", "<?php if(\\1) { ?>", $str );
        $str = preg_replace ( "/\{else\}/", "<?php } else { ?>", $str );
        $str = preg_replace ( "/\{elseif\s+(.+?)\}/", "<?php } elseif (\\1) { ?>", $str );
        $str = preg_replace ( "/\{\/if\}/", "<?php } ?>", $str );
        //for 循环
        $str = preg_replace("/\{for\s+(.+?)\}/","<?php for(\\1) { ?>",$str);
        $str = preg_replace("/\{\/for\}/","<?php } ?>",$str);
        //++ --
        $str = preg_replace("/\{\+\+(.+?)\}/","<?php ++\\1; ?>",$str);
        $str = preg_replace("/\{\-\-(.+?)\}/","<?php ++\\1; ?>",$str);
        $str = preg_replace("/\{(.+?)\+\+\}/","<?php \\1++; ?>",$str);
        $str = preg_replace("/\{(.+?)\-\-\}/","<?php \\1--; ?>",$str);
        //alex fix
        $str = preg_replace ( "/\``if\s+(.+?)\``/", "{{if \\1}}", $str );
        $str = preg_replace ( "/\``else``/", "{{else}}", $str );
        $str = preg_replace ( "/\``\/if\``/", "{{/if}}", $str );
        $str = preg_replace ( "/\{loop\s+(\S+)\s+(\S+)\}/", "<?php \$n=1;if(is_array(\\1)) foreach(\\1 AS \\2) { ?>", $str );
        $str = preg_replace ( "/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/", "<?php \$n=1; if(is_array(\\1)) foreach(\\1 AS \\2 => \\3) { ?>", $str );
        $str = preg_replace ( "/\{\/loop\}/", "<?php \$n++;}unset(\$n); ?>", $str );
        $str = preg_replace ( "/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/", "<?php echo \\1;?>", $str );
        $str = preg_replace ( "/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}/", "<?php echo \\1;?>", $str );
        $str = preg_replace ( "/\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", "<?php echo \\1;?>", $str );
        $str = preg_replace("/\{(\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/es", "\$this->addquote('<?php echo \\1;?>')",$str);
        $str = preg_replace ( "/\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}/s", "<?php echo \\1;?>", $str );
        $str = preg_replace("/\{pc:(\w+)\s+([^}]+)\}/ie", "self::pc_tag('$1','$2', '$0')", $str);
        $str = preg_replace("/\{\/pc\}/ie", "self::end_pc_tag()", $str);
        $str = "<?php defined('BASEPATH') or exit('No direct script access allowed.'); ?>" . $str;
        return $str;
    }
    /**
     * 转义 // 为 /
     *
     * @param $var    转义的字符
     * @return 转义后的字符
     */
    public function addquote($var) {
        return str_replace ( "\\\"", "\"", preg_replace ( "/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var ) );
    }
    /**
     * 解析PC标签
     * @param string $op 操作方式
     * @param string $data 参数
     * @param string $html 匹配到的所有的HTML代码
     */
    public static function pc_tag($op, $data, $html) {
        preg_match_all("/([a-z]+)\=[\"]?([^\"]+)[\"]?/i", stripslashes($data), $matches, PREG_SET_ORDER);
        $arr = array('action','num','cache','page', 'pagesize', 'urlrule', 'return', 'start','setpages');
        $tools = array('json', 'xml', 'block', 'get');
        $datas = array();
        $tag_id = md5(stripslashes($html));
        //可视化条件
        $str_datas = 'op='.$op.'&tag_md5='.$tag_id;
        foreach ($matches as $v) {
            $str_datas .= $str_datas ? "&$v[1]=".($op == 'block' && strpos($v[2], '$') === 0 ? $v[2] : urlencode($v[2])) : "$v[1]=".(strpos($v[2], '$') === 0 ? $v[2] : urlencode($v[2]));
            if(in_array($v[1], $arr)) {
                $$v[1] = $v[2];
                continue;
            }
            $datas[$v[1]] = $v[2];
        }
        $str = '';
        $setpages = isset($setpages) && intval($setpages) ? intval($setpages) : 10;
        $num = isset($num) && intval($num) ? intval($num) : 20;
        $cache = isset($cache) && intval($cache) ? intval($cache) : 0;
        $return = isset($return) && trim($return) ? trim($return) : 'data';
        if (!isset($urlrule)) $urlrule = '';
        if (!empty($cache) && !isset($page)) {
            $str .= '$tag_cache_name = md5(implode(\'&\','.self::arr_to_html($datas).').\''.$tag_id.'\');if(!$'.$return.' = tpl_cache($tag_cache_name,'.$cache.')){';
        }
        if (in_array($op,$tools)) {
            switch ($op) {
                case 'json':
                        if (isset($datas['url']) && !empty($datas['url'])) {
                            $str .= '$json = @file_get_contents(\''.$datas['url'].'\');';
                            $str .= '$'.$return.' = json_decode($json, true);';
                        }
                    break;
                case 'block':
                    $str .= '$block_tag = pc_base::load_app_class(\'block_tag\', \'block\');';
                    $str .= 'echo $block_tag->pc_tag('.self::arr_to_html($datas).');';
                    break;
            }
        } else {
            if (!isset($action) || empty($action)) return false;
            if ( file_exists(APPPATH.'libraries'.DIRECTORY_SEPARATOR.$op.'_tag.php')) {
                $str .= 'if(!isset($CI))$CI =& get_instance();$CI->load->library("'.$op.'_tag");if (method_exists($CI->'.$op.'_tag, \''.$action.'\')) {';    
                if (isset($start) && intval($start)) {
                    $datas['limit'] = intval($start).','.$num;
                } else {
                    $datas['limit'] = $num;
                }
                if (isset($page)) {
                    $str .= '$pagesize = '.$num.';';
                    $str .= '$page = intval('.$page.') ? intval('.$page.') : 1;if($page<=0){$page=1;}';
                    $str .= '$offset = ($page - 1) * $pagesize;$urlrule="'.$urlrule.'";';
                    $datas['limit'] = '$offset.",".$pagesize';
                    $datas['action'] = $action;
                    $str .= '$'.$op.'_total = $CI->'.$op.'_tag->count('.self::arr_to_html($datas).');';
                    $str .= 'if($'.$op.'_total>$pagesize){ $pages = pages($'.$op.'_total, $page, $pagesize, $urlrule); } else { $pages="" ;}';
                }
                $str .= '$'.$return.' = $CI->'.$op.'_tag->'.$action.'('.self::arr_to_html($datas).');';
                $str .= '}';
            } 
        }
        if (!empty($cache) && !isset($page)) {
            $str .= 'if(!empty($'.$return.')){setcache($tag_cache_name, $'.$return.', \'tpl_data\');}';
            $str .= '}';
        }
        return "<"."?php ".$str."?".">";
    }
    /**
     * PC标签结束
     */
    static private function end_pc_tag() {
        return '<?php if(defined(\'IN_ADMIN\') && !defined(\'HTML\')) {if(isset($data))unset($data);echo \'</div>\';}?>';
    }
    /**
     * 转换数据为HTML代码
     * @param array $data 数组
     */
    private static function arr_to_html($data) {
        if (is_array($data)) {
            $str = 'array(';
            foreach ($data as $key=>$val) {
                if (is_array($val)) {
                    $str .= "'$key'=>".self::arr_to_html($val).",";
                } else {
                    if (strpos($val, '$')===0) {
                        $str .= "'$key'=>$val,";
                    } else {
                        $str .= "'$key'=>'".self::new_addslashes($val)."',";
                    }
                }
            }
            return $str.')';
        }
        return false;
    }
    /**
     * 返回经addslashes处理过的字符串或数组
     * @param $string 需要处理的字符串或数组
     * @return mixed
     */
    function new_addslashes($string){
        if(!is_array($string)) return addslashes($string);
        foreach($string as $key => $val) $string[$key] = new_addslashes($val);
        return $string;
    }
}

然后在global_helper中增加一个 template函数
if ( ! function_exists('template'))
{
    /**
     * 模板调用
     * 
     * @param $module
     * @param $template
     * @param $istag
     * @return unknown_type
     */
    function template($module = 'expatree', $template = 'index', $style = 'expatree',$return_full_path=true) {
        global $CI;
        if(!isset($CI))$CI =& get_instance();
        if(!$style) $style = 'default';
        $CI->load->library('template_cache','template_cache');
        $template_cache = $CI->template_cache;
        //编译模板生成地址
        $compiledtplfile = $template_cache->cache_path.DIRECTORY_SEPARATOR.'caches_template'.DIRECTORY_SEPARATOR.$style.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.$template.EXT;
        //视图文件
        $tplfile= APPPATH.'views'.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.$template.EXT;
        if(file_exists($tplfile)) {
            if(!file_exists($compiledtplfile) || (@filemtime($tplfile) > @filemtime($compiledtplfile))) {    
                $template_cache->template_compile($module, $template, $style);
            }
        } else {
            //如果没有就调取默认风格模板
            $compiledtplfile = $template_cache->cache_path.DIRECTORY_SEPARATOR.'caches_template'.DIRECTORY_SEPARATOR.'default'.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.$template.EXT;
            if(!file_exists($compiledtplfile) || (file_exists($tplfile) && filemtime($tplfile) > filemtime($compiledtplfile))) {
                $template_cache->template_compile($module, $template, 'default');
            } elseif (!file_exists($tplfile)) {
                show_error($tplfile ,  500 ,  'Template does not exist(0)');
            }
        }
        if($return_full_path)
            return $compiledtplfile;
        else
            return 'caches_template'.DIRECTORY_SEPARATOR.$style.DIRECTORY_SEPARATOR.$module.DIRECTORY_SEPARATOR.$template;
    }
}

然后在MY_Controller.php,增加一个方法
/**
    * 自动模板调用
    * 
    * @param $module
    * @param $template
    * @param $istag
    * @return unknown_type
    */
   protected function view($view_file,$page_data=false,$cache=false)
   {
       $view_file=$this->template($this->page_data['controller_name'].$this->page_data['module_name'],$view_file);       $this->load->view($view_file,$page_data);
   }

这样基本上完成了,可以直接phpcms模板语法了。
PHP 相关文章推荐
php foreach、while性能比较
Oct 15 PHP
php 空格,换行,跳格使用说明
Dec 18 PHP
用PHP获取Google AJAX Search API 数据的代码
Mar 12 PHP
PHP eval函数使用介绍
Dec 08 PHP
Thinkphp中的volist标签用法简介
Jun 18 PHP
PHP获取表单所有复选框的值的方法
Aug 28 PHP
php获取根域名方法汇总
Oct 28 PHP
smarty缓存用法分析
Dec 16 PHP
PHP中的类型约束介绍
May 11 PHP
laravel创建类似ThinPHP中functions.php的全局函数
Nov 26 PHP
php实现微信发红包功能
Jul 13 PHP
Laravel 自动转换长整型雪花 ID 为字符串的实现
Oct 27 PHP
php用正则表达式匹配URL的简单方法
Nov 12 #PHP
CodeIgniter基本配置详细介绍
Nov 12 #PHP
PHP URL路由类实例
Nov 12 #PHP
PHP set_error_handler()函数使用详解(示例)
Nov 12 #PHP
php inc文件使用的风险和注意事项
Nov 12 #PHP
php防止SQL注入详解及防范
Nov 12 #PHP
php session劫持和防范的方法
Nov 12 #PHP
You might like
PHP Curl出现403错误的解决办法
2014/05/29 PHP
smarty模板引擎之内建函数用法
2015/03/30 PHP
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
PHP CURL post数据报错 failed creating formpost data
2016/10/16 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
Laravel框架实现简单的学生信息管理平台案例
2019/05/07 PHP
PHP扩展类型及安装方式解析
2020/04/27 PHP
JS 拼图游戏 面向对象,注释完整。
2009/06/18 Javascript
JavaScript 选中文字并响应获取的实现代码
2011/08/28 Javascript
JavaScript面向对象之Prototypes和继承
2012/07/12 Javascript
JS跨域代码片段
2012/08/30 Javascript
Js,alert出现乱码问题的解决方法
2013/06/19 Javascript
jquery+easeing实现仿flash的载入动画
2015/03/10 Javascript
简单谈谈node.js 版本控制 nvm和 n
2015/10/15 Javascript
浅析JavaScript动画模拟拖拽原理
2016/12/09 Javascript
12306 刷票脚本及稳固刷票脚本(防挂)
2017/01/04 Javascript
Vue.js中 v-model 指令的修饰符详解
2018/12/03 Javascript
详解vue更改头像功能实现
2019/04/28 Javascript
js实现的订阅发布者模式简单示例
2020/03/14 Javascript
[46:23]OG vs EG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python中IPYTHON入门实例
2015/05/11 Python
pandas groupby 分组取每组的前几行记录方法
2018/04/20 Python
对Xpath 获取子标签下所有文本的方法详解
2019/01/02 Python
Python实现通过解析域名获取ip地址的方法分析
2019/05/17 Python
softmax及python实现过程解析
2019/09/30 Python
Python 添加文件注释和函数注释操作
2020/08/09 Python
Django Form常用功能及代码示例
2020/10/13 Python
美国批发零售网站:GearXS
2016/07/26 全球购物
中科软笔试题和面试题
2014/10/07 面试题
秦兵马俑教学反思
2014/02/07 职场文书
投标承诺书范本
2014/03/27 职场文书
2014年三万活动总结
2014/04/26 职场文书
大学生见习报告总结
2014/11/04 职场文书
Win11 Build 22000.51版本文件资源管理器“命令栏”和上下文菜单有什么新变化?
2021/11/21 数码科技
HTML基本元素标签介绍
2022/02/28 HTML / CSS
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers