当前位置: 首页 > SEO教程 > 中度优化技术 > PHP脚本语言自动压缩静态资源文件(css、js)

PHP脚本语言自动压缩静态资源文件(css、js)

这次,我总结并分享了一种大规模的网站优化技术,该技术可以自动压缩项目中的静态资源文件(css,js),并让网站自动加载压缩的资源文件。当然网站优化技术,这项技术也记录在Yahoo的35个前端优化建议中,但这只是一个理论上的解决方案,它使用外部压缩工具对其进行压缩,而在我的项目中,它是直接通过我自己的程序自动生成的压缩所有的css和js文件,然后让页面直接加载压缩的资源,然后直接输入主题。

该实验使用PHP脚本语言,版本为PHP 5. 6,这是在LINUX下构建的环境(用于构建LAMP或LNMP的在线教程都很混乱,下一次我将总结并分享一篇博客文章关于如何在LINUX下构建服务器环境的说明,并且构建环境必须成功构建一次)。选择的框架是CI框架,使用的模板是Smarty模板引擎。当然,这些只是我使用的环境。如果您是PHP开发人员,则想测试此实验,那么我建议您的PHP版本为5. 4或更高。至于框架,您可以使用任何东西。而且,如果您不是PHP开发人员(您是JSP或ASP开发人员或其他开发人员),那么在您理解了这个想法之后,就可以用您熟悉的语言进行实验性测试。

一、示意图

首先,我画出一个思路图,供大家首先理解。

首先,是资源压缩的示意图:

网站优化技术

接下来是资源文件替换的示意图:

网站优化技术

如果您仔细地理解和理解这两个原理图,那么您将基本掌握我分享的想法。如果您仍然不理解它,我将使用代码详细解释上述示意图的每个步骤。

二、想法的详细分析

1.首先,调用压缩方法。您可以将此方法放在要在网站上加载的公共类的位置。例如,每次您访问该网站时,都会调用该压缩方法进行压缩。当然,这仅在开发环境中每次都调用。如果是在线环境,则在发布网站的新版本时,只需调用用于生成压缩版本的静态资源即可。

 1 class MY_Controller extends CI_Controller {
 2     public function __construct() {
 3         parent::__construct();
 4 
 5         //压缩jscss资源文件
 6         $this->compressResHandle();
 7     }
 8     /**
 9      * 压缩js、css资源文件(优化)
10      * @return [type] [description]
11      */
12     private function compressResHandle() {
13         $this->load->library('ResMinifier');
14         //压缩指定文件夹下的资源文件
15         $this->resminifier->compressRes();
16     }
17 }

2.然后在ResMinifier类中调用compressRes方法。在这里,我首先附加ResMinifier类的代码,然后可以方便地逐步分析和解释

  1 php 
  2 defined('BASEPATH') OR exit('No direct script access allowed');
  3 /**
  4  * 资源压缩类
  5  */
  6 class ResMinifier {
  7     /** 需要压缩的资源目录*/
  8     public $compressResDir = ['css', 'js'];
  9     /** 忽略压缩的路径,例如此处是js/icon开头的路径忽略压缩*/
 10     public $compressResIngorePrefix = ['js/icon'];
 11     /** 资源根目录*/
 12     public $resRootDir;
 13     /** 资源版本文件路径*/
 14     private $resStatePath;
 15 
 16     public function __construct() {
 17         $this->resRootDir = WEBROOT . 'www/';
 18         $this->resStatePath = WEBROOT . 'www/resState.php';
 19     }
 20 
 21     public function compressRes() {
 22         //获取存放版本的资源文件
 23         $resState = $this->getResState();
 24         $count = 0;
 25 
 26         //开始遍历需要压缩的资源目录
 27         foreach ($this->compressResDir as $resDir) {
 28             foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->resRootDir . $resDir , FilesystemIterator::SKIP_DOTS)) as $file) {
 29                 //获取该资源文件的绝对路径
 30                 $filePath = str_replace('\\', '/', $file->getRealPath());
 31                 //获取文件相对路径
 32                 $object = substr($filePath, strlen($this->resRootDir));
 33                 //计算文件的版本号
 34                 $state = $this->_getResStateVersion($filePath);
 35 
 36                 //获取文件的几个参数值
 37                 if (true !== $this->getObjectInfo($object, $minObject, $needCompress, $state, $extension)) {
 38                     continue;
 39                 }
 40 
 41                 //压缩文件的绝对路径
 42                 $minFilePath = str_replace('\\', '/', $this->resRootDir. $minObject);
 43 
 44                 //************此处p判断是最重要部分之一*****************//
 45                 //判断文件是否存在且已经改动过
 46                 if (isset($resState[$object]) && $resState[$object] == $state && isset($resState[$minObject]) && file_exists($minFilePath)) {
 47                     continue;
 48                 }
 49 
 50                 //确保/www/min/目录可写
 51                 $this->_ensureWritableDir(dirname($minFilePath));
 52 
 53                 if ($needCompress) {
 54                     $this->compressResFileAndSave($filePath, $minFilePath);
 55                 } else {
 56                     copy($filePath, $minFilePath);
 57                 }
 58 
 59 
 60                 $resState[$object] = $state;
 61                 $resState[$minObject] = '';
 62                 $count++;
 63 
 64                 if ($count == 50) {
 65                     $this->_saveResState($resState);
 66                     $count = 0;
 67                 }
 68 
 69             }
 70         }
 71         if($count) $this->_saveResState($resState);
 72     }
 73 
 74     public function getObjectInfo($object, &$minObject, &$needCompress, &$state, &$extension) {
 75         //获取资源绝对路径
 76         $filePath = $this->resRootDir . $object;
 77         //判断资源是否存在
 78         if (!file_exists($filePath)) return "资源文件不存在{$filePath}";
 79         //版本号
 80         $state = $this-> _getResStateVersion($filePath);
 81         //文件名后缀
 82         $extension = pathinfo($filePath, PATHINFO_EXTENSION);
 83         //是否要压缩
 84         $needCompress = true;
 85 
 86         //判断资源文件是否是以 .min.css或者.min.js结尾的
 87         //此类结尾一般都是已压缩过,例如jquery.min.js,就不必再压缩了
 88         if (str_end_with($object, '.min.'.$extension, true)) {
 89             //压缩后的资源存放路径,放在 /www/min/ 目录下
 90             $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension) - 4) . $state .'.'. $extension;
 91             $needCompress = false;
 92         } else if (in_array($extension, $this->compressResDir)) {
 93             //此处是需要压缩的文件目录
 94             $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension)) . $state . '.' . $extension;
 95             //看看是否是忽略的路径前缀
 96             foreach ($this->compressResIngorePrefix as $v) {
 97                 if (str_start_with($object, $v, true)) {
 98                     $needCompress = false;
 99                 }
100             }
101         } else {
102             $minObject = 'min/'.$object;
103             $needCompress = false;
104         }
105         return true;
106     }
107 
108 
109     /**
110      * 获取存放资源版本的文件
111      * 它是放在一个数组里
112      * $resState = array(
113      *         '文件路径' => '对应的版本号',
114      *         '文件路径' => '对应的版本号',
115      *         '文件路径' => '对应的版本号',
116      *     );
117      * @return [type] [description]
118      */
119     public function getResState() {
120         if (file_exists($this->resStatePath)) {
121             require $this->resStatePath;
122             return $resState;
123         }
124         return [];
125     }
126 
127     /**
128      * 计算文件的版本号,这个是根据计算文件MD5散列值得到版本号
129      * 只要文件内容改变了,所计算得到的散列值就会不一样
130      * 用于判断资源文件是否有改动过
131      * @param  [type] $filePath [description]
132      * @return [type]           [description]
133      */
134     public function _getResStateVersion($filePath) {
135         return base_convert(crc32(md5_file($filePath)), 10, 36);
136     }
137 
138     /**
139      * 确保目录可写
140      * @param  [type] $dir [description]
141      * @return [type]      [description]
142      */
143     private function _ensureWritableDir($dir) {
144         if (!file_exists($dir)) {
145             @mkdir($dir, 0777, true);
146             @chmod($dir, 0777);
147         } else if (!is_writable($dir)) {
148             @chmod($dir, 0777);
149             if (!is_writable($dir)) {
150                 show_error('目录'.$dir.'不可写');
151             }
152         }
153     }
154 
155     /**
156      * 将压缩后的资源文件写入到/www/min/下去
157      * @param  [type] $filePath    [description]
158      * @param  [type] $minFilePath [description]
159      * @return [type]              [description]
160      */
161     private function compressResFileAndSave($filePath, $minFilePath) {
162         if (!file_put_contents($minFilePath, $this->compressResFile($filePath))) {
163 
164             //$CI->exceptions->show_exception("写入文件{$minFilePath}失败");
165             show_error("写入文件{$minFilePath}失败", -1);
166         }
167     }
168 
169     /**
170      * 压缩资源文件
171      * @param  [type] $filePath [description]
172      * @return [type]           [description]
173      */
174     private function compressResFile($filePath) {
175         $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
176         if ($extension === 'js') {
177             require_once 'JShrink/Minifier.php';
178             return \JShrink\Minifier::minify(file_get_contents($filePath));
179         } else if ($extension ==='css') {
180             $content = file_get_contents($filePath);
181             $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
182             $content = str_replace(["\r\n", "\r", "\n"], '', $content);
183             $content = preg_replace('/([{}),;:>])\s+/', '$1', $content);
184             $content = preg_replace('/\s+([{}),;:>])/', '$1', $content);
185             $content = str_replace(';}', '}', $content);
186             return $content;
187         } else {
188             //$CI->exceptions->show_exception("不支持压缩{extension}文件[$filePath]");
189             show_error("不支持压缩{extension}文件[$filePath]", -1);
190 
191         }
192     }
193 
194     private function _saveResState($resState) {
195         ksort($resState);
196         $content = ";
197         foreach ($resState as $k => $v) {
198             $content .= "\t '$k' => '$v',\n";
199         }
200         $content .= ");\n\n";
201         file_put_contents($this->resStatePath, $content); 
202     }
203 
204 }

