css/js 压缩

为了提高页面加载速度,通常将css文件和js文件压缩成生成一个文件引入,其中css直接以文本形式放在页面头部,js以异步请求的方式放在页面底部。下面为CI框架下实现的压缩类。

压缩类文件:Compress.php

<?php

// +----------------------------------------------------------------------
// | 静态资源css,js压缩合并类Compress.class.php
// +----------------------------------------------------------------------
// | Copyright (c) 2003-2014 http://www.17php.org All rights reserved.
// |  支持压缩js,css,剔除换行,注释
// |  合并多个js和css
// |  自动修正css里的背景图片的地址,绝对路径和远程图片url不会被修正
// |  自动检测不存在的载入js,css 提示错误并退出
// |  缓存已经压缩合并的css和js,只有在载入的js,css有改动才会重新压缩合并
// |  会在根目录下生成/Static/Min/Js/和/Static/Min/Css/目录存放压缩合并后的文件
// +----------------------------------------------------------------------
class Compress {
    const FILEDIR =  '/static/min/';
    static public $compress = null;
    private $_type = 'css';
    private $_mode = '';
    private $_files = array(); //待处理的文件
    private $_cacheFileDir = ''; //缓存文件存放目录
    private $_cacheFileName = ''; //缓存文件名称
    private $_fileContent = ''; //文件内容

    public function init($files = array(), $type = "css", $outPath = null){
        $this->_setType($type); //设置文件类型
        $this->_setMode(); //设置文件处理模型
        $this->_setFiles($files); //设置待处理文件
        $this->_setCaheFileDir($outPath); //设置缓存文件目录
        $this->_setCacheFileName(); // 设置缓存文件名称
        $this->_setFileContent(); //设置文件内容
    }
    
    //获取压缩文件内容
    static public function get($file = array(),$type='css',$outPath=null,$method='link'){
        if(!self::$compress instanceof self){
            self::$compress = new self();
        }
        self::$compress->init($file,$type,$outPath);
        //更新文件内容
        return self::$compress->_getFile($method);
    }
    
    //对外提供缓存文件名称
    public function getCacheFile(){
        return self::getDomain().self::FILEDIR."{$this->_type}/".$this->_cacheFileName;
    }
    
    //对外提供文件内容
    public function getFileContent(){
        return $this->_fileContent;
    }
    
    //获取缓存文件
    private function _getFile($method='link'){
        $method .= 'Reback';
        $compress = $this->_mode;
        return $compress::$method($this);
    }
    
    //设置文件类型
    private function _setType($type){
        $this->_type = $type;
    }
    
    //设置文件处理模型
    private function _setMode(){
        $mode = 'Compress'.ucfirst(strtolower($this->_type));
        if(!class_exists($mode)) throw new CompressException("文件格式{$mode}无法识别");
        return $this->_mode = $mode;
    }
    
    //设置缓存文件目录
    private function _setCaheFileDir($outPath=''){
        $outPath = empty($outPath) ? $_SERVER['DOCUMENT_ROOT'].self::FILEDIR."{$this->_type}/" : $outPath;
        if(!is_dir($outPath)){
            if(!mkdir($outPath,0775,TRUE)) throw new CompressException("缓存文件目录{$outPath}创建失败");
        }
        return $this->_cacheFileDir = $outPath;
    }
    
    //设置待处理文件
    public function _setFiles($files=array()){
        if(empty($files)) throw new CompressException("待压缩文件名缺失");
        $files = is_array($files) ? $files : explode(',',$files);
        foreach($files as $key=>$value){
            $fileName = $_SERVER['DOCUMENT_ROOT'].$value;
            if(!file_exists($fileName)) {
                throw new CompressException("待压缩文件{$fileName}缺失");
                break;
            }
            $files[$key] = $fileName;
        }
        return $this->_files = $files;
    }
    
    //生成缓存文件名称(依据文件名和文件内容)
    private function _setCacheFileName(){
        $cacheName = '';
        foreach($this->_files as $key=>$value){
            $cacheName .= md5_file($value);
        }
        return $this->_cacheFileName = md5($cacheName).".{$this->_type}";
    }
    
    //更新缓存文件内容
    private function _setFileContent(){
        $cacheFilePath = $this->_cacheFileDir.$this->_cacheFileName;
        if(file_exists($cacheFilePath)){
            $this->_fileContent = file_get_contents($cacheFilePath);
        }else{
            file_put_contents($cacheFilePath,$this->_getFileContent());
        }
        return $this->_fileContent;
    }
    
    //获取文件内容
    private function _getFileContent(){
        $content = '';
        $compress = $this->_mode;
        foreach($this->_files as $key=>$value){
            $content .= $compress::strip($value);
        }
        
        return $this->_fileContent = $content;
    }    
    
