CodeIgniter使用phpcms模板引擎
author:一佰互联 2019-04-29   click:144

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 ( "/{templates+(.+)}/", "<?php include template(\1); ?>", $str );
        $str = preg_replace ( "/{includes+(.+)}/", "<?php include \1; ?>", $str );
        $str = preg_replace ( "/{views+(.+)}/", "<?php $this->load->view(\1); ?>", $str );
        $str = preg_replace ( "/{phps+(.+)}/", "<?php \1?>", $str );
        //alex fix
        $str = preg_replace ( "/{{ifs+(.+?)}}/", "``if \1``", $str );
        $str = preg_replace ( "/{{else}}/", "``else``", $str );
        $str = preg_replace ( "/{{/if}}/", "``/if``", $str );        $str = preg_replace ( "/{ifs+(.+?)}/", "<?php if(\1) { ?>", $str );
        $str = preg_replace ( "/{else}/", "<?php } else { ?>", $str );
        $str = preg_replace ( "/{elseifs+(.+?)}/", "<?php } elseif (\1) { ?>", $str );
        $str = preg_replace ( "/{/if}/", "<?php } ?>", $str );        //for 循环
        $str = preg_replace("/{fors+(.+?)}/","<?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 ( "/``ifs+(.+?)``/", "{{if \1}}", $str );
        $str = preg_replace ( "/``else``/", "{{else}}", $str );
        $str = preg_replace ( "/``/if``/", "{{/if}}", $str );        $str = preg_replace ( "/{loops+(S+)s+(S+)}/", "<?php $n=1;if(is_array(\1)) foreach(\1 AS \2) { ?>", $str );
        $str = preg_replace ( "/{loops+(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模板语法了。