单击以打开资源压缩类

我在整个类的大多数代码中添加了注释,以帮助您快速理解。在这里,我还将解释每一行代码。

([1)

/** 需要压缩的资源目录*/
    public $compressResDir = ['css', 'js'];
    /** 忽略压缩的路径,例如此处是js/icon开头的路径忽略压缩*/
    public $compressResIngorePrefix = ['js/icon'];
    /** 资源根目录*/
    public $resRootDir;
    /** 资源版本文件路径*/
    private $resStatePath;
    public function __construct() {
        $this->resRootDir = WEBROOT . 'www/';
        $this->resStatePath = WEBROOT . 'www/resState.php';
    }

$ compressResDir变量是需要压缩的资源目录。如果有新的处理目录,则只要新目录名称在此变量中,就可以对其进行处理。附上我的测试项目的目录图

网站优化技术

$ compressResIngorePrefix忽略压缩路径。路径的前面是数组变量的字符串。例如,资源路径是js / icon / bg.js或js / icon_index.js或js / icon.header。 js,如果将字符串js / icon添加到数组中,则以js / icon开头的资源路径将被忽略,即直接跳过而不进行压缩。 (因为总有一些资源文件不需要压缩)

$ resRootDir存储资源根目录

$ resStatePath这是资源版本文件路径

(2)输入compressRes()方法,让我们首先分析前面的代码

public function compressRes() {
        //获取存放版本的资源文件
        $resState = $this->getResState();
        $count = 0;  

-------------------------------调用getResState()解释开始--------- -------------------------------------------------- --

首先要调用$ this-> getResState()方法来获取存储版本的资源文件,这里首先跳转至该方法以查看其编写方式,实际上是要包含该文件,然后返回存储在数组中的版本号,通过查看注释我们可以知道存储在文件中的版本号的格式(顺便附上图片供大家查看)

   /**
     * 获取存放资源版本的文件
     * 它是放在一个数组里
     * $resState = array(
     *         '文件路径' => '对应的版本号',
     *         '文件路径' => '对应的版本号',
     *         '文件路径' => '对应的版本号',
     *     );
     * @return [type] [description]
     */
    public function getResState() {
        if (file_exists($this->resStatePath)) {
            require $this->resStatePath;
            return $resState;
        }
        return [];
    }

(资源版本文件的屏幕截图:)

网站优化技术

-------------------------------调用getResState()解释结束--------- -------------------------------------------------- --

在compressRes()中查看这段代码

//开始遍历需要压缩的资源目录
        foreach ($this->compressResDir as $resDir) {
            foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->resRootDir . $resDir , FilesystemIterator::SKIP_DOTS)) as $file) {
                //获取该资源文件的绝对路径
                $filePath = str_replace('\\', '/', $file->getRealPath());
                //获取文件相对路径
                $object = substr($filePath, strlen($this->resRootDir));
                //计算文件的版本号
                $state = $this->_getResStateVersion($filePath);

第一个遍历是js和css目录。第二遍是将js目录或css目录中的文件更改为路径形式,

例如,文件$ filePath的绝对路径的值如下:

seo技术优化_英文网站优化_网站优化技术

/usr/local/apache2/htdocs/project/www/css/home/index.css

文件的相对路径$ object如下:

css / home / index.css

在这里,我们开始调用$ this-> _ getResStateVersion($ filePath)来计算文件的版本号

-------------------------------调用_getResStateVersion($ filePath)来解释开始------- -------------------------------------------------- ----

/**
     * 计算文件的版本号,这个是根据计算文件MD5散列值得到版本号
     * 只要文件内容改变了,所计算得到的散列值就会不一样
     * 用于判断资源文件是否有改动过
     * @param  [type] $filePath [description]
     * @return [type]           [description]
     */
    public function _getResStateVersion($filePath) {
        return base_convert(crc32(md5_file($filePath)), 10, 36);
    }

-------------------------------调用_getResStateVersion($ filePath)解释结束------ -------------------------------------------------- ----

或者在获得版本号之后,查看下一段代码。在这里,开始调用$ this-> getObjectInfo()方法。在这里,您可以获取压缩文件$ minObject的相对路径,无论是否需要压缩$ needCompress,版本号$ state,文件后缀$ extension。

             //获取文件的几个参数值
                if (true !== $this->getObjectInfo($object, $minObject, $needCompress, $state, $extension)) {
                    continue;
                }
            

-------------------------------调用$ this-> getObjectInfo()解释开始----- -------------------------------------------------- ------

   /**
     * 获取资源文件相关信息
     * @param  [type] $object       资源文件路径 (www/css/home/index.css)
     * @param  [type] $minObject    压缩资源文件路径 (www/min/css/home/index.ae123a.css)
     * @param  [type] $needCompress 是否需要压缩
     * @param  [type] $state        文件版本号
     * @param  [type] $extension    文件名后缀
     * @return [type]               [description]
     */
    public function getObjectInfo($object, &$minObject, &$needCompress, &$state, &$extension) {
        //获取资源绝对路径
        $filePath = $this->resRootDir . $object;
        //判断资源是否存在
        if (!file_exists($filePath)) return "资源文件不存在{$filePath}";
        //版本号
        $state = $this-> _getResStateVersion($filePath);
        //文件名后缀
        $extension = pathinfo($filePath, PATHINFO_EXTENSION);
        //是否要压缩
        $needCompress = true;
        //判断资源文件是否是以 .min.css或者.min.js结尾的
        //此类结尾一般都是已压缩过,例如jquery.min.js,就不必再压缩了
        if (str_end_with($object, '.min.'.$extension, true)) {
            //压缩后的资源存放路径,放在 /www/min/ 目录下
            $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension) - 4) . $state .'.'. $extension;
            $needCompress = false;
        } else if (in_array($extension, $this->compressResDir)) {
            //此处是需要压缩的文件目录
            $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension)) . $state . '.' . $extension;
            //看看是否是忽略的路径前缀
            foreach ($this->compressResIngorePrefix as $v) {
                if (str_start_with($object, $v, true)) {
                    $needCompress = false;
                }
            }
        } else {
            $minObject = 'min/'.$object;
            $needCompress = false;
        }
        return true;
    }

