壮高校习

这节内容是本人最熟习,结果相反因为如此才想花更加多时光写好,所以等到后来再产生来好了,大家先能够先看看以下多少个站点:

  • Chromium
  • Mozilla Hacks
  • Surfin’ Safari

调整和裁减HTTP央浼之统一图片详解(大型网址优化本事)

2015/11/26 · HTML5 ·
HTTP

原作出处: Kelly   

一、相关文化授课

看过雅虎的前端优化35条提议,都明白优化前端是有多么首要。页面包车型大巴加载速度一贯影响到客商的体会。70%的顶点客户响应时间都花在了前端上,在那之中山大学部分光阴都在下载页面上的各个零件:图片,样式表,脚本,Flash等等。

裁减组件数一定能够降低页面提交的HTTP恳求数。那是让页面越来越快的首要。收缩页面组件数的一种格局是简化页面设计。但有未有一种方法能够在创设复杂的页面同期加快响应时间呢?嗯,确实有鱼和熊掌兼得的格局。

这里大家就拿雅虎的率先条提议:尽量降低HTTP央求数里的压缩图片央浼数量
进行批注。

大家都领悟,三个网址的多个页面或者有非常的多小Logo,譬喻有个别按键、箭头等等。当加载html文书档案时,只要碰着有图表的,都会活动构建起HTTP央求下载,然后将图片下载到页面上,那几个小图片恐怕也正是十几K大依旧1K都不到,假诺我们的二个页面有九18个小Logo,大家在加载页面时,就要发送九十八个HTTP诉求,假如你的网站访谈量不小并发量也相当高,假如上百万访谈量,那发起的伸手正是纯属等第了,服务器是有必然的下压力的,并且二个客商的叁个页面要提倡那么多央求,是很耗费时间的。

为此,我们优化的方案就是:将这么些十几K、几K的小Logo合併在一张图片里,然后用CSS的background-imagebackground-position特性来恒定要展示的局地。

二、代码实现

1、思路:

将三个文件夹里的Logo,自动生成在一张图片里面,同一时候自动生成对应的css文件,大家只要在HTML里的竹签中添加相应的属性值就能够突显图片了。

2、完结进度:

XHTML