    //获取网站域名
    public static function getDomain(){
        /* 协议 */
        $protocol = (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) ? 'https://' : 'http://';
        /* 域名或IP地址 */
        if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
            $host = $_SERVER['HTTP_X_FORWARDED_HOST'];
        } elseif (isset($_SERVER['HTTP_HOST'])) {
            $host = $_SERVER['HTTP_HOST'];
        } else {
            $port = ''; //端口
            if (isset($_SERVER['SERVER_PORT'])) {
                $port = ':' . $_SERVER['SERVER_PORT'];
                if ((':80' == $port && 'http://' == $protocol) || (':443' == $port && 'https://' == $protocol)) {
                    $port = '';
                }
            }
            if (isset($_SERVER['SERVER_NAME'])) {
                $host = $_SERVER['SERVER_NAME'] . $port;
            } elseif (isset($_SERVER['SERVER_ADDR'])) {
                $host = $_SERVER['SERVER_ADDR'] . $port;
            }
        }
        return $protocol . $host;        
    }
}


/**
 * 压缩类型父类
 */
interface CompressModel {
    static public function strip($file='');
    static public function linkReback(Compress $e);
    static public function contentReback(Compress $e);
}
 
/**
 * 压缩JS
 */
class Compressjs implements CompressModel{
    private static $ignore = array("://", "\//", '"//', "'//");
    private static $temporary = array("!@#temporary_string_one!@#", "!@#temporary_string_two!@#", "!@#temporary_string_three!@#", "!@#temporary_string_four!@#");
    
    //过滤无效字符
    static function strip($file=''){
        $content = file_get_contents($file);
        $content = str_replace(self::$ignore, self::$temporary, $content);
        $content = preg_replace('#\/\/[^\r\n]*#', '', $content); //剔除js行注释
        $content = str_replace(self::$temporary, self::$ignore, $content);
        $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content); //剔除内容里的块注释
        $content = str_replace(array("\r\n", "\r", "\n", "\t"), ' ', $content); //剔除换行
        $content = str_replace(array('  ','   '),' ',$content); //剔除多空格
        return rtrim($content,';').';';
    }
    
    //以link形式返回
    static function linkReback(Compress $e){
        return '<script type="text/javascript" src="' . $e->getCacheFile() . '"></script>';
    }
    
    //以文本形式返回
    static function contentReback(Compress $e){
        return "<style type=\"text/javascript\">".$e->getFileContent()."</style>";
    }
}

/**
 * 压缩CSS
 */
class CompressCss implements CompressModel {
    
    /**
     * strip 过滤无效字符
     * @param  string $file 待处理的文件路径
     * @return string      处理后的内容
     */    
    static function strip($file=''){
        $content = file_get_contents($file);
        $path = dirname($file) . "/"; //获取载入文件的目录
        preg_match_all("/url\((.*)\)/iUs", $content, $mach);
        $mach = array_unique($mach[1]);
        foreach ($mach as $k => $v) {
            $url = trim($v, "'\"");
            if(strpos($v,'data:image') !== false) continue;
            if (substr($url, 0, 1) != "/" && substr(strtolower($url), 0, 4) != 'http') {
                $url = explode("?", $path . trim($url, "'\""));
                $url[0] = realpath($url[0]);
                $url = str_replace(str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']), '', str_replace('\\', '/', implode("?", $url)));
                $url = '/' . trim($url, "/");
                if (!empty($url)) $content = str_replace($v, $url, $content);
            }
        }
        $content = str_replace(array(", "), ',', $content);
        $content = str_replace(array(': '), ':', $content);
        $content = preg_replace('/@charset (.*);/i', '', $content); //剔除css编码信息
        $content = str_replace(array("url()", "background:;", "background: ;"), '', $content);
        $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content); //剔除内容里的块注释
        $content = str_replace(array("\r\n", "\r", "\n", "\t"), ' ', $content); //剔除换行
        $content = str_replace(array('  ','   '),' ',$content); //剔除多空格
        return $content;
    }    
    
    //以link形式返回
    static function linkReback(Compress $e){
        return '<link type="text/css" rel="stylesheet" href="' . $e->getCacheFile() . '"></link>';
    }
    
    //以文本形式返回
    static function contentReback(Compress $e){
        return "<style type=\"text/css\">".$e->getFileContent()."</style>";
    }
}

class CompressException extends Exception {
    public function __construct($message='',$code=0){
        parent::__construct($message,$code);
    }
    public function handle(){
        writeLog($this->getmessage(),'CompressException');
    }
}


在 base_help.php 文件中定义执行入口:


if (!function_exists("css")) {

    /**
     * 压缩css
     * @param array|string $files 要载入的css文件
     * @param boolen $getUrl 是否获取压缩文件的url
     * @return string
     */
    function css($files = array(), $type = 'content') {
        include_once APPPATH . '/libraries/Compress.class.php';
        try{
            return Compress::get($files,'css',null,$type);
        }catch(CompressException $e){
            $e->handle();
        }        
    }

}



if (!function_exists("js")) {

    /**
     * 压缩js
     * @param array|string $files 要载入的js文件
     * @param boolen $getUrl 是否获取压缩文件的url
     * @return string
     */
    function js($files = array(), $type = 'link') {
        include_once APPPATH . '/libraries/Compress.class.php';
        try{
            return Compress::get($files,'js',null,$type);
        }catch(CompressException $e){
            $e->handle();
        }
    }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值