此方法中的每一行代码都基本注释过,因此我不会用一句话来解释,这里我们主要看下面的判断部分:

    if (str_end_with($object, '.min.'.$extension, true))  这个判断是比较资源文件路径字串后面部分是否以 .min.$extension 结尾,例如是 jquery.min.js,这种文件本来就是
压缩过的文件,所以就不用再进行压缩处理了, $minObject 这个变量存放的是压缩后的资源文件路径。
  此处附上str_end_with()函数的代码:

/**
     * 判断 subject 是否以 search结尾, 参数指定是否忽略大小写
     * @param  [type]  $subject     [description]
     * @param  [type]  $search      [description]
     * @param  boolean $ignore_case [description]
     * @return [type]               [description]
     */
    function str_end_with($subject, $search, $ignore_case = false) {
        $len2 = strlen($search);
        if (0 === $len2) return true;
        $len1 = strlen($subject);
        if ($len2 > $len1) return false;
        if ($ignore_case) {
            return 0 === strcmp(substr($subject, $len1 - $len2), $search);
        } else {
            return 0 === strcasecmp(substr($subject, $len1 - $len2), $search);
        }
    }

如果是(in_array($ extension,$ this-> compressResDir),则此判断是是否在两个目录中,需要处理。

然后在foreach内部($ this-> compressResIngorePrefix as $ v){if(str_start_with($ object,$ v,true)){$ needCompress = false;}}

这是判断路径是否是由$ this-> compressResIngorePrefix属性定义的字符串的开头部分开始的路径,如果是,则忽略资源文件的压缩。

判断结束时,否则意味着不需要压缩资源文件,并最终返回$ minObject,$ needCompress,$ state和$ extension这四个变量。

-------------------------------调用$ this-> getObjectInfo()解释结束----- -------------------------------------------------- ------

让我们继续在这里查看compressRes()方法中的代码

                //压缩文件的绝对路径
                $minFilePath = str_replace('\\', '/', $this->resRootDir. $minObject);
                //************此处p判断是最重要部分之一*****************//
                //判断文件是否存在且已经改动过
                if (isset($resState[$object]) && $resState[$object] == $state && isset($resState[$minObject]) && file_exists($minFilePath)) {
                    continue;
                }    

此代码首先拼接出压缩文件的绝对路径,

下一个判断是关键部分。通过此判断,您可以知道资源文件是否已更改。如果已更改,请重新压缩资源文件。如果尚未更改,请继续处理下一个。资源。在这里查看判断:isset($ resState [$ object])&& $ resState [$ object] == $ state,该判断是判断文件路径是否存在以及文件中对应的版本号以及计算的版本号仍然一致; isset($ resState [$ minObject])&& file_exists($ minFilePath),这是用来判断压缩文件路径是否存在以及目录中是否实际存在压缩文件。

看下一段代码。如果您可以转到此部分,则表示当前资源文件已更改(代码已修改),然后此时将文件压缩。

                //确保/www/min/目录可写
                $this->_ensureWritableDir(dirname($minFilePath));
                if ($needCompress) {
                    $this->compressResFileAndSave($filePath, $minFilePath);
                } else {
                    copy($filePath, $minFilePath);
                }

$ this-> _ ensureWritableDir(),此方法是确保新创建的www / min目录可写,这是代码:

-------------------------------调用$ this-> _ ensureWritableDir()解释开始----- -------------------------------------------------- ------

   /**
     * 确保目录可写
     * @param  [type] $dir [description]
     * @return [type]      [description]
     */
    private function _ensureWritableDir($dir) {
        if (!file_exists($dir)) {
            @mkdir($dir, 0777, true);
            @chmod($dir, 0777);
        } else if (!is_writable($dir)) {
            @chmod($dir, 0777);
            if (!is_writable($dir)) {
                show_error('目录'.$dir.'不可写');
            }
        }
    }

-------------------------------调用$ this-> _ ensureWritableDir()解释结束----- -------------------------------------------------- ------

如果($ needCompress),它判断是否需要压缩资源文件,如有必要,调用$ this-> compressResFileAndSave($ filePath,$ minFilePath);如果没有,直接将文件复制到压缩文件路径copy($ filePath,$ minFilePath);

首先查看$ this-> compressResFileAndSave()

-------------------------------调用$ this-> compressResFileAndSave()解释开始----- -------------------------------------------------- ------

    /**
     * 将压缩后的资源文件写入到/www/min/下去
     * @param  [type] $filePath    [description]
     * @param  [type] $minFilePath [description]
     * @return [type]              [description]
     */
    private function compressResFileAndSave($filePath, $minFilePath) {
        if (!file_put_contents($minFilePath, $this->compressResFile($filePath))) {
            //$CI->exceptions->show_exception("写入文件{$minFilePath}失败");
            show_error("写入文件{$minFilePath}失败", -1);
        }
    }
    /**
     * 压缩资源文件
     * @param  [type] $filePath [description]
     * @return [type]           [description]
     */
    private function compressResFile($filePath) {
        $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        if ($extension === 'js') {
            require_once 'JShrink/Minifier.php';
            return \JShrink\Minifier::minify(file_get_contents($filePath));
        } else if ($extension ==='css') {
            $content = file_get_contents($filePath);
            $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
            $content = str_replace(["\r\n", "\r", "\n"], '', $content);
            $content = preg_replace('/([{}),;:>])\s+/', '$1', $content);
            $content = preg_replace('/\s+([{}),;:>])/', '$1', $content);
            $content = str_replace(';}', '}', $content);
            return $content;
        } else {
            //$CI->exceptions->show_exception("不支持压缩{extension}文件[$filePath]");
            show_error("不支持压缩{extension}文件[$filePath]", -1);
        }
    } 

首先压缩,然后将压缩的内容写入压缩的文件路径。

首先让我们看一下这种压缩方法:

$ this-> compressResFile($ filePath);此方法有两种压缩类型。第一种压缩js文件,第二种压缩css文件。首先让我谈谈js压缩,这是一个调用JShrink的类,

英文网站优化_网站优化技术_seo技术优化

百度可以找到一个用于压缩js文件的PHP类。调用此类的minify()方法可以对其进行压缩; CSS压缩使用常规替换来压缩,删除那些空格和线条。到目前为止,压缩已成功

,然后将压缩资源写入相应的压缩文件路径。

-------------------------------调用$ this-> compressResFileAndSave()解释结束----- -------------------------------------------------- ------

然后继续查看compressRes()方法中的代码,这里是将新版本号保存在$ resState数组$ object => $ state中,以及新的压缩路径$ minObject,这里是$ count ++。效果是,当循环为50次时,$ resState的数组将被写入一次resState.php文件。这是经过严格考虑的。如果您不将$ count添加到此部分,则可以编写一次。就是这样。

                $resState[$object] = $state;
                $resState[$minObject] = '';
                $count++;
                if ($count == 50) {
                    $this->_saveResState($resState);
                    $count = 0;
                }
            }
        }
        if($count) $this->_saveResState($resState);         