<?php //自个儿定义二个根目录 define(‘ROOT’,
$_SERVER[‘DOCUMENT_ROOT’].’iconwww’); //那个是图表的目录
define(‘RES_BASE_URL’, ”); /** *
生成背景图的函数 */ function generateIcon() { //网址根目录 $webRoot =
rtrim(ROOT, ‘/’); //背景图目录 $root = “$webRoot/img/bg”; //Php-SPL库中
的 目录文件遍历器 $iterator = new DirectoryIterator($root);
//开首遍历该背景图目录下的目录,大家是把想生成背景图的目录,放在bg目录中以一一模块的目录分类存放foreach ($iterator as $file) { //遇到目录遍历 if (!$file->isDot() &&
$file->isDir()) { //获得文件名 $fileName = $file->getFilename();
generateIconCallback(“$root/$fileName”, “$webRoot/img/$fileName”,
“$webRoot/css/$fileName.css”); } } } /** *
客商生成合併的背景图和css文件的函数 * @param string $dir
生成背景图的Logo所在的目录路线 * @param string $bgSavePath
背景图所保存的路线 * @param string $cssSave帕特h css保存的路线 */
function generateIconCallback($dir, $bgSavePath, $cssSavePath) {
$shortDir = str_replace(‘\\’, ‘/’, substr($dir, strlen(ROOT-1)));
//重回文件路线音讯 $pathInfo = pathinfo($bgSavePath.’.png’); $bgSaveDir
= $pathInfo[‘dirname’]; //确认保障目录可写
ensure_writable_dir($bgSaveDir); //背景图名字 $bgName =
$pathInfo[‘filename’];
//调用generateIconCallback_GetFileMap()函数生成每三个Logo所必要的数据结构
$fileMap = array(‘a’ => generateIconCallback_GetFileMap($dir));
$iterator = new DirectoryIterator($dir); foreach ($iterator as $file) {
if ($file->isDot()) continue; if ($file->isDir()) {
//二级目录也要管理 $fileMap[‘b-‘.$file->getFilename()] =
generateIconCallback_GetFileMap($file->getRealPath()); } }
ksort($fileMap);
//剖析一边fileMap,计算整个背景图的尺寸和每三个Logo的offset
//起始化偏移量和背景图 $offsetX = $offsetY = $bgWidth = 0;
//设定种种小Logo之间的偏离 $spaceX =$spaceY = 5; //图片最小幅面
$maxWidth = 800; $fileMd5List =array();
//这里须要打字与印刷下$fileMap就清楚它的数据结构了 foreach ($fileMap as $k1
=> $innerMap) { foreach ($innerMap as $k2 => $itemList) {
//行高姐X轴偏移量起首化 $offsetX = $lineHeight = 0; foreach ($itemList
as $k3 => $item) {
//变量分别是:Logo的增加率,高度,类型,文件名,路径,MD5加密字符串
list($imageWidth, $imageHeight, $imageType, $fileName, $filePathname,
$fileMd5) = $item; $fileMd5List []= $fileMd5; //借使图片的上涨的幅度+偏移量
> 最大开间(800) 那就换行 if ($offsetX !== 0 && $imageWidth +
$offsetX > $maxWidth) { $offsetY += $spaceY + $lineHeight; $offsetX =
$lineHeight = 0; } //假使图片中度 > 当前行高
那就讲图片中度付给行高大家那的 if ($imageHeight > $lineHeight)
$lineHeight = $imageHeight; $fileMap[$k1][$k2][$k3] =
array($imageWidth, $imageHeight, $offsetX, $offsetY, $imageType,
$fileName, $filePathname); //X轴偏移量的乘除 $offsetX += $imageWidth +
$spaceX; if ($offsetX > $bgWidth) $bgWidth = $offsetX; }
//Y轴偏移量的一个钱打二14个结 $offsetY += $lineHeight + $spaceY; } }
//把右下两边多加了的空域距离给干掉 $bgWidth -= $spaceX; $bgHeight =
$offsetY – $spaceY; $fileMd5List = implode(“\n”, $fileMd5List);
//生成背景图和 css文件 //能源路线 $resBaseUrl = RES_BASE_URL; $suffix
= base_convert(abs(crc32($fileMd5List)), 10, 36); $writeHandle =
fopen($cssSavePath, ‘w’); fwrite($writeHandle, “/** bg in dir:
$shortDir/
*/\n[icon-$bgName]{background:url({$resBaseUrl}/$bgName.png?$suffix)
no-repeat;display:inline-block;}”);
//做图片,这一个函数具体能够查看PHP手册 $destResource =
imagecreatetruecolor($bgWidth, $bgHeight);
image阿尔法blending($destResource, false); imagesave阿尔法($destResource,
false); $color = imagecolorallocate阿尔法($destResource, 255, 255, 255,
127); imagefill($destResource, 0, 0, $color);
//对每一张小图片打开始拍录卖,生成在大背景图里,并生成css文件 foreach
($fileMap as $innerMap) { foreach ($innerMap as $itemList) { foreach
($itemList as $item) { list($imageWidth, $imageHeight, $offsetX,
$offsetY, $imageType, $fileName, $filePathname) = $item; if ($imageType
=== IMAGETYPE_PNG) { $srcResource = imagecreatefrompng($filePathname);
} else if ($imageType === IMAGETYPE_JPEG) { $srcResource =
imagecreatefromjpeg($filePathname); } imagecopy($destResource,
$srcResource, $offsetX, $offsetY, 0, 0, $imageWidth, $imageHeight);
imagedestroy($srcResource); //写入css $posX = $offsetX === 0 ? 0 :
“-{$offsetX}px”; $posY = $offsetY === 0 ? 0 : “-{$offsetY}px”;
fwrite($writeHandle,
“\n[icon-$bgName=\”$fileName\”]{width:{$imageWidth}px;height:{$imageHeight}px;background-position:$posX
$posY;}”); } } } //压缩等级 7 imagepng($destResource, “$bgSavePath.png”,
7); imagedestroy($destResource); fclose($writeHandle); $shortCssSavePath
= substr($cssSavePath, strlen(ROOT)); } /** *
将图片的音信管理成我们想要的数据结构 * @param [type] $dir
[description] * @return [type] [description] */ function
generateIconCallback_GetFileMap($dir) { $map = $sort = array();
$iterator = new DirectoryIterator($dir); foreach($iterator as $file) {
if(!$file->isFile()) continue; $filePathname = str_replace(“\\”,
‘/’, $file->getRealPath()); //那一个函数能够查看PHP手册 $imageInfo =
getimagesize($filePathname); $imageWidth = $imageInfo[0]; $imageHeight
= $imageInfo[1]; $imageType = $imageInfo[2];
if(!in_array($imageType, array(IMAGETYPE_JPEG, IMAGETYPE_PNG))) {
$fileShortName = substr($filePathname, strlen(ROOT) – 1); echo
“<p> $fileShortName 图片被忽略:
因为图片类型不是png|jpg.</p>”; continue; }
//那是大家的图纸规格,行高分别有 16 32 64 128 256 99999
foreach(array(16, 32, 64, 128, 256, 99999) as $height) { if($imageHeight
<= $height) { $mapKey = $height; break; } }
if(!isset($map[$mapKey])) $map[$mapKey] = array(); $filePathInfo =
pathinfo($filePathname); $map[$mapKey] []= array($imageWidth,
$imageHeight, $imageType, $filePathInfo[‘filename’], $filePathname,
md5_file($filePathname)); $sort[$mapKey] []= str_pad($imageHeight,
4, ‘0’, STR_PAD_LEFT) . $filePathInfo[‘filename’]; } foreach($map as
$k => $v) array_multisort($map[$k], SORT_ASC, SORT_NUMERIC,
$sort[$k]); ksort($map, SORT_NUMERIC); return $map; } /** *
推断目录是还是不是可写 * @param string $dir 目录路线 */ function
ensure_writable_dir($dir) { if(!file_exists($dir)) { mkdir($dir,
0766, true); @chmod($dir, 0766); @chmod($dir, 0777); } else
if(!is_writable($dir)) { @chmod($dir, 0766); @chmod($dir, 0777);
if(!@is_writable($dir)) { throw new
BusinessLogicException(“目录不可写”, $dir); } } } generateIcon(); ?>
<!DOCTYPE html> <html> <head> <link
rel=”stylesheet” type=”text/css” href=”css/Pink.css”>
<title></title> </head> <body>
<div>大家平昔引进所生成的css文件,并测验一下是或不是成功</div>
<br> <div>这里在span标签 增加属性 icon-Pink
,值为About-40,符合规律展现图片</div> <span
icon-Pink=”About-40″></span> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<?php
    //自己定义一个根目录
    define(‘ROOT’, $_SERVER[‘DOCUMENT_ROOT’].’iconwww’);
    //这个是图片的目录
    define(‘RES_BASE_URL’, ‘http://localhost:8080/iconwww/img’);
 
    /**
     * 生成背景图的函数
     */
    function generateIcon() {
        //网站根目录
        $webRoot = rtrim(ROOT, ‘/’);
        //背景图目录
        $root = "$webRoot/img/bg";
        //Php-SPL库中 的 目录文件遍历器
        $iterator = new DirectoryIterator($root);
        //开始遍历该背景图目录下的目录,我们是把想生成背景图的目录,放在bg目录中以各个模块的目录分类存放
        foreach ($iterator as $file) {
            //遇到目录遍历
            if (!$file->isDot() && $file->isDir()) {
                //取得文件名
                $fileName = $file->getFilename();
                generateIconCallback("$root/$fileName", "$webRoot/img/$fileName", "$webRoot/css/$fileName.css");
            }
        }
    }
 
    /**
     * 用户生成合并的背景图和css文件的函数
     * @param  string $dir         生成背景图的图标所在的目录路径
     * @param  string $bgSavePath  背景图所保存的路径
     * @param  string $cssSavePath css保存的路径
     */
    function generateIconCallback($dir, $bgSavePath, $cssSavePath) {
        $shortDir = str_replace(‘\\’, ‘/’, substr($dir, strlen(ROOT-1)));
        //返回文件路径信息
        $pathInfo = pathinfo($bgSavePath.’.png’);
 
        $bgSaveDir = $pathInfo[‘dirname’];
        //确保目录可写
        ensure_writable_dir($bgSaveDir);
        //背景图名字
        $bgName = $pathInfo[‘filename’];
        //调用generateIconCallback_GetFileMap()函数生成每一个图标所需要的数据结构
        $fileMap = array(‘a’ => generateIconCallback_GetFileMap($dir));
 
        $iterator = new DirectoryIterator($dir);
        foreach ($iterator as $file) {
            if ($file->isDot()) continue;
            if ($file->isDir()) {
                //二级目录也要处理
                $fileMap[‘b-‘.$file->getFilename()] = generateIconCallback_GetFileMap($file->getRealPath());
            }
        }
        ksort($fileMap);
 
        //分析一边fileMap,计算整个背景图的大小和每一个图标的offset
        //初始化偏移量和背景图    
        $offsetX = $offsetY = $bgWidth = 0;
        //设定每个小图标之间的距离
        $spaceX =$spaceY = 5;
        //图片最大宽度
        $maxWidth = 800;
        $fileMd5List =array();
        //这里需要打印下$fileMap就知道它的数据结构了
        foreach ($fileMap as $k1 => $innerMap) {
            foreach ($innerMap as $k2 => $itemList) {
                //行高姐X轴偏移量初始化
                $offsetX = $lineHeight = 0;
                foreach ($itemList as $k3 => $item) {
                    //变量分别是:图标的宽度,高度,类型,文件名,路径,MD5加密字符串
                    list($imageWidth, $imageHeight, $imageType, $fileName, $filePathname, $fileMd5) = $item;
                    $fileMd5List []= $fileMd5;
                    //如果图片的宽度+偏移量 > 最大宽度(800) 那就换行
                    if ($offsetX !== 0 && $imageWidth + $offsetX > $maxWidth) {
                        $offsetY += $spaceY + $lineHeight;
                        $offsetX = $lineHeight = 0;
                    }
                    //如果图片高度 > 当前行高  那就讲图片高度付给行高我们这的
                    if ($imageHeight > $lineHeight) $lineHeight = $imageHeight;
                    $fileMap[$k1][$k2][$k3] = array($imageWidth, $imageHeight, $offsetX, $offsetY, $imageType, $fileName, $filePathname);
                    //X轴偏移量的计算
                    $offsetX += $imageWidth + $spaceX;
                    if ($offsetX > $bgWidth) $bgWidth = $offsetX;
                }
                //Y轴偏移量的计算
                $offsetY +=  $lineHeight + $spaceY;
            }
        }
        //把右下两边多加了的空白距离给干掉
        $bgWidth -= $spaceX;
        $bgHeight = $offsetY – $spaceY;
        $fileMd5List = implode("\n", $fileMd5List);
 
        //生成背景图和 css文件
 
        //资源路径
        $resBaseUrl = RES_BASE_URL;
        $suffix = base_convert(abs(crc32($fileMd5List)), 10, 36);
        $writeHandle = fopen($cssSavePath, ‘w’);
        fwrite($writeHandle, "/** bg in dir: $shortDir/ */\n[icon-$bgName]{background:url({$resBaseUrl}/$bgName.png?$suffix) no-repeat;display:inline-block;}");
 
        //做图片,这些函数具体可以查看PHP手册
        $destResource = imagecreatetruecolor($bgWidth, $bgHeight);
        imagealphablending($destResource, false);
        imagesavealpha($destResource, false);
        $color = imagecolorallocatealpha($destResource, 255, 255, 255, 127);
 
        imagefill($destResource, 0, 0, $color);
 
        //对每一张小图片进行处理,生成在大背景图里,并生成css文件
        foreach ($fileMap as $innerMap) {
            foreach ($innerMap as $itemList) {
                foreach ($itemList as $item) {
                     list($imageWidth, $imageHeight, $offsetX, $offsetY, $imageType, $fileName, $filePathname) = $item;
                     if ($imageType === IMAGETYPE_PNG) {
                        $srcResource = imagecreatefrompng($filePathname);
                     } else if ($imageType === IMAGETYPE_JPEG) {
                        $srcResource = imagecreatefromjpeg($filePathname);
                     }
                     imagecopy($destResource, $srcResource, $offsetX, $offsetY, 0, 0, $imageWidth, $imageHeight);
                     imagedestroy($srcResource);
 
                     //写入css
                     $posX = $offsetX === 0 ? 0 : "-{$offsetX}px";
                     $posY = $offsetY === 0 ? 0 : "-{$offsetY}px";
                     fwrite($writeHandle, "\n[icon-$bgName=\"$fileName\"]{width:{$imageWidth}px;height:{$imageHeight}px;background-position:$posX $posY;}");
                 }
            }
        }
 
        //压缩级别 7
        imagepng($destResource, "$bgSavePath.png", 7);
        imagedestroy($destResource);
        fclose($writeHandle);
 
        $shortCssSavePath = substr($cssSavePath, strlen(ROOT));
    }
 
    /**
     * 将图片的信息处理成我们想要的数据结构
     * @param  [type] $dir [description]
     * @return [type]      [description]
     */
    function generateIconCallback_GetFileMap($dir) {
        $map = $sort = array();
        $iterator = new DirectoryIterator($dir);
        foreach($iterator as $file) {
            if(!$file->isFile()) continue;
            $filePathname = str_replace("\\", ‘/’, $file->getRealPath());
            //这些函数可以查看PHP手册
            $imageInfo = getimagesize($filePathname);
            $imageWidth = $imageInfo[0];
            $imageHeight = $imageInfo[1];
            $imageType = $imageInfo[2];
 
            if(!in_array($imageType, array(IMAGETYPE_JPEG, IMAGETYPE_PNG))) {
                $fileShortName = substr($filePathname, strlen(ROOT) – 1);
                echo "<p> $fileShortName 图片被忽略: 因为图片类型不是png|jpg.</p>";
                continue;
            }
 
            //这是我们的图片规格,行高分别有 16 32 64 128 256 99999
            foreach(array(16, 32, 64, 128, 256, 99999) as $height) {
                if($imageHeight <= $height) {
                    $mapKey = $height;
                    break;
                }
            }
            if(!isset($map[$mapKey])) $map[$mapKey] = array();
            $filePathInfo = pathinfo($filePathname);
            $map[$mapKey] []= array($imageWidth, $imageHeight, $imageType, $filePathInfo[‘filename’], $filePathname, md5_file($filePathname));
            $sort[$mapKey] []= str_pad($imageHeight, 4, ‘0’, STR_PAD_LEFT) . $filePathInfo[‘filename’];
        }
        foreach($map as $k => $v) array_multisort($map[$k], SORT_ASC, SORT_NUMERIC, $sort[$k]);
        ksort($map, SORT_NUMERIC);
        return $map;
    }
 
    /**
     * 判断目录是否可写
     * @param  string $dir 目录路径
     */
    function ensure_writable_dir($dir) {
        if(!file_exists($dir)) {
            mkdir($dir, 0766, true);
            @chmod($dir, 0766);
            @chmod($dir, 0777);
        }
        else if(!is_writable($dir)) {
            @chmod($dir, 0766);
            @chmod($dir, 0777);
            if(!@is_writable($dir)) {
                throw new BusinessLogicException("目录不可写", $dir);
            }
        }
    }
 
    generateIcon();
?>
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="css/Pink.css">
    <title></title>
 
</head>
<body>
<div>我们直接引入所生成的css文件,并测试一下是否成功</div>
<br>
<div>这里在span标签 添加属性 icon-Pink ,值为About-40,正常显示图片</div>
<span icon-Pink="About-40"></span>
</body>
</html>

调用以上代码,我们的浏览器是这么展现的:

澳门微尼斯人手机版 1

然后css目录生成了Pink.css文件:

澳门微尼斯人手机版 2

img目录下生成了Pink.png文件:

澳门微尼斯人手机版 3

探问生成的背景图是长啥样子:

澳门微尼斯人手机版 4

 

接下去大家再看一下所生成的图片大小与Pink文件夹里全部小图片总和的大小,对它们做个比较:

澳门微尼斯人手机版 5

 

澳门微尼斯人手机版 6

从上海教室能够看看,我们转换的图纸的轻重鲜明低于文件夹全体图片的高低,所以在将玖16个小图标下载下来的进度会分明低于 将背景图下载下来和将CSS下载下来的速度。

当访谈量大时,恐怕小图片的量大时,会起到很分明的优化功用!!!

代码中的每三个点都大致有注释,比异常的低价大家去明白,只要大家用心去看,确定能将这一网站优化手艺用到和睦的品种中。

此番博文就写到那!!!

若是此博文中有哪个地方讲得令人为难明白,招待留言调换,若有讲解错的地方应接建议。

举个例子您以为您能在此博法学到了新知识,请为自身顶贰个,如文章中有表明错的地方,招待提议。

  相互学习,共同提高!

2 赞 3 收藏
评论

澳门微尼斯人手机版 7

静态财富文件自动削减并替换到压缩版本(大型网址优化技巧)

2015/11/26 · HTML5 ·
静态财富

原稿出处: Kelly   

那一次,笔者总计和分享一项大型网址优化技巧,那正是在项目中机动削减静态财富文件(css、js),并让网站自行加载压缩后的财富文件。当然,那项技能在雅虎35条前端优化提出里也许有记载,但它那只是给出三个理论的方案而已,何况选择的是表面压缩工具去减弱,而在自个儿的品种中,是一向通过友好的次第自动化去收缩全部css、js文件,然后让页面一直加载所减少后的财富,接下去直接进去正题。

这一次试验应用的是PHP脚本语言,版本是PHP5.6,是在LINUX下搭建的景况(网络搭建无论是搭建LAMP照旧LNMP的教程都五花八门一塌糊涂,下一次小编会总计和分享什么在LINUX下搭建服务器蒙受的博文,并且搭建的条件必需一回性搭建成功的)。所选取的框架是CI框架,所使用的模版是斯马特y模板引擎。当然了,这么些只是本人所利用的景况而已,假如你是PHP开荒者,倘令你要测验下此番实验,那么,小编建议你的PHP版本采纳5.4以上,至于框架用什么样都以足以的。而一旦你不是PHP开荒者(你是JSP恐怕是ASP开辟者恐怕是别的开垦者),那么您知道好这一思路后,完全可以在温馨熟谙的言语里打开尝试测量试验。

一、原理图

率先笔者画一张思路图,便于大家先清楚。

首先是能源裁减原理图:

澳门微尼斯人手机版 8

随正是资源文件替换的原理图:

澳门微尼斯人手机版 9

一旦我们认真精晓并且看懂这两张原理图的话,基本上也就调控了本身所享用的笔触。假诺还是不可能领略的话,接下去笔者会结合代码,对以上原理图的每一步进行详尽讲授。

二、思路详细分析

1.先是是调用该滑坡的不二等秘书籍,你能够把该方法放在网址所要加载的公共类的地点,譬如每一回访谈网址都会调用该滑坡方法进行压缩。当然,这一个只是在付出条件才会每一次都调用,要是是线上的碰到,在你的网址发二遍新本子的时候,调用叁次用来生成压缩版的静态能源就能够了。

class MY_Controller extends CI_Controller { public function
__construct() { parent::__construct(); //压缩jscss能源文件
$this->compressResHandle(); } /** * 压缩js、css能源文件(优化) *
@return [type] [description] */ private function
compressResHandle() { $this->load->library(‘ResMinifier’);
//压缩钦命文件夹下的能源文件 $this->resminifier->compressRes(); }
}

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

2.接着就调用了 ResMinifier类里的 compressRes方法。在那边笔者先附上
ResMinifier那几个类的代码,然后方便一步步开展深入分析批注

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
/** * 能源压缩类 */ class ResMinifier { /** 必要减弱的财富目录*/
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’; } public function
compressRes() { //获取存放版本的财富文件 $resState =
$this->getResState(); $count = 0; //开头遍历须要减小的能源目录
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); //获取文件的多少个参数值 if
(true !== $this->getObjectInfo($object, $minObject, $needCompress,
$state, $extension)) { continue; } //压缩文件的相对路线 $minFilePath =
str_replace(‘\\’, ‘/’, $this->resRootDir. $minObject);
//************此处p判别是最要紧部分之一*****************//
//判定文件是不是存在且已经济体退换过 if (isset($resState[$object]) &&
$resState[$object] == $state && isset($resState[$minObject]) &&
file_exists($minFilePath)) { continue; } //确定保障/www/min/目录可写
$this->_ensureWritableDir(dirname($minFilePath)); if ($needCompress)
{ $this->compressResFileAndSave($filePath, $minFilePath); } else {
copy($filePath, $minFilePath); } $resState[$object] = $state;
$resState[$minObject] = ”; $count++; if ($count == 50) {
$this->_saveResState($resState); $count = 0; } } } if($count)
$this->_saveResState($resState); } public function
getObjectInfo($object, &$minObject, &$needCompress, &$state,
&$extension) { //获取能源相对路线 $filePath = $this->resRootDir .
$object; //剖断能源是还是不是存在 if (!file_exists($filePath)) return
“财富文件空中楼阁{$filePath}”; //版本号 $state = $this->
_getResStateVersion($filePath); //文件名后缀 $extension =
pathinfo($file帕特h, 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; } /** * 获取存放财富版本的公文 * 它是坐落二个数组里 *
$resState = array( * ‘文件路线’ => ‘对应的版本号’, * ‘文件路线’
=> ‘对应的本子号’, * ‘文件路线’ => ‘对应的本子号’, * ); *
@return [type] [description] */ public function getResState() { if
(file_exists($this->resStatePath)) { require $this->resStatePath;
return $resState; } return []; } /** *
总结文件的版本号,那一个是依据测算文件MD5散列值获得版本号 *
只要文件内容退换了,所总计获得的散列值就能不雷同 *
用于判别能源文件是还是不是有改变过 * @param [type] $filePath
[description] * @return [type] [description] */ public function
_getResStateVersion($filePath) { return
base_convert(crc32(md5_file($filePath)), 10, 36); } /** *
确认保障目录可写 * @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.’不可写’); } } } /**
* 将压缩后的财富文件写入到/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); } } private
function _saveResState($resState) { ksort($resState); $content =
“<?php\n\n\$resState = array(\n”; foreach ($resState as $k =>
$v) { $content .= “\t ‘$k’ => ‘$v’,\n”; } $content .= “);\n\n”;
file_put_contents($this->resStatePath, $content); } } 点击张开能源压缩类

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

任何类大部分代码笔者都加了讲明,方便大家连忙掌握。这里小编也会对每一行代码实行批注。

(1)

PHP

/** 须求减少的财富目录*/ 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’; }