在这里查看$ this-> _ saveResState($ resState)。此方法是将$ resState数组写入resState.php文件。

-------------------------------调用$ this-> _ saveResState($ resState)解释开始--- -------------------------------------------------- --------

    private function _saveResState($resState) {
        ksort($resState);
        $content = ";
        foreach ($resState as $k => $v) {
            $content .= "\t '$k' => '$v',\n";
        }
        $content .= ");\n\n";
        file_put_contents($this->resStatePath, $content); 
    }    

-------------------------------调用$ this-> _ saveResState($ resState)解释结束- -------------------------------------------------- --------

处理后,查看生成的文件。这里将有一个文件的多个版本。旧版本尚未删除。在开发环境中是否删除它并不重要。为什么不在这里删除旧版本的压缩文件?这涉及更新多个应用程序服务器代码时应注意的问题。让我在这里多解释一点。让我给你一个简单的例子。通常,大型项目中的静态资源和模板文件部署在不同的计算机群集上。在联机过程中,静态资源和页面文件的部署时间间隔可能会很长。对于大型Internet应用程序,即使在很小的时间间隔内,也可能会有新的用户访问。如果删除旧版本的静态资源,但尚未部署新版本的静态资源,则用户将无法加载该静态资源,其结果可想而知。因此,在正常情况下,我们将保留旧版本的静态资源,然后等待所有部署完成,然后通过某个脚本将其删除。这些不必删除。想一想,当一个版本发布一个项目时,资源文件压缩方法将被调用一次。它只会为修改后的文件生成具有新版本号的静态文件。这完全取决于个人实践。

网站优化技术

我们可以打开它看看。以下是压缩文件的代码。文件的原始大小为16K。压缩后,大约少了5K。现在是11K。压缩比约为2/3。如果它在大型项目中,那么一个复杂的页面将有一个很大的静态资源文件要加载,这种方法大大提高了加载速度。 (也许有些朋友认为压缩几个K或十几个K没什么,它可以完全忽略。实际上,我想说的是,当在大型项目中优化项目时,可以减少代码的数量。 K很少,这也提高了网站的性能。改进了很多)

网站优化技术

至此,对资源压缩处理的分析完成了。实际上,有一定基础的朋友可以看一下我直接共享的代码。如果他们听不懂,请看我上面的逐步分析和说明。我是一个可以看到此博客的朋友,无论使用哪种技术。这是好事还是有些弱,可以理解,因此逐步分析并解释了代码。 (希望您能对我有很多帮助)

--------------------------------------------------- -------------------------------------------------- ------------------------

3.接下来是解释如何替换压缩的资源文件。

这到Home.php

 1 php
 2 defined('BASEPATH') OR exit('No direct script access allowed');
 3 
 4 class Home extends MY_Controller {
 5     public function index() {
 6         $this->smartyData['test'] = 111;
 7         //这个默认是加载 www/css/home/index.css文件
 8         $this->addResLink('index.css');
 9         //这个默认是加载www/js/jquery.all.min.js文件
10         $this->addResLink('/jquery.all.min.js');
11         //这个默认是加载www/js/index.js文件
12         $this->addResLink('index.js');
13         $this->displayView('home/index.tpl');
14     }
15 }

上面加载了三个资源文件,让我们看一下$ this-> addResLink();。这个方法,这个方法放在My_Controller.php中:

    /**
     * 资源路径
     * @param [type] $filePath [description]
     */
    protected function addResLink($filePath) {
        list($filePath, $query) = explode('?', $filePath . '?');
        $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        foreach ($this->_resLink as $v) {
            if (false === array_search($filePath, $this->_resLink[$extension])) {
                $this->_resLink[$extension][] = $query == null ? $filePath : $filePath .'?'. $query;
            }
        }
        return $this;
    }

这里的主要目的是确定资源文件是css还是js,然后将其存储在$ this-> _ resLink属性中。

所以在这里,我将首先附加父类My_Controller.php的所有代码

  1 php
  2 defined('BASEPATH') OR exit('No direct script access allowed');
  3 
  4 class MY_Controller extends CI_Controller {
  5     public function __construct() {
  6         parent::__construct();
  7 
  8         //压缩jscss资源文件
  9         $this->compressResHandle();
 10     }
 11 
 12     //==========================使用SMARTY模板引擎================================//
 13     /* Smarty母版页文件路径 */
 14     protected $masterPage = 'default.tpl';
 15     /* 视图文件路径*/
 16     protected $smartyView;
 17     /* 要赋值给smarty视图的数据*/
 18     protected $smartyData = [];
 19     /* 资源文件*/
 20     protected $_resLink = ['js'=>[], 'css'=>[]];
 21 
 22     /**
 23      * 使用母版页输出一个视图
 24      * @return [type] [description]
 25      */
 26     protected function displayView($viewName = null, $masterPage = null) {
 27         //为空则选用默认母版
 28         if ($masterPage == null) $masterPage = $this->masterPage;
 29         //获取视图的输出内容
 30         $viewContent = $this->_fetchView($this->smartyData, $viewName, $masterPage);
 31 
 32         $output = '';
 33         
 34         //添加css Link
 35         foreach ($this->_resLink['css'] as $v) {
 36             $output .= res_link($v);
 37         }
 38 
 39         //内容部分
 40         $output .= $viewContent;
 41         //尾部添加js 链接
 42         foreach ($this->_resLink['js'] as $v) {
 43             $output .= res_link($v);
 44         }
 45         //发送最终输出结果以及服务器的 HTTP 头到浏览器
 46         
 47         $this->output->_display($output);
 48         return $output;
 49     }
 50 
 51     private function _fetchView($smartyData, &$viewName, &$masterPage) {
 52         if ($viewName == null) $viewName = $this->smartyView;
 53 
 54         if (empty($this->smarty)) {
 55             require_once SMARTY_DIR.'Smarty.class.php';
 56             $this->smarty = new Smarty();
 57             $this->smarty->setCompileDir(APPPATH . 'cache/');
 58             $this->smarty->setCacheDir(APPPATH . 'cache/');
 59         }
 60 
 61         //设置视图真实路径
 62         $this->_getViewDir(true, $viewName, $masterPage, $templateDir);
 63 
 64         foreach ($smartyData as $k => $v) {
 65             $this->smarty->assign($k, $v);
 66         }
 67 
 68         if (empty($masterPage)) {
 69             return $this->smarty->fetch($viewName);
 70         } else {
 71             $this->smarty->assign('VIEW_MAIN', $viewName);
 72             return $this->smarty->fetch($masterPage);
 73         }
 74     }
 75 
 76     /**
 77      * 资源路径
 78      * @param [type] $filePath [description]
 79      */
 80     protected function addResLink($filePath) {
 81         list($filePath, $query) = explode('?', $filePath . '?');
 82         $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
 83         foreach ($this->_resLink as $v) {
 84             if (false === array_search($filePath, $this->_resLink[$extension])) {
 85                 $this->_resLink[$extension][] = $query == null ? $filePath : $filePath .'?'. $query;
 86             }
 87         }
 88 
 89         return $this;
 90     }
 91 
 92     private function _getViewDir($setTemplateDir, &$viewName, &$masterPage = null, &$templateDir) {
 93         if ('/' === $viewName[0]) $viewName = substr($viewName, 1);
 94 
 95         //是否使用模板,有,则路由到 /views/master_page/*****.tpl下去
 96         if ($masterPage) {
 97             $masterPage = '/' === $masterPage[0] ? substr($masterPage, 1) : ('master_page' .'/'. $masterPage);
 98         }
 99 
100         //是否设置模板目录
101         if ($setTemplateDir) {
102             $templateDir = VIEWPATH;
103             $this->smarty->setTemplateDir($templateDir);
104         }
105     }
106 
107     /**
108      * 压缩js、css资源文件(优化)
109      * @return [type] [description]
110      */
111     private function compressResHandle() {
112         $this->load->library('ResMinifier');
113         //压缩指定文件夹下的资源文件
114         $this->resminifier->compressRes();
115     }
116 }

点击打开My_Controller.php

打印出属性$ this-> _ resLink的结构是这样的:

Array
(
    [js] => Array
        (
            [0] => /jquery.all.min.js
            [1] => index.js
        )
    [css] => Array
        (
            [0] => index.css
        )
)

返回Home.php并调用$ this-> displayView('home / index.tpl');

让我们看看这种方法:

     /**
     * 使用母版页输出一个视图
     * @return [type] [description]
     */
    protected function displayView($viewName = null, $masterPage = null) {
        //为空则选用默认母版
        if ($masterPage == null) $masterPage = $this->masterPage;
        //获取视图的输出内容
        $viewContent = $this->_fetchView($this->smartyData, $viewName, $masterPage);
        $output = '';
        
        //添加css Link
        foreach ($this->_resLink['css'] as $v) {
            $output .= res_link($v);
        }
        //内容部分
        $output .= $viewContent;
        //尾部添加js 链接
        foreach ($this->_resLink['js'] as $v) {
            $output .= res_link($v);
        }
        //发送最终输出结果以及服务器的 HTTP 头到浏览器
        
        $this->output->_display($output);
        return $output;
    }
    private function _fetchView($smartyData, &$viewName, &$masterPage) {
        if ($viewName == null) $viewName = $this->smartyView;
        if (empty($this->smarty)) {
            require_once SMARTY_DIR.'Smarty.class.php';
            $this->smarty = new Smarty();
            $this->smarty->setCompileDir(APPPATH . 'cache/');
            $this->smarty->setCacheDir(APPPATH . 'cache/');
        }
        //设置视图真实路径
        $this->_getViewDir(true, $viewName, $masterPage, $templateDir);
        foreach ($smartyData as $k => $v) {
            $this->smarty->assign($k, $v);
        }
        if (empty($masterPage)) {
            return $this->smarty->fetch($viewName);
        } else {
            $this->smarty->assign('VIEW_MAIN', $viewName);
            return $this->smarty->fetch($masterPage);
        }
    }

这段代码中没有任何部分调用Smarty模板引擎的内容。我不会谈论有关Smarty的知识。您可以自己百度。在这里,我们主要讨论res_link()函数,该函数用于执行资源文件。替换。首先看一下该函数的代码:

    /**
     * 输出 HttpHead 中的资源连接。 css/js 自动判断真实路径
     * @param  string  文件路径
     * @return string      
     */
    function res_link($file) {
        $file = res_path($file, $extension);
        if ($extension === 'css') {
           return '$file . '"/>';
        } else if ($extension === 'js') {
            return '';
        } else {
            return false;
        }
    }
 

这里最重要的是res_path()函数,该函数可以自动路由资源的真实路径。例如:index.css => css / home / index.css

此功能最重要的功能之一是替换资源的压缩版本。

直接查看代码:

   /**
     * 智能路由资源真实路径
     * @param  string      路径
     * @param  string      扩展名
     * @return string       真实路径
     */
    function res_path($file, &$extension) {
        //检查是否存在查询字符串
        list($file, $query) = explode('?', $file . '?');
        //取得扩展名
        $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        //
        $file = str_replace('\\', '/', $file);
        //取得当前控制器名
        global $class;
        if ($class == null) exit('can not get class name');
        $className = strtolower($class);
        //此处的规则是这样:
        //例如,如果不加 / ,Home控制器对应的格式是: index.css,那么 此处的路径会变成css/home/index.css
        //假如有 / ,控制器的格式可以是 /main.css,那么此处的路径会变成 css/main.css(公用的css类)
        if ('/' !== $file[0]) {
            //index.css => css/home/index.css
            $object = $extension .'/'. $className .'/' . $file;
        } else {
            // /css/main.css 或者 /main.css => css/main.css
            $object = substr($file, 1);
            //若object是 main.css ,则自动加上 扩展名目录 => css/main.css
            if (0 !== strncasecmp($extension, $object, strlen($extension))) {
                $object = $extension . '/' . $object;
            }
        }
        //资源真实路径
        $filepath = WEBROOT.'www/'.$object;
        
        //替换压缩版本,这部分逻辑与文件压缩逻辑对应
        if (in_array($extension, array('css', 'js'))) {
            if(!str_start_with($object, 'min/') && file_exists(APPPATH.'libraries/ResMinifier.php')) {
                require_once APPPATH.'libraries/ResMinifier.php';
                $resminifier = new ResMinifier();
                //获取存放资源版本的文件的数组变量
                $resState = $resminifier->getResState();
                //计算得到当前文件版本号
                $state = $resminifier->_getResStateVersion($filepath);
                //判断该版本号是否存在
                if (isset($resState[$object])) {
                    //判断是否是.min.css或.min.js结尾
                    if (str_end_with($object, '.min.'.$extension)) {
                        //将版本号拼接上去,然后得到min的文件路径
                        $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension) - 4) . $state . '.' . $extension;
                    } else {
                        //将版本号拼接上去,然后得到min的文件路径
                        $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension)) . $state . '.' . $extension;
                    }
                    //判断min的路径是否存在在$resState里面
                     if (isset($resState[$minObject])) {
                        $object = $minObject;
                        $query = '';
                     }
                } 
            }
            
            $file = RES_BASE_URL . $object;
        }
        return ($query == null) ? $file : ($file .'?'. $query);
    }

网站优化技术_seo技术优化_英文网站优化

为便于理解,基本上对代码进行了注释。第一部分是智能路径css和js资源的路径,后一部分是替换压缩版本。这部分的逻辑基本上与资源压缩的逻辑相同。它是通过资源文件的路径进行判断和处理,最后获得资源的压缩版本的路径,最后返回资源的压缩版本的路径并将其放入“”。这样,资源文件路径将成功地替换为资源文件路径的压缩版本,并且在输出模板时,输出就是压缩的资源文件。

至此,资源替换的内容完成。并在此处分析了整个技术。

三、摘要

在这里,我专注于在此博客文章中附加几个文件代码:

Home.php

 1 php
 2 defined('BASEPATH') OR exit('No direct script access allowed');
 3 
 4 class Home extends MY_Controller {
 5     public function index() {
 6         $this->smartyData['test'] = 111;
 7         //这个默认是加载 www/css/home/index.css文件
 8         $this->addResLink('index.css');
 9         //这个默认是加载www/js/jquery.all.min.js文件
10         $this->addResLink('/jquery.all.min.js');
11         //这个默认是加载www/js/index.js文件
12         $this->addResLink('index.js');
13         $this->displayView('home/index.tpl');
14     }
15 }

点击打开