1
2
3
4
5
6
7
8
9
10
11
12
13
/** 需要压缩的资源目录*/
    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变量是供给减弱的能源目录,假设你有新的管理目录,能够在此变量里假设新的目录名就能够管理。附上自身测量检验项目标目录图

澳门微尼斯人手机版 10

$compressResIngorePrefix 忽略被压缩的门径的路子前有的是该数组变量的字符串,举例有三个财富路线为
js/icon/bg.js只怕是js/icon_index.js可能是js/icon.header.js,假设在该数组中到场了
js/icon这些字符串,那么财富路线为js/icon起先的都会被忽略掉,也正是一贯跳过,不用压缩。(因为财富文件里总有局地是无需减小的嘛)

$resRootDir寄存财富根目录的

$resStatePath 这些是财富版本文件路线

(2)步入compressRes() 方法,大家先分析前边这一段代码

PHP

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

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

——————————-调用getResState() 讲解start————————————————————-

此处首先是调用 $this->getResState() 方法来获得寄放版本的能源文件,此处先跳到该办法看看是何等写的,其实便是带有该文件,然后回来里面寄放版本号的数组,大家看注释能够清楚该公文里寄放版本号的格式(顺便附上海教室让我们看看)

PHP

/** * 获取贮存财富版本的文件 * 它是坐落八个数组里 * $resState =
array( * ‘文件路线’ => ‘对应的本子号’, * ‘文件路线’ =>
‘对应的版本号’, * ‘文件路线’ => ‘对应的本子号’, * ); * @return
[type] [description] */ public function getResState() { if
(file_exists($this->resStatePath)) { require $this->resStatePath;
return $resState; } return []; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
     * 获取存放资源版本的文件
     * 它是放在一个数组里
     * $resState = array(
     *         ‘文件路径’ => ‘对应的版本号’,
     *         ‘文件路径’ => ‘对应的版本号’,
     *         ‘文件路径’ => ‘对应的版本号’,
     *     );
     * @return [type] [description]
     */
    public function getResState() {
        if (file_exists($this->resStatePath)) {
            require $this->resStatePath;
            return $resState;
        }
        return [];
    }

(财富版本文件截图:)

澳门微尼斯人手机版 11

——————————-调用getResState() 讲解end————————————————————-

随之看compressRes()里的这一段代码

PHP

//起先遍历须求减小的财富目录 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);

1
2
3
4
5
6
7
8
9
//开始遍历需要压缩的资源目录
        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 的值是那样子的:

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

而文件的相对路线$object是那样子的 :

css/home/index.css

此地就从头调用$this->_getResStateVersion($filePath)来计量文件的版本号

——————————-调用_getResStateVersion($filePath)
讲解start————————————————————

PHP

/** * 计算文件的版本号,那个是基于测算文件MD5散列值获得版本号 *
只要文件内容更动了,所计算获得的散列值就能够分歧等 *
用于判别财富文件是或不是有改造过 * @param [type] $filePath
[description] * @return [type] [description] */ public function
_getResStateVersion($filePath) { return
base_convert(crc32(md5_file($filePath)), 10, 36); }

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

——————————-调用_getResStateVersion($filePath)
讲解end————————————————————-

恐怕到版本号后,再看下一段代码,这里初始调用$this->getObjectInfo()方法,这里获得到压缩文件的相对路线$minObject,是还是不是须求压缩$needCompress,版本号$state,文件后缀$extension。

PHP

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

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

——————————调用$this->getObjectInfo() 讲解start————————————————————

PHP

/** * 获取财富文件有关音讯 * @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; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
     * 获取资源文件相关信息
     * @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()函数的代码:

PHP

/** * 推断 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); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
     * 判断 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);
        }
    }

if
(in_array($extension, $this->compressResDir),那几个论断便是是还是不是是需求管理的多个目录里的。

下一场中间的foreach ($this->compressResIngorePrefix as $v) { if
(str_start_with($object, $v, true)) { $needCompress = false; } }

以此是判别是还是不是是以$this->compressResIngorePrefix属性定义的前边部分字串开端的不二等秘书技,是的话就概略压缩该能源文件。

决断到结尾else
正是注解该财富文件没有需要减小了,最终是回来$minObject,$needCompress,$state,$extension那五个变量。

——————————-调用$this->getObjectInfo() 讲解end————————————————————-

到那边延续回到看 compressRes()方法里面包车型客车代码

PHP

//压缩文件的绝对路线 $minFilePath = str_replace(‘\\’, ‘/’,
$this->resRootDir. $minObject);
//************此处p推断是最关键部分之一*****************//
//决断文件是或不是存在且早已改动过 if (isset($resState[$object]) &&
$resState[$object] == $state && isset($resState[$minObject]) &&
file_exists($minFilePath)) { continue; }