My_Controller.php

  1 php
  2 defined('BASEPATH') OR exit('No direct script access allowed');
  3 
  4 class MY_Controller extends CI_Controller {
  5     public function __construct() {
  6         parent::__construct();
  7 
  8         //压缩jscss资源文件
  9         $this->compressResHandle();
 10     }
 11 
 12     //==========================使用SMARTY模板引擎================================//
 13     /* Smarty母版页文件路径 */
 14     protected $masterPage = 'default.tpl';
 15     /* 视图文件路径*/
 16     protected $smartyView;
 17     /* 要赋值给smarty视图的数据*/
 18     protected $smartyData = [];
 19     /* 资源文件*/
 20     protected $_resLink = ['js'=>[], 'css'=>[]];
 21 
 22     /**
 23      * 使用母版页输出一个视图
 24      * @return [type] [description]
 25      */
 26     protected function displayView($viewName = null, $masterPage = null) {
 27         //为空则选用默认母版
 28         if ($masterPage == null) $masterPage = $this->masterPage;
 29         //获取视图的输出内容
 30         $viewContent = $this->_fetchView($this->smartyData, $viewName, $masterPage);
 31 
 32         $output = '';
 33         
 34         //添加css Link
 35         foreach ($this->_resLink['css'] as $v) {
 36             $output .= res_link($v);
 37         }
 38 
 39         //内容部分
 40         $output .= $viewContent;
 41         //尾部添加js 链接
 42         foreach ($this->_resLink['js'] as $v) {
 43             $output .= res_link($v);
 44         }
 45         //发送最终输出结果以及服务器的 HTTP 头到浏览器
 46         
 47         $this->output->_display($output);
 48         return $output;
 49     }
 50 
 51     private function _fetchView($smartyData, &$viewName, &$masterPage) {
 52         if ($viewName == null) $viewName = $this->smartyView;
 53 
 54         if (empty($this->smarty)) {
 55             require_once SMARTY_DIR.'Smarty.class.php';
 56             $this->smarty = new Smarty();
 57             $this->smarty->setCompileDir(APPPATH . 'cache/');
 58             $this->smarty->setCacheDir(APPPATH . 'cache/');
 59         }
 60 
 61         //设置视图真实路径
 62         $this->_getViewDir(true, $viewName, $masterPage, $templateDir);
 63 
 64         foreach ($smartyData as $k => $v) {
 65             $this->smarty->assign($k, $v);
 66         }
 67 
 68         if (empty($masterPage)) {
 69             return $this->smarty->fetch($viewName);
 70         } else {
 71             $this->smarty->assign('VIEW_MAIN', $viewName);
 72             return $this->smarty->fetch($masterPage);
 73         }
 74     }
 75 
 76     /**
 77      * 资源路径
 78      * @param [type] $filePath [description]
 79      */
 80     protected function addResLink($filePath) {
 81         list($filePath, $query) = explode('?', $filePath . '?');
 82         $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
 83         foreach ($this->_resLink as $v) {
 84             if (false === array_search($filePath, $this->_resLink[$extension])) {
 85                 $this->_resLink[$extension][] = $query == null ? $filePath : $filePath .'?'. $query;
 86             }
 87         }
 88 
 89         return $this;
 90     }
 91 
 92     private function _getViewDir($setTemplateDir, &$viewName, &$masterPage = null, &$templateDir) {
 93         if ('/' === $viewName[0]) $viewName = substr($viewName, 1);
 94 
 95         //是否使用模板,有,则路由到 /views/master_page/*****.tpl下去
 96         if ($masterPage) {
 97             $masterPage = '/' === $masterPage[0] ? substr($masterPage, 1) : ('master_page' .'/'. $masterPage);
 98         }
 99 
100         //是否设置模板目录
101         if ($setTemplateDir) {
102             $templateDir = VIEWPATH;
103             $this->smarty->setTemplateDir($templateDir);
104         }
105     }
106 
107     /**
108      * 压缩js、css资源文件(优化)
109      * @return [type] [description]
110      */
111     private function compressResHandle() {
112         $this->load->library('ResMinifier');
113         //压缩指定文件夹下的资源文件
114         $this->resminifier->compressRes();
115     }
116 }

点击打开

ResMinifier.php

  1 php 
  2 defined('BASEPATH') OR exit('No direct script access allowed');
  3 /**
  4  * 资源压缩类
  5  */
  6 class ResMinifier {
  7     /** 需要压缩的资源目录*/
  8     public $compressResDir = ['css', 'js'];
  9     /** 忽略压缩的路径,例如此处是js/icon开头的路径忽略压缩*/
 10     public $compressResIngorePrefix = ['js/icon'];
 11     /** 资源根目录*/
 12     public $resRootDir;
 13     /** 资源版本文件路径*/
 14     private $resStatePath;
 15 
 16     public function __construct() {
 17         $this->resRootDir = WEBROOT . 'www/';
 18         $this->resStatePath = WEBROOT . 'www/resState.php';
 19     }
 20 
 21     public function compressRes() {
 22         //获取存放版本的资源文件
 23         $resState = $this->getResState();
 24         $count = 0;
 25 
 26         //开始遍历需要压缩的资源目录
 27         foreach ($this->compressResDir as $resDir) {
 28             foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->resRootDir . $resDir , FilesystemIterator::SKIP_DOTS)) as $file) {
 29                 //获取该资源文件的绝对路径
 30                 $filePath = str_replace('\\', '/', $file->getRealPath());
 31 
 32                 //获取文件相对路径
 33                 $object = substr($filePath, strlen($this->resRootDir));
 34 
 35                 //计算文件的版本号
 36                 $state = $this->_getResStateVersion($filePath);
 37 
 38                 //获取文件的几个参数值
 39                 if (true !== $this->getObjectInfo($object, $minObject, $needCompress, $state, $extension)) {
 40                     continue;
 41                 }
 42 
 43                 //压缩文件的绝对路径
 44                 $minFilePath = str_replace('\\', '/', $this->resRootDir. $minObject);
 45 
 46                 //************此处p判断是最重要部分之一*****************//
 47                 //判断文件是否存在且已经改动过
 48                 if (isset($resState[$object]) && $resState[$object] == $state && isset($resState[$minObject]) && file_exists($minFilePath)) {
 49                     continue;
 50                 }
 51 
 52                 //确保/www/min/目录可写
 53                 $this->_ensureWritableDir(dirname($minFilePath));
 54 
 55                 if ($needCompress) {
 56                     $this->compressResFileAndSave($filePath, $minFilePath);
 57                 } else {
 58                     copy($filePath, $minFilePath);
 59                 }
 60 
 61 
 62                 $resState[$object] = $state;
 63                 $resState[$minObject] = '';
 64                 $count++;
 65 
 66                 if ($count == 50) {
 67                     $this->_saveResState($resState);
 68                     $count = 0;
 69                 }
 70 
 71             }
 72         }
 73         if($count) $this->_saveResState($resState);
 74     }
 75 
 76     /**
 77      * 获取资源文件相关信息
 78      * @param  [type] $object       资源文件路径 (www/css/home/index.css)
 79      * @param  [type] $minObject    压缩资源文件路径 (www/min/css/home/index.ae123a.css)
 80      * @param  [type] $needCompress 是否需要压缩
 81      * @param  [type] $state        文件版本号
 82      * @param  [type] $extension    文件名后缀
 83      * @return [type]               [description]
 84      */
 85     public function getObjectInfo($object, &$minObject, &$needCompress, &$state, &$extension) {
 86         //获取资源绝对路径
 87         $filePath = $this->resRootDir . $object;
 88         //判断资源是否存在
 89         if (!file_exists($filePath)) return "资源文件不存在{$filePath}";
 90         //版本号
 91         $state = $this-> _getResStateVersion($filePath);
 92         //文件名后缀
 93         $extension = pathinfo($filePath, PATHINFO_EXTENSION);
 94         //是否要压缩
 95         $needCompress = true;
 96 
 97         //判断资源文件是否是以 .min.css或者.min.js结尾的
 98         //此类结尾一般都是已压缩过,例如jquery.min.js,就不必再压缩了
 99         if (str_end_with($object, '.min.'.$extension, true)) {
100             //压缩后的资源存放路径,放在 /www/min/ 目录下
101             $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension) - 4) . $state .'.'. $extension;
102             $needCompress = false;
103         } else if (in_array($extension, $this->compressResDir)) {
104             //此处是需要压缩的文件目录
105             $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension)) . $state . '.' . $extension;
106             //看看是否是忽略的路径前缀
107             foreach ($this->compressResIngorePrefix as $v) {
108                 if (str_start_with($object, $v, true)) {
109                     $needCompress = false;
110                 }
111             }
112         } else {
113             $minObject = 'min/'.$object;
114             $needCompress = false;
115         }
116         return true;
117     }
118 
119 
120     /**
121      * 获取存放资源版本的文件
122      * 它是放在一个数组里
123      * $resState = array(
124      *         '文件路径' => '对应的版本号',
125      *         '文件路径' => '对应的版本号',
126      *         '文件路径' => '对应的版本号',
127      *     );
128      * @return [type] [description]
129      */
130     public function getResState() {
131         if (file_exists($this->resStatePath)) {
132             require $this->resStatePath;
133             return $resState;
134         }
135         return [];
136     }
137 
138     /**
139      * 计算文件的版本号,这个是根据计算文件MD5散列值得到版本号
140      * 只要文件内容改变了,所计算得到的散列值就会不一样
141      * 用于判断资源文件是否有改动过
142      * @param  [type] $filePath [description]
143      * @return [type]           [description]
144      */
145     public function _getResStateVersion($filePath) {
146         return base_convert(crc32(md5_file($filePath)), 10, 36);
147     }
148 
149     /**
150      * 确保目录可写
151      * @param  [type] $dir [description]
152      * @return [type]      [description]
153      */
154     private function _ensureWritableDir($dir) {
155         if (!file_exists($dir)) {
156             @mkdir($dir, 0777, true);
157             @chmod($dir, 0777);
158         } else if (!is_writable($dir)) {
159             @chmod($dir, 0777);
160             if (!is_writable($dir)) {
161                 show_error('目录'.$dir.'不可写');
162             }
163         }
164     }
165 
166     /**
167      * 将压缩后的资源文件写入到/www/min/下去
168      * @param  [type] $filePath    [description]
169      * @param  [type] $minFilePath [description]
170      * @return [type]              [description]
171      */
172     private function compressResFileAndSave($filePath, $minFilePath) {
173         if (!file_put_contents($minFilePath, $this->compressResFile($filePath))) {
174 
175             //$CI->exceptions->show_exception("写入文件{$minFilePath}失败");
176             show_error("写入文件{$minFilePath}失败", -1);
177         }
178     }
179 
180     /**
181      * 压缩资源文件
182      * @param  [type] $filePath [description]
183      * @return [type]           [description]
184      */
185     private function compressResFile($filePath) {
186         $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
187         if ($extension === 'js') {
188             require_once 'JShrink/Minifier.php';
189             return \JShrink\Minifier::minify(file_get_contents($filePath));
190         } else if ($extension ==='css') {
191             $content = file_get_contents($filePath);
192             $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content);
193             $content = str_replace(["\r\n", "\r", "\n"], '', $content);
194             $content = preg_replace('/([{}),;:>])\s+/', '$1', $content);
195             $content = preg_replace('/\s+([{}),;:>])/', '$1', $content);
196             $content = str_replace(';}', '}', $content);
197             return $content;
198         } else {
199             //$CI->exceptions->show_exception("不支持压缩{extension}文件[$filePath]");
200             show_error("不支持压缩{extension}文件[$filePath]", -1);
201 
202         }
203     }
204 
205     private function _saveResState($resState) {
206         ksort($resState);
207         $content = ";
208         foreach ($resState as $k => $v) {
209             $content .= "\t '$k' => '$v',\n";
210         }
211         $content .= ");\n\n";
212         file_put_contents($this->resStatePath, $content); 
213     }
214 
215 }

点击打开

Common.php

  1 php 
  2     /**
  3      * 输出 HttpHead 中的资源连接。 css/js 自动判断真实路径
  4      * @param  string  文件路径
  5      * @return string      
  6      */
  7     function res_link($file) {
  8         $file = res_path($file, $extension);
  9 
 10         if ($extension === 'css') {
 11            return '$file . '"/>';
 12         } else if ($extension === 'js') {
 13             return '';
 14         } else {
 15             return false;
 16         }
 17     }
 18 
 19     /**
 20      * 智能路由资源真实路径
 21      * @param  string      路径
 22      * @param  string      扩展名
 23      * @return string       真实路径
 24      */
 25     function res_path($file, &$extension) {
 26         //检查是否存在查询字符串
 27         list($file, $query) = explode('?', $file . '?');
 28         //取得扩展名
 29         $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
 30         //
 31         $file = str_replace('\\', '/', $file);
 32         //取得当前控制器名
 33         global $class;
 34         if ($class == null) exit('can not get class name');
 35         $className = strtolower($class);
 36 
 37         //此处的规则是这样:
 38         //例如,如果不加 / ,Home控制器对应的格式是: index.css,那么 此处的路径会变成css/home/index.css
 39         //假如有 / ,控制器的格式可以是 /main.css,那么此处的路径会变成 css/main.css(公用的css类)
 40         if ('/' !== $file[0]) {
 41             //index.css => css/home/index.css
 42             $object = $extension .'/'. $className .'/' . $file;
 43         } else {
 44             // /css/main.css 或者 /main.css => css/main.css
 45             $object = substr($file, 1);
 46 
 47             //若object是 main.css ,则自动加上 扩展名目录 => css/main.css
 48             if (0 !== strncasecmp($extension, $object, strlen($extension))) {
 49                 $object = $extension . '/' . $object;
 50             }
 51         }
 52         //资源真实路径
 53         $filepath = WEBROOT.'www/'.$object;
 54         
 55         //替换压缩版本,这部分逻辑与文件压缩逻辑对应
 56         if (in_array($extension, array('css', 'js'))) {
 57             if(!str_start_with($object, 'min/') && file_exists(APPPATH.'libraries/ResMinifier.php')) {
 58                 require_once APPPATH.'libraries/ResMinifier.php';
 59                 $resminifier = new ResMinifier();
 60                 //获取存放资源版本的文件的数组变量
 61                 $resState = $resminifier->getResState();
 62                 //计算得到当前文件版本号
 63                 $state = $resminifier->_getResStateVersion($filepath);
 64                 //判断该版本号是否存在
 65                 if (isset($resState[$object])) {
 66                     //判断是否是.min.css或.min.js结尾
 67                     if (str_end_with($object, '.min.'.$extension)) {
 68                         //将版本号拼接上去,然后得到min的文件路径
 69                         $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension) - 4) . $state . '.' . $extension;
 70                     } else {
 71                         //将版本号拼接上去,然后得到min的文件路径
 72                         $minObject = 'min/'.substr($object, 0, strlen($object) - strlen($extension)) . $state . '.' . $extension;
 73                     }
 74                     //判断min的路径是否存在在$resState里面
 75                      if (isset($resState[$minObject])) {
 76                         $object = $minObject;
 77                         $query = '';
 78                      }
 79                 } 
 80 
 81             }
 82             
 83             $file = RES_BASE_URL . $object;
 84         }
 85 
 86         return ($query == null) ? $file : ($file .'?'. $query);
 87 
 88     }
 89 
 90     /**
 91      * 判断 subject 是否以 search开头, 参数指定是否忽略大小写
 92      * @param  [type]  $subject     [description]
 93      * @param  [type]  $search      [description]
 94      * @param  boolean $ignore_case [description]
 95      * @return [type]               [description]
 96      */
 97     function str_start_with($subject, $search, $ignore_case = false) {
 98         $len2 = strlen($search);
 99         if (0 === $len2) return true;
100         $len1 = strlen($subject);
101         if ($len1 < $len2) return false;
102         if ($ignore_case) {
103             return 0 === strncmp($subject, $search, $len2);
104         } else {
105             return 0 === strncasecmp($subject, $search, $len2);
106         }
107     }
108 
109     /**
110      * 判断 subject 是否以 search结尾, 参数指定是否忽略大小写
111      * @param  [type]  $subject     [description]
112      * @param  [type]  $search      [description]
113      * @param  boolean $ignore_case [description]
114      * @return [type]               [description]
115      */
116     function str_end_with($subject, $search, $ignore_case = false) {
117         $len2 = strlen($search);
118         if (0 === $len2) return true;
119         $len1 = strlen($subject);
120         if ($len2 > $len1) return false;
121         if ($ignore_case) {
122             return 0 === strcmp(substr($subject, $len1 - $len2), $search);
123         } else {
124             return 0 === strcasecmp(substr($subject, $len1 - $len2), $search);
125         }
126     }