1
2
3
4
5
6
7
8
//压缩文件的绝对路径
                $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),这几个是决断压缩文件路线是还是不是留存,而且该压缩文件是还是不是实际存在目录中。

看下一段代码,借使能走到这一有个别,表明当前的这些财富文件是被转移过的(代码修改过),那么此时就对文本实行削减操作了

PHP

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

1
2
3
4
5
6
7
8
//确保/www/min/目录可写
                $this->_ensureWritableDir(dirname($minFilePath));
 
                if ($needCompress) {
                    $this->compressResFileAndSave($filePath, $minFilePath);
                } else {
                    copy($filePath, $minFilePath);
                }

$this->_ensureWritableDir(),此办法是要有限协理新创设的www/min目录是可写的,这里附上代码:

——————————-调用$this->_ensureWritableDir() 讲解start————————————————————-

PHP

/** * 确认保障目录可写 * @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.’不可写’); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
     * 确保目录可写
     * @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() 讲解end————————————————————-

if
($needCompress),那些判别资源文件是还是不是须求缩短,要求的话调用$this->compressResFileAndSave($filePath,
$minFilePath);无需的话,间接复制文件到压缩文件路径 copy($filePath,
$minFilePath);

先看$this->compressResFileAndSave()

——————————-调用$this->compressResFileAndSave()
讲解start————————————————————-

PHP

/** * 将削减后的能源文件写入到/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); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
     * 将压缩后的资源文件写入到/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的类,它

贰个用来压缩js文件的PHP类,百度得以找到,调用这几个类的minify()那一个办法就能够减小了;而css的压缩利用正则替换到压缩,把这一个空格换行什么的都去掉。到此就收缩成功

了,然后再将核减后的能源写入到相应的压缩文件路线里去。

——————————-调用$this->compressResFileAndSave()
讲解end————————————————————-

紧接着继续看compressRes()这么些格局里的代码,这里发轫正是保存新的版本号到$resState数组里
$object=>$state,还应该有正是新的回退路线$minObject,而那边$count++的功效是,当那些轮回肆18回就将
$resState这么些数组写入贰遍到
resState.php文件里,这里是由于审慎思量而已,就算你不加这几个$count的管理那某些也能够,最终写入二遍就行了。

PHP

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

1
2
3
4
5
6
7
8
9
10
11
12
$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)
讲解start————————————————————-

PHP

private function _saveResState($resState) { ksort($resState); $content
= “<?php\n\n\$resState = array(\n”; foreach ($resState as $k
=> $v) { $content .= “\t ‘$k’ => ‘$v’,\n”; } $content .=
“);\n\n”; file_put_contents($this->resStatePath, $content); }

1
2
3
4
5
6
7
8
9
private function _saveResState($resState) {
        ksort($resState);
        $content = "<?php\n\n\$resState = array(\n";
        foreach ($resState as $k => $v) {
            $content .= "\t ‘$k’ => ‘$v’,\n";
        }
        $content .= ");\n\n";
        file_put_contents($this->resStatePath, $content);
    }

——————————-调用$this->_saveResState($resState)
讲解end————————————————————-

拍卖完后,看看所生成的文书,这里八个文本会有多少个版本,旧版本从未删除掉,在支付条件下删不删除都没难题,这里怎么不删除旧版本的压缩文件,那就关乎到在更新多少个应用服务器代码时所要注意的主题素材里。在此作者就多讲明一点吧,简单地举例吗,一般大型项目中的静态财富和模板文件是安顿在差异的机器集群上的,上线的进程中,静态财富和页面文件的布局时间距离恐怕会相当短,对于叁个重型互连网使用来讲正是在二个非常小的小运输距离离内,都有一点都不小只怕出现新客商访问,假使旧版本的静态能源删除了,但新本子的静态财富还没布署到位,那么客户就加载不到该静态能源,结果总之,所以,一般情形下大家会保留旧版本的静态能源,然后等有着片段配置产生了,再经过自然的脚本删除掉也没涉及,其实,这个不必删除也是足以的,你想想,一个门类发叁回版本,才会调用三回财富文件缩小方法,它只会对修改过的文本进行生成新版本号的静态文件而已。那么些就看个人的做法了。

澳门微尼斯人手机版 12

大家能够张开看看,下面这些正是减掉后的文书的代码了,文件原大小为16K,压缩后大概少了5K,以往是11K,压缩比差十分的少是2/3,假如在大型项目中,贰个复杂点的页面会有极大的静态能源文件要加载,通过此办法,大大地拉长了加载的快慢。(或许有一些朋友以为压缩个几K只怕十几K算什么,完全能够忽略,其实本人想说的是,当您在大型项目中优化品种的时候,能够减弱几K的代码,也给网址的属性升高了一大截)

澳门微尼斯人手机版 13

到此,能源减少处理就剖判完结了。其实,有早晚基础的爱侣,能够一向看本人享受的可怜代码就能够了,要是通晓不了,再看自个儿下边这一步步的解析批注,笔者是处在能看过来此博客的对象,无论技巧是好依然是稍弱,都能看懂,所以才对代码一步步地张开分析教学。(希望各位多多协理四哥)

————————————————————————————————————————-

  1. 接下去正是教师如何替换压缩后的财富文件了。

这个到Home.php

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
class Home extends MY_Controller { public function index() {
$this->smartyData[‘test’] = 111; //那么些私下认可是加载
www/css/home/index.css文件 $this->addResLink(‘index.css’);
//那么些暗中认可是加载www/js/jquery.all.min.js文件
$this->addResLink(‘/jquery.all.min.js’);
//这么些私下认可是加载www/js/index.js文件 $this->addResLink(‘index.js’);
$this->displayView(‘home/index.tpl’); } }

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

上边有加载八个财富文件,大家先看看$this->addResLink();那一个办法,这些办法放在My_Controller.php里:

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; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
     * 资源路径
     * @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那些父类的具有代码吧

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
class MY_Controller extends CI_Controller { public function
__construct() { parent::__construct(); //压缩jscss能源文件
$this->compressResHandle(); }
//==========================使用SMARTY模板引擎================================//
/* 斯Matty母版页文件路线 */ protected $masterPage = ‘default.tpl’; /*
视图像和文字件路线*/ protected $smartyView; /* 要赋值给smarty视图的多少*/
protected $smartyData = []; /* 能源文件*/ protected $_resLink =
[‘js’=>[], ‘css’=>[]]; /** * 使用母版页输出二个视图 *
@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_DIOdyssey.’Smarty.class.php’; $this->smarty = new 斯马特y();
$this->smarty->setCompileDir(APPPATH . ‘cache/’);
$this->smarty->setCacheDir(应用程式PATH . ‘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); } } /** * 能源路径 * @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; } private function
_getViewDir($setTemplateDir, &$viewName, &$masterPage = null,
&$templateDir) { if (‘/’ === $viewName[0]) $viewName =
substr($viewName, 1); //是不是选取模板,有,则路由到
/views/master_page/*****.tpl下去 if ($masterPage) { $masterPage =
‘/’ === $masterPage[0] ? substr($masterPage, 1) : (‘master_page’
.’/’. $masterPage); } //是不是设置模板目录 if ($setTemplateDir) {
$templateDir = VIEWPATH;
$this->smarty->setTemplateDir($templateDir); } } /** *
压缩js、css财富文件(优化) * @return [type] [description] */
private function compressResHandle() {
$this->load->library(‘Res迷你fier’); //压缩内定文件夹下的财富文件
$this->resminifier->compressRes(); } } 点击展开 My_Controller.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
 