点击打开

$ resState.php(内部代码是自动生成的)

 1 php
 2 
 3 $resState = array(
 4      'css/home/index.css' => 'gwy933',
 5      'js/echarts-all.min.js' => 'wqrf1c',
 6      'js/home/index.js' => 's2z6f5',
 7      'js/icon.js' => 'pgcyih',
 8      'js/icon_home.js' => 'zhl9iu',
 9      'js/ion.rangeSlider.min.js' => 'akq381',
10      'js/jquery-ui-autocomplete.js' => '8nzacv',
11      'js/jquery-ui.min.js' => 'i6tw8z',
12      'js/jquery.all.min.js' => 'd2w76v',
13      'js/jquery.city.js' => 'toxdrf',
14      'js/jquery.easydropdown.min.js' => '2ni3i0',
15      'js/jquery.matrix.js' => '3vrqkk',
16      'js/jquery.mobile.all.min.js' => 'ernu7r',
17      'js/jquery.qrcode.min.js' => 'yuhnsj',
18      'js/jquery.tinyscrollbar.min.js' => 'oakk3c',
19      'js/mobiscroll.custom.min.js' => 'kn8h2e',
20      'js/store.min.js' => 'n50jwr',
21      'js/swiper.animate1.0.2.min.js' => 'mm27zc',
22      'js/swiper.min.js' => 'jicwhh',
23      'min/css/home/index.6a4e83eb.css' => '',
24      'min/css/home/index.gwy933.css' => '',
25      'min/css/home/index.puzbnf.css' => '',
26      'min/css/home/index.thv8x7.css' => '',
27      'min/js/echarts-all.76025ee0.js' => '',
28      'min/js/echarts-all.wqrf1c.js' => '',
29      'min/js/home/index.65363d41.js' => '',
30      'min/js/home/index.s2z6f5.js' => '',
31      'min/js/icon.5bbd4db9.js' => '',
32      'min/js/icon.pgcyih.js' => '',
33      'min/js/icon_home.7fe74076.js' => '',
34      'min/js/icon_home.zhl9iu.js' => '',
35      'min/js/ion.rangeSlider.261d8ed1.js' => '',
36      'min/js/ion.rangeSlider.akq381.js' => '',
37      'min/js/jquery-ui-autocomplete.1f3bb62f.js' => '',
38      'min/js/jquery-ui-autocomplete.8nzacv.js' => '',
39      'min/js/jquery-ui.418e9683.js' => '',
40      'min/js/jquery-ui.i6tw8z.js' => '',
41      'min/js/jquery.all.2f248267.js' => '',
42      'min/js/jquery.all.d2w76v.js' => '',
43      'min/js/jquery.city.6b036feb.js' => '',
44      'min/js/jquery.city.toxdrf.js' => '',
45      'min/js/jquery.easydropdown.2ni3i0.js' => '',
46      'min/js/jquery.easydropdown.98fa138.js' => '',
47      'min/js/jquery.matrix.3vrqkk.js' => '',
48      'min/js/jquery.matrix.dfe2a44.js' => '',
49      'min/js/jquery.mobile.all.3539ebb7.js' => '',
50      'min/js/jquery.mobile.all.ernu7r.js' => '',
51      'min/js/jquery.qrcode.7d9738b3.js' => '',
52      'min/js/jquery.qrcode.yuhnsj.js' => '',
53      'min/js/jquery.tinyscrollbar.578e4cb8.js' => '',
54      'min/js/jquery.tinyscrollbar.oakk3c.js' => '',
55      'min/js/mobiscroll.custom.4a684f66.js' => '',
56      'min/js/mobiscroll.custom.kn8h2e.js' => '',
57      'min/js/store.536545cb.js' => '',
58      'min/js/store.n50jwr.js' => '',
59      'min/js/swiper.4650ad75.js' => '',
60      'min/js/swiper.animate1.0.2.517f82e8.js' => '',
61      'min/js/swiper.animate1.0.2.mm27zc.js' => '',
62      'min/js/swiper.jicwhh.js' => '',
63 );

点击打开

此外,为PHP类JShrink附加一个链接,供所有人下载

如果您仍然觉得还不够好,我将直接打包此实验项目,以供大家下载以学习和理解:

四、结论

最后,让我分享我们在线项目的具体实施计划:

我们的项目分为在线环境,开发环境和测试环境。在开发和测试环境中,每次访问时我们都调用压缩文件接口,然后我们需要判断生成的资源文件的大小。如果压缩文件太小,则需要将资源文件的代码合并到其他资源文件中,以减少不必要的HTTP请求(因为文件太小,资源的下载时间比HTTP的消耗少得多)请求响应时间);另一种是图片的处理,所有图片都必须经过压缩才能传递(例如,在本网站上可以压缩图片),在PC端,如果它是一个小图标,请使用图片合并方法进行优化。有关详细信息,请参阅我的博客文章:wap端的图像处理使用base64编码来处理图像。有关详细信息,请参阅我的博客文章:,输出页面时网站优化技术,redis将用于缓存页面(为什么使用内存来缓存而不是使用页面缓存,我稍后会与您分享)。如果是在线环境,则每次发布版本时都会调用资源文件压缩接口,并且在线静态资源(css,js,图片)存储在阿里云的OSS中,与我们的应用程序服务器相同。分为。这是我们在线项目优化解决方案的一部分。当然,还有更多的优化技术。我将在未来进行总结和分享,以便每个人都可以一起学习和交流。

此博客文章在此处共享,谢谢阅读此博客文章的朋友。

如果此博客文章中有一些难以理解的内容,请留言并进行交流。如果有任何错误的解释,请指出。

如果您认为您可以在此博客中学习新知识,请给我一个头等知识。如果文章中的解释有误,请指出。

彼此学习,共同进步!

转载请注明:http://www.hetuiseo.com/p/zhongdujishu/406.html

上一篇:独立网站运营需标准化管理提出未来对外贸B2C的规划

下一篇:没有了