class MY_Controller extends CI_Controller {
    public function __construct() {
        parent::__construct();
 
        //压缩jscss资源文件
        $this->compressResHandle();
    }
 
    //==========================使用SMARTY模板引擎================================//
    /* Smarty母版页文件路径 */
    protected $masterPage = ‘default.tpl’;
    /* 视图文件路径*/
    protected $smartyView;
    /* 要赋值给smarty视图的数据*/
    protected $smartyData = [];
    /* 资源文件*/
    protected $_resLink = [‘js’=>[], ‘css’=>[]];
 
    /**
     * 使用母版页输出一个视图
     * @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);
        }
    }
 
    /**
     * 资源路径
     * @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;
    }
 
    private function _getViewDir($setTemplateDir, &$viewName, &$masterPage = null, &$templateDir) {
        if (‘/’ === $viewName[0]) $viewName = substr($viewName, 1);
 
        //是否使用模板,有,则路由到 /views/master_page/*****.tpl下去
        if ($masterPage) {
            $masterPage = ‘/’ === $masterPage[0] ? substr($masterPage, 1) : (‘master_page’ .’/’. $masterPage);
        }
 
        //是否设置模板目录
        if ($setTemplateDir) {
            $templateDir = VIEWPATH;
            $this->smarty->setTemplateDir($templateDir);
        }
    }
 
    /**
     * 压缩js、css资源文件(优化)
     * @return [type] [description]
     */
    private function compressResHandle() {
        $this->load->library(‘ResMinifier’);
        //压缩指定文件夹下的资源文件
        $this->resminifier->compressRes();
    }
}
 
点击打开 My_Controller.php

打字与印刷出来 $this->_resLink那脾特性的组织是那样子的:

PHP

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Array
(
    [js] => Array
        (
            [0] => /jquery.all.min.js
            [1] => index.js
        )
 
    [css] => Array
        (
            [0] => index.css
        )
 
)

再再次回到Home.php里面调用 $this->displayView(‘home/index.tpl’);

咱俩看这么些方式:

PHP

/** * 使用母版页输出三个视图 * @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_DIRubicon.’Smarty.class.php’; $this->smarty = new 斯玛特y();
$this->smarty->setCompileDir(APPPATH . ‘cache/’);
$this->smarty->setCacheDir(应用程式PATH . ‘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); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
     * 使用母版页输出一个视图
     * @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);
        }
    }

这一段代码未有一部分正是调用了斯马特y模板引擎的内容,这几个关于斯马特y的学识笔者就不讲了,我们能够本身百度,这里最主要讲
res_link()
那么些函数,正是经过这么些函数来张开财富文件替换的。先看这些函数的代码:

PHP

/** * 输出 HttpHead 中的能源总是。 css/js 自动决断真实路径 * @param
string 文件路线 * @return string */ function res_link($file) { $file
= res_path($file, $extension); if ($extension === ‘css’) { return
‘<link rel=”stylesheet” type=”text/css” href=”‘%20.%20$file%20.%20′”/>’; }
else if ($extension === ‘js’) { return ‘<script
type=”text/javascript” src=”‘.$file.'”></script>’; } else {
return false; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
     * 输出 HttpHead 中的资源连接。 css/js 自动判断真实路径
     * @param  string  文件路径
     * @return string      
     */
    function res_link($file) {
        $file = res_path($file, $extension);
 
        if ($extension === ‘css’) {
           return ‘<link rel="stylesheet" type="text/css" href="’%20.%20$file%20.%20’"/>’;
        } else if ($extension === ‘js’) {
            return ‘<script type="text/javascript" src="’.$file.’"></script>’;
        } else {
            return false;
        }
    }

这边最重视正是 res_path() 函数了,那么些函数能活动路由财富的不追求虚名路线。举例:index.css = > css/home/index.css

该函数最关键的两个功力是替换财富的缩减版本。

直接看代码:

PHP

/** * 智能路由财富实际路线 * @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
应用软件PATH.’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); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
     * 智能路由资源真实路径
     * @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);
 
    }

代码基本上都给了解说,方便大家轻便去领略,前边一部分是智能路线css、js财富的不二等秘书诀,前边一部分是替换压缩版本,这一有个别的逻辑其实和能源减弱这里的逻辑基本一致,就是经过能源文件路线,进行推断和拍卖,最终获得能源的滑坡版本的门路,最终就将财富的回落版本的门道重返去,放在'<link
rel=”stylesheet” type=”text/css” href=”‘ . $file . ‘”/>’里面。这样 
,就马到功成地将财富文件路线替换来了滑坡版本的能源文件路线,並且在模板输出时,输出的是收缩后的财富文件。

到此,财富替换的故事情节就到此疏解甘休。而整一项手艺也深入分析到此。

三、总结

在这里自身集中地附着本博文疏解中的几个文件代码:

Home.php

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
class Home extends MY_Controller { public function index() {
$this->smartyData[‘test’] = 111; //这么些暗中认可是加载
www/css/home/index.css文件 $this->addResLink(‘index.css’);
//那些暗中同意是加载www/js/jquery.all.min.js文件
$this->addResLink(‘/jquery.all.min.js’);
//那么些暗许是加载www/js/index.js文件 $this->addResLink(‘index.js’);
$this->displayView(‘home/index.tpl’); } } 点击打开

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

My_Controller.php

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
class MY_Controller extends CI_Controller { public function
__construct() { parent::__construct(); //压缩jscss能源文件
$this->compressResHandle(); }
//==========================使用SMARTY模板引擎================================//
/* Smarty母版页文件路线 */ protected $masterPage = ‘default.tpl’; /*
视图像和文字件路线*/ protected $smartyView; /* 要赋值给smarty视图的数目*/
protected $smartyData = []; /* 能源文件*/ protected $_resLink =
[‘js’=>[], ‘css’=>[]]; /** * 使用母版页输出三个视图 *
@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_DICRUISER.’斯马特y.class.php’; $this->smarty = new 斯马特y();
$this->smarty->setCompileDir(APPPATH . ‘cache/’);
$this->smarty->setCacheDir(应用程式PATH . ‘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); } } /** * 资源路线 * @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; } private function
_getViewDir($setTemplateDir, &$viewName, &$masterPage = null,
&$templateDir) { if (‘/’ === $viewName[0]) $viewName =
substr($viewName, 1); //是不是利用模板,有,则路由到
/views/master_page/*****.tpl下去 if ($masterPage) { $masterPage =
‘/’ === $masterPage[0] ? substr($masterPage, 1) : (‘master_page’
.’/’. $masterPage); } //是或不是设置模板目录 if ($setTemplateDir) {
$templateDir = VIEWPATH;
$this->smarty->setTemplateDir($templateDir); } } /** *
压缩js、css财富文件(优化) * @return [type] [description] */
private function compressResHandle() {
$this->load->library(‘ResMinifier’); //压缩钦点文件夹下的能源文件
$this->resminifier->compressRes(); } } 点击张开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php
defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
 
class MY_Controller extends CI_Controller {
    public function __construct() {
        parent::__construct();
 
        //压缩jscss资源文件
        $this->compressResHandle();
    }
 
    //==========================使用SMARTY模板引擎================================//
    /* Smarty母版页文件路径 */
    protected $masterPage = ‘default.tpl’;
    /* 视图文件路径*/
    protected $smartyView;
    /* 要赋值给smarty视图的数据*/
    protected $smartyData = [];
    /* 资源文件*/
    protected $_resLink = [‘js’=>[], ‘css’=>[]];
 
    /**
     * 使用母版页输出一个视图
     * @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);
        }
    }
 
    /**
     * 资源路径
     * @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;
    }
 
    private function _getViewDir($setTemplateDir, &$viewName, &$masterPage = null, &$templateDir) {
        if (‘/’ === $viewName[0]) $viewName = substr($viewName, 1);
 
        //是否使用模板,有,则路由到 /views/master_page/*****.tpl下去
        if ($masterPage) {
            $masterPage = ‘/’ === $masterPage[0] ? substr($masterPage, 1) : (‘master_page’ .’/’. $masterPage);
        }
 
        //是否设置模板目录
        if ($setTemplateDir) {
            $templateDir = VIEWPATH;
            $this->smarty->setTemplateDir($templateDir);
        }
    }
 
    /**
     * 压缩js、css资源文件(优化)
     * @return [type] [description]
     */
    private function compressResHandle() {
        $this->load->library(‘ResMinifier’);
        //压缩指定文件夹下的资源文件
        $this->resminifier->compressRes();
    }
}
 
点击打开

ResMinifier.php

PHP

<?php defined(‘BASEPATH’) OR exit(‘No direct script access allowed’);
/** * 财富压缩类 */ class ResMinifier { /** 需求减小的财富目录*/
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’; } public function
compressRes() { //获取存放版本的能源文件 $resState =
$this->getResState(); $count = 0; //起头遍历须求减弱的财富目录
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); //获取文件的多少个参数值 if
(true !== $this->getObjectInfo($object, $minObject, $needCompress,
$state, $extension)) { continue; } //压缩文件的相对路径 $minFilePath =
str_replace(‘\\’, ‘/’, $this->resRootDir. $minObject);
//************此处p判定是最根本部分之一*****************//
//剖断文件是或不是存在且已经更动过 if (isset($resState[$object]) &&
$resState[$object] == $state && isset($resState[$minObject]) &&
file_exists($minFilePath)) { continue; } //确定保证/www/min/目录可写
$this->_ensureWritableDir(dirname($minFilePath)); if ($needCompress)
{ $this->compressResFileAndSave($filePath, $minFilePath); } else {
copy($filePath, $minFilePath); } $resState[$object] = $state;
$resState[$minObject] = ”; $count++; if ($count == 50) {
$this->_saveResState($resState); $count = 0; } } } if($count)
$this->_saveResState($resState); } /** * 获取能源文件有关消息 *
@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($file帕特h); //文件名后缀
$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; } /** * 获取寄存财富版本的公文 * 它是献身二个数组里 *
$resState = array( * ‘文件路线’ => ‘对应的版本号’, * ‘文件路线’
=> ‘对应的本子号’, * ‘文件路线’ => ‘对应的本子号’, * ); *
@return [type] [description] */ public function getResState() { if
(file_exists($this->resStatePath)) { require $this->resStatePath;
return $resState; } return []; } /** *
总结文件的版本号,这一个是依赖测算文件MD5散列值获得版本号 *
只要文件内容改换了,所计算得到的散列值就能不雷同 *
用于推断能源文件是不是有变动过 * @param [type] $filePath
[description] * @return [type] [description] */ public function
_getResStateVersion($filePath) { return
base_convert(crc32(md5_file($filePath)), 10, 36); } /** *
确定保证目录可写 * @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.’不可写’); } } } /**
* 将削减后的财富文件写入到/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(“写入文件{$minFile帕特h}失败”, -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); } } private
function _saveResState($resState) { ksort($resState); $content =
“<?php\n\n\$resState = array(\n”; foreach ($resState as $k =>
$v) { $content .= “\t ‘$k’ => ‘$v’,\n”; } $content .= “);\n\n”;
file_put_contents($this->resStatePath, $content); } } 点击展开

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

Common.php

PHP

<?php /** * 输出 HttpHead 中的资源总是。 css/js 自动剖断真实路线
* @param string 文件路线 * @return string */ function
res_link($file) { $file = res_path($file, $extension); if ($extension
=== ‘css’) { return ‘<link rel=”stylesheet” type=”text/css” href=”‘ .
$file . ‘”/>’; } else if ($extension === ‘js’) { return ‘<script
type=”text/javascript” src=”‘.$file.'”></script>’; } else {
return false; } } /** * 智能路由财富实际路线 * @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
应用软件PATH.’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); } /** * 判定 subject 是或不是以 search开端,
参数钦赐是或不是忽略大小写 * @param [type] $subject [description] *
@param [type] $search [description] * @param boolean $ignore_case
[description] * @return [type] [description] */ function
str_start_with($subject, $search, $ignore_case = false) { $len2 =
strlen($search); if (0 === $len2) return true; $len1 = strlen($subject);
if ($len1 < $len2) return false; if ($ignore_case) { return 0 ===
strncmp($subject, $search, $len2); } else { return 0 ===
strncasecmp($subject, $search, $len2); } } /** * 判定 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); } } 点击张开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
    /**
     * 输出 HttpHead 中的资源连接。 css/js 自动判断真实路径
     * @param  string  文件路径
     * @return string      
     */
    function res_link($file) {
        $file = res_path($file, $extension);
 
        if ($extension === ‘css’) {
           return ‘<link rel="stylesheet" type="text/css" href="’%20.%20$file%20.%20’"/>’;
        } else if ($extension === ‘js’) {
            return ‘<script type="text/javascript" src="’.$file.’"></script>’;
        } else {
            return false;
        }
    }
 
    /**
     * 智能路由资源真实路径
     * @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);
 
    }
 
    /**
     * 判断 subject 是否以 search开头, 参数指定是否忽略大小写
     * @param  [type]  $subject     [description]
     * @param  [type]  $search      [description]
     * @param  boolean $ignore_case [description]
     * @return [type]               [description]
     */
    function str_start_with($subject, $search, $ignore_case = false) {
        $len2 = strlen($search);
        if (0 === $len2) return true;
        $len1 = strlen($subject);
        if ($len1 < $len2) return false;
        if ($ignore_case) {
            return 0 === strncmp($subject, $search, $len2);
        } else {
            return 0 === strncasecmp($subject, $search, $len2);
        }
    }
 
    /**
     * 判断 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);
        }
    }
 
点击打开

$resState.php(里面包车型客车代码是自动生成的)

XHTML

<?php $resState = array( ‘css/home/index.css’ => ‘gwy933’,
‘js/echarts-all.min.js’ => ‘wqrf1c’, ‘js/home/index.js’ =>
‘s2z6f5’, ‘js/icon.js’ => ‘pgcyih’, ‘js/icon_home.js’ =>
‘zhl9iu’, ‘js/ion.rangeSlider.min.js’ => ‘akq381’,
‘js/jquery-ui-autocomplete.js’ => ‘8nzacv’, ‘js/jquery-ui.min.js’
=> ‘i6tw8z’, ‘js/jquery.all.min.js’ => ‘d2w76v’,
‘js/jquery.city.js’ => ‘toxdrf’, ‘js/jquery.easydropdown.min.js’
=> ‘2ni3i0’, ‘js/jquery.matrix.js’ => ‘3vrqkk’,
‘js/jquery.mobile.all.min.js’ => ‘ernu7r’, ‘js/jquery.qrcode.min.js’
=> ‘yuhnsj’, ‘js/jquery.tinyscrollbar.min.js’ => ‘oakk3c’,
‘js/mobiscroll.custom.min.js’ => ‘kn8h2e’, ‘js/store.min.js’ =>
‘n50jwr’, ‘js/swiper.animate1.0.2.min.js’ => ‘mm27zc’,
‘js/swiper.min.js’ => ‘jicwhh’, ‘min/css/home/index.6a4e83eb.css’
=> ”, ‘min/css/home/index.gwy933.css’ => ”,
‘min/css/home/index.puzbnf.css’ => ”,
‘min/css/home/index.thv8x7.css’ => ”,
‘min/js/echarts-all.76025ee0.js’ => ”,
‘min/js/echarts-all.wqrf1c.js’ => ”, ‘min/js/home/index.65363d41.js’
=> ”, ‘min/js/home/index.s2z6f5.js’ => ”,
‘min/js/icon.5bbd4db9.js’ => ”, ‘min/js/icon.pgcyih.js’ => ”,
‘min/js/icon_home.7fe74076.js’ => ”, ‘min/js/icon_home.zhl9iu.js’
=> ”, ‘min/js/ion.rangeSlider.261d8ed1.js’ => ”,
‘min/js/ion.rangeSlider.akq381.js’ => ”,
‘min/js/jquery-ui-autocomplete.1f3bb62f.js’ => ”,
‘min/js/jquery-ui-autocomplete.8nzacv.js’ => ”,
‘min/js/jquery-ui.418e9683.js’ => ”, ‘min/js/jquery-ui.i6tw8z.js’
=> ”, ‘min/js/jquery.all.2f248267.js’ => ”,
‘min/js/jquery.all.d2w76v.js’ => ”, ‘min/js/jquery.city.6b036feb.js’
=> ”, ‘min/js/jquery.city.toxdrf.js’ => ”,
‘min/js/jquery.easydropdown.2ni3i0.js’ => ”,
‘min/js/jquery.easydropdown.98fa138.js’ => ”,
‘min/js/jquery.matrix.3vrqkk.js’ => ”,
‘min/js/jquery.matrix.dfe2a44.js’ => ”,
‘min/js/jquery.mobile.all.3539ebb7.js’ => ”,
‘min/js/jquery.mobile.all.ernu7r.js’ => ”,
‘min/js/jquery.qrcode.7d9738b3.js’ => ”,
‘min/js/jquery.qrcode.yuhnsj.js’ => ”,
‘min/js/jquery.tinyscrollbar.578e4cb8.js’ => ”,
‘min/js/jquery.tinyscrollbar.oakk3c.js’ => ”,
‘min/js/mobiscroll.custom.4a684f66.js’ => ”,
‘min/js/mobiscroll.custom.kn8h2e.js’ => ”,
‘min/js/store.536545cb.js’ => ”, ‘min/js/store.n50jwr.js’ => ”,
‘min/js/swiper.4650ad75.js’ => ”,
‘min/js/swiper.animate1.0.2.517f82e8.js’ => ”,
‘min/js/swiper.animate1.0.2.mm27zc.js’ => ”,
‘min/js/swiper.jicwhh.js’ => ”, ); 点击张开

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

 

除此以外附上JShrink那些PHP类的链接给大家下载 

举个例子大家照旧以为相当不足OK的话,笔者一直将以此试验项目打包供大家下载下来学习和询问:

四、结语

聊起底作者来分享大家线上体系的现实性达成方案:

大家的门类分线上情形、开垦意况和测量检验遭受,在开拓和测验境况中,我们每三次访谈都会调用压缩文件的接口,然后再对转移的财富文件的高低是要做决断的,假若缩减后文件过小,将供给将该财富文件的代码合并到别的能源文件里去,以此缩小不需求的HTTP伏乞(因为文件太小,财富的下载时间远小于HTTP供给响应所消耗的小时);另叁个是图片的拍卖,全部图片都要因而压缩本领由此(举例在: 
那一个网址去收缩图片),在PC端,就算是小Logo的话,使用图片合併的艺术进行优化,详细情况可参照本身的那篇博文:http://www.cnblogs.com/it-cen/p/4618954.html   
而在wap端的图纸管理利用的是base64编码格局来处理图片,详细情况能够参见本身的那篇博文: 
,当页面输出时,会利用redis来缓存页面(为何用内部存款和储蓄器来缓存实际不是选用页面缓存,这几个以往再享受给大家)。假使是线上意况,每发一次版本,才会调用一下能源文件减少这么些接口,并且线上的静态能源(css、js、图片)是寄存在阿里云的OSS里的,与大家的应用服务器是分手的。那是大家线上项目标一片段优消除决方案,当然了,还也可以有越来越多优化手艺,笔者会在其后各种计算和享受出来,方便大家一道念书和交换。

此次博文就享受到此,谢谢观看此博文的敌人们。

1 赞 1 收藏
评论

澳门微尼斯人手机版 7

从输入 U中华VL 到页面加载成功的进程中都时有产生了怎么业务?

2015/10/03 · HTML5,
JavaScript · 6
评论 ·
HTTP,
浏览器

初稿出处:
百度FEX/吴多益(@吴多益)   

背景  本文来源于事先笔者发的一篇搜狐:

澳门微尼斯人手机版 15

可是写这篇小说并非为了帮大家筹算面试,而是想借那道题来介绍Computer和互连网的基础知识,让读者驾驭它们之间是何等关联起来的。

为了便于明白,笔者将一切经过分成了八个难题来开展。

从内部存储器到 LCD

在手提式有线电话机的 SoC 中国和扶桑常都会有贰个 LCD 调整器,当 Framebuffer 筹划好后,CPU
会通过 AMBA 内部总线通告LCD 调整器,然后那个调节器读取 Framebuffer
中的数据,进行格式调换、伽马改进等操作,最终经过 DSI、HDMI
等接口发往 LCD 显示器。

以 OMAP5432 为例,下图是它所支撑的一种互动数据传输:澳门微尼斯人手机版 16

运转商网络内的路由

多少过双绞线发送到运行商网络后,还恐怕会因此重重当中等路由转载,读者能够通过
traceroute
命令只怕在线可视化学工业具来查阅那几个路由的
ip 和地点。

当数码传递到那个路由器后,路由器会抽出包中目标地址的前缀,通过内部的转发表查找对应的出口链路,而这么些转载布是什么样获得的吗?这正是路由器中最要紧的选路算法了,可选的有比很多,笔者对那上头并不太领悟,看起来维基百科上的词条列得很全。

CPU 内部的管理

活动设备中的 CPU 并非一个单独的微芯片,而是和 GPU
等微电路集成在一道,被称得上 SoC(片上系统)。

近年来提到了触屏和 CPU
的接二连三,这么些接二连三和超过八分之四计算机内部的连天一样,都以经过电气时域信号来扩充通讯的,也等于电压高低的变迁,如下边的时序图:澳门微尼斯人手机版 17

在石英钟的垄断下,这么些电流会经过 MOSFET 晶体管,晶体管中隐含
N 型元素半导体和 P 型非晶态半导体,通过电压就会操纵线路开闭,然后那么些 MOSFET
构成了 CMOS,接着再由 CMOS
完毕「与」「或」「非」等逻辑电路门,最终由逻辑电路门上就能够兑现加法、位移等总括,全部如下图所示(来自《计算机种类布局》):澳门微尼斯人手机版 18

除此之外总结,在 CPU
中还亟需存款和储蓄单元来加载和积存数据,这些存款和储蓄单元一般经过触发器(Flip-flop)来贯彻,称为贮存器。

以上那个概念都比较空虚,推荐阅读「How to Build an 8-Bit
Computer」那篇小说,小编遵照晶体管、双极型晶体管、电容等原件制作了四个8 位的Computer,扶助简单汇编指令和结果输出,即使今世 CPU
的贯彻要比那么些纷纷得多,但基本原理还是一直以来的。

另外其实自身也是刚起先学习 CPU
集成电路的兑现,所以就不在那误人子弟了,感兴趣的读者请阅读本节背后推荐的书本。

恢宏学习

  • 《微型电脑体系布局》
  • 《Computer种类布局:量化商量措施》
  • 《微型Computer组成与设计:硬件/软件接口》
  • 《编码》
  • 《CPU自制入门》
  • 《操作系统概念》
  • 《ARMv7-AR种类布局参照他事他说加以考察手册》
  • 《Linux内核设计与落到实处》
  • 《精通Linux设备驱动程序开荒》

其次个难点:浏览器怎样向网卡发送数据?

从字符到图片

二维渲染中最复杂的要数文字展现了,即使想想就像相当的粗略,不就是将有个别文字对应的字形(glyph)找寻来么?在中文和阿拉伯语中那样做是没难点的,因为多少个字符就相应三个字形(glyph),在字体文件中找到字形,然后画上去就能够了,但在马耳他语中是极度的,因为它有有连体格局。

(现在续再单独介绍,这里非常复杂)

第七个难点:服务器重回数据后浏览器如何管理?

眼下聊起服务端管理完央求后,结果将因而互连网发回看客端的浏览器,从本节启幕将介绍浏览器接收到数量后的管理,值得说的是那上边以前有一篇不错的篇章 How
Browsers
Work,所以重重内容本人不想再另行介绍,因而将首要放在那篇文章所忽略的片段。

扩充学习

  • 《处理器网络:自顶向下方法与Internet特色》
  • 《微型计算机互连网》
  • 《Web质量权威指南》

正文所忽略的剧情

为了编写制定方便,前边的介绍上将相当多平内部原因节落成忽略了,譬喻:

  • 内部存款和储蓄器相关
    • 堆,这里的分配政策有广大,举个例子malloc 的实现
    • 栈,函数调用,已经有那多少个精粹的篇章或书籍介绍了
    • 内部存款和储蓄器映射,动态库加载等
    • 队列差不离无处不在,但这几个细节和公理没太大关系
  • 种种缓存
    • CPU 的缓存、操作系统的缓存、HTTP 缓存、后端缓存等等
  • 各类监督
    • 广大日志会保存下来以便后续深入分析

LCD 显示

最终简短介绍一下 LCD 的来得原理。

先是,要想令人眼能看见,就非得有光辉步向,要么通过反射、要么有光源,例如Kindle 所使用的 E-ink
显示屏自己是不发光的,所以必需在有光线的地方能力阅读,它的长处是省电,但限制太大,所以大概具备LCD 都会自带光源。

当下 LCD
中国和东瀛常选拔 LED 作为光源,LED
接上电源后,在电压的职能下,内部的正负电子结合会自由光子,进而发出光,这种物理现象叫电致发光(Electroluminescence),这在前方介绍光导纤维时也介绍过。

以下是 iPod Touch 2
拆开后的轨范:(来自 Wikipedia):

澳门微尼斯人手机版 19

在上航海用教室中能够看来 6 盏
LED,那就是整整显示器的光源,那几个光源将因此反射的反射输出到显示屏中。

有了光源还得有色彩,在 LED 中国和东瀛常做法是选择彩色滤光片(Color filter)来将
LED 光源转成不一样颜色。

另外直接行使二种颜色的 LED
也有效的,它能防止了滤光导致的光子浪费,降低耗能,很适用于智能石英表那样的小荧屏,Apple
收购的 LuxVue
集团就应用的是这种方法,感兴趣的话能够去商讨它的专利

LCD 显示屏上的各类物理像素点实际上是由红、绿、蓝 3
种色彩的点构成,每种颜色点能独立主宰,上边是用显微镜放大后的图景(来自Wikipedia):澳门微尼斯人手机版 20

从上海教室能够看来每 3
种颜色的滤光片都全亮的时候便是反革命,都灭便是莲红,假使你精心看还是可以够看出某个点并非全然黑,那是字体上的反锯齿效果。

经过这 3 种颜色亮度的两样组合就能够发出出各类色彩,假设每一个颜色点能生出
256 种亮度,就能够生成 256 * 256 * 256 = 16777216 种色彩。

实际不是独具荧屏的亮度都能实现 256,在选取显示器时有个参数是 8-Bit 或
6-Bit 面板,当中 8-Bit 的面板能在物理上到达 256 种亮度,而 6-Bit
的则唯有 64 种,它须求靠刷新率调整(Frame rate
control)技巧来达成256 的功用。

何以调整这么些颜色点的亮度?那将在靠液晶体了,液晶体的风味是当有电流通过时会发生旋转,进而将一些光线挡住,所以假如透过电压调节液晶体的团团转就会决定那几个颜色点的亮度,近年来手提式有线电电话机荧屏中数见不鲜采用TFT 调整器来对其开展支配,在 TFT 中最著名的要数 IPS 面板。

那几个过滤后的光辉大多数会直接进去眼睛,有些光还也许会在别的表面上通过漫(diffuse)反射或镜面(specular)反射后再进来眼睛,加上碰到光的震慑,要实在算出有多少光到肉眼是多少个积分难题,感兴趣的读者可以斟酌依赖物理的渲染。

当光线步向眼睛后,接下去就是生物学的世界了,所以大家到此甘休。

外链资源的加载

(待补充,这里有调节计谋)

底层互连网左券的有血有肉事例

接下去假设持续介绍 IP 公约和 MAC
合同或然过多读者会晕,所以本节将利用 Wireshark 来通超过实际际事例解说,以下是自己呼吁百度首页时抓取到的互连网数据:澳门微尼斯人手机版 21

最上面是实在的二进制数据,中间是深入分析出来的次第字段值,能够看看里边最尾部为
HTTP 左券(Hypertext Transfer Protocol),在 HTTP 以前有 54
字节(0x36),那正是底层互联网协议所拉动的费用,我们接下去对那个公约进行剖析。

在 HTTP 之上是 TCP 协议(Transmission Control
Protocol),它的具体内容如下图所示:澳门微尼斯人手机版 22

透过尾巴部分的二进制数据,能够看看 TCP 左券是加在 HTTP 文本前边的,它有 21个字节,个中定义了地面端口(Source port)和目的端口(Destination
port)、顺序序号(Sequence Number)、窗口长度等新闻,以下是 TCP
左券各类部分数据的完好介绍:

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data
| |U|A|E|R|S|F| | | Offset| Reserved |R|C|O|S|Y|I| Window | | |
|G|K|L|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|E|R|S|F|                               |
| Offset| Reserved  |R|C|O|S|Y|I|            Window             |
|       |           |G|K|L|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

现实种种字段的功力这里就不介绍了,感兴趣的读者能够阅读 RFC
793,并整合抓包深入分析来明白。

亟待小心的是,在 TCP 和睦中并不曾 IP 地址音信,因为那是在上一层的 IP
合同中定义的,如下图所示:澳门微尼斯人手机版 23

IP 斟酌同样是在 TCP 前边的,它也可以有 20
字节,在这里指明了版本号(Version)为 4,源(Source) IP
为 192.168.1.106,目标(Destination) IP 为 119.75.217.56,因而 IP
合同最要紧的成效便是规定 IP 地址。

因为 IP 左券中得以查看到对象 IP 地址,所以一旦开掘一些特定的 IP
地址,有些路由器就能。。。

而是,光靠 IP 地址是无力回天张开通讯的,因为 IP
地址并不和某台设备绑定,举例您的记录簿的 IP
在家中是 192.168.1.1,但到商铺就成为172.22.22.22 了,所以在底层通信时供给使用二个定点的地点,那就是MAC(media access control) 地址,各样网卡出厂时的 MAC
地址都是定点且独一的。

就此再往上就是 MAC 协议,它有 14
字节,如下所示:澳门微尼斯人手机版 24

当一台电脑步入互连网时,须求经过 ARP 合同告诉其他互连网设施它的
IP 及相应的 MAC 地址是怎样,这样任何设备就能够透过 IP
地址来查找对应的器械了。

最顶上的 Frame 是表示 Wireshark 的抓包序号,并不是互连网契约

就这么,大家解答了第二个难题,但是事实上那之中还会有多数众多细节没介绍,建议大家经过下边包车型大巴书本进一步读书。

强大学习

  • 《Computer Graphics, 3rd Edition : Principles and
    Practices》
  • 《交互式电脑图形学》

连接 Wi-Fi 路由

Wi-Fi 网卡要求经过 Wi-Fi
路由来与外界通讯,原理是遵照有线电,通过电流变化来发生有线电,这些进度也叫「调制」,而扭曲有线电能够挑起电磁场变化,进而发出电流变化,利用这一个原理就能够将有线电中的消息解读出来就叫「解调」,个中单位时间内转移的次数就叫做频率,近期在
Wi-Fi 中所采纳的频率分为 2.4 GHz 和 5 GHz 三种。

在同四个 Wi-Fi
路由下,因为使用的成效一样,同期利用时会发生争持,为了消除那个难题,Wi-Fi
选取了被称为 CSMA/CA 的主意,简单的话正是在传输前先确认信道是不是已被应用,未有才发送数据。

而同等基于有线电原理的 2G/3G/LTE 也会越过类似的标题,但它并从未利用
Wi-Fi
这样的独占方案,而是经过频分(FDMA)、时分(TDMA)和码分(CDMA)来开展复用,具体细节这里就不进行了。

以华为路由为例,它应用的晶片是 BCM
4709,那个微芯片由
ARM Cortex-A9
管理器及流量(Flow)硬件加快组成,使用硬件微电路能够制止经过操作系统中断、上下文切换等操作,进而进步了质量。

路由器中的操作系统能够依附 OpenWrt 或 DD-WRT 来开垦的,具体细节作者不太领会,所以就不开展了。

因为内网设备的 IP
都以周围 192.168.1.x 这样的内网地址,外网不可能直接向那么些地址发送数据,所以网络数据在经过路由时,路由会修改有关地方和端口,那个操作称为 NAT 映射。

最后家庭路由一般会经过双绞线连续到运营商网络的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注