PHP网站提速
最近在研究网站提速、搜索引擎优化等技术,打算将一些技巧逐步分享,这里先说说提速。
对于基于PHP构建的网站,一个可行的方法是将网络上传输的内容减少。一是压缩,二是如果内容没有发生变化,则不发送内容到客户端,而是让客户端使用缓存的数据。虽然说现在网络速度已经比较快了,但是考虑到网页大部分都是文本内容,压缩率还是相当可观的,一般来说,构成网页的文本内容如HTML/CSS/JS等,使用gzip压缩可以达到60%以上的压缩率。这样,一个简单的网站页面每次访问也可减少60KB以上的网络传输量。而压缩操作速度是很快的,一个100KB的页面文本,压缩耗时在3毫秒以下,基本可以忽略。
我打算先从css/javascript文件入手。下面来看一段代码:
- // Created by Apex
- // http://apex.ncksoft.com/archives/279
- define('FILE_TYPE_UNKNOWN', 0);
- define('FILE_TYPE_CSS', 1);
- define('FILE_TYPE_JS', 2);
- // 这个PHP文件将会放到与css和js文件同一个目录下,方便文件定位
- $this_path = dirname( realpath(__FILE__) ).DIRECTORY_SEPARATOR;
- // 根据URL请求来决定后续发生什么样的header到客户端
- $type = FILE_TYPE_UNKNOWN;
- $fname = '';
- if(isset($_REQUEST['css']))
- {
- $type = FILE_TYPE_CSS;
- $fname = $_REQUEST['css'];
- }
- else if(isset($_REQUEST['js']))
- {
- $type = FILE_TYPE_JS;
- $fname = $_REQUEST['js'];
- }
- else
- {
- exit();
- }
- // 对参数进行判断
- if(empty($fname))
- {
- exit();
- }
- // 指定的文件应该存在,否则什么都不输出
- $fname = $this_path . $fname;
- if(!is_file($fname))
- {
- exit();
- }
- // 得到文件内容,并获取文件最后修改时间
- $output = file_get_contents($fname);
- $fmtime = filemtime($fname);
- // 如果该客户端不是第一次希望获取此文件,则会有如下变量
- if(isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]))
- {
- // 这个变量里面放着客户端所缓存的这个文件的最后修改时间
- $checktime = $_SERVER["HTTP_IF_MODIFIED_SINCE"];
- $checktime = strtotime($checktime);
- // 比较一下时间,如果文件没有改动过,则无需发送文件内容(通过发送304响应码来完成)
- if($fmtime <= $checktime)
- {
- header('HTTP/1.1 304 Not Modified');
- exit();
- }
- }
- // 一个额外处理,将css文件中的注释全部去掉。如何去掉js的注释,还没有做。 :)
- if(FILE_TYPE_CSS == $type)
- {
- $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
- }
- // 重要:只有服务端的PHP加载了zlib模块,且客户端支持获取gzip压缩数据的情况下,我们才进行压缩
- if(
- !headers_sent() &&
- extension_loaded("zlib") &&
- strstr($_SERVER["HTTP_ACCEPT_ENCODING"],"gzip")
- )
- {
- // 9 代表最强压缩
- $output = gzencode($output, 9);
- // 告诉客户端我们发送的数据是压缩过的
- header("Content-Encoding: gzip");
- // 下面这个header不太清楚其含义,貌似用于通知缓存服务器或者代理服务器(如果有的话)做某些操作吧,请达人告诉我
- header("Vary: Accept-Encoding");
- // 告诉客户端压缩后的数据长度,因为压缩后的数据是二进制的,客户端需要这个数据来决定接收多少数据后可以结束
- header("Content-Length: ".strlen($output));
- }
- // 告诉客户端我们本次发送的数据是什么内容,注意编码格式,如果你的不是utf-8编码,要进行修改
- if(FILE_TYPE_CSS == $type)
- {
- header ("content-type: text/css; charset: utf-8");
- }
- else if(FILE_TYPE_JS == $type)
- {
- header ("content-type: text/javascript; charset: utf-8");
- }
- // 重要:告诉客户端这个文件的最后修改时间,这样客户端下次访问此文件时,才会将这个时间再发回服务器,以便服务器进行判断
- header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $fmtime) . ' GMT');
- header('Etag: "' . md5($_SERVER['REQUEST_URI']).'"');
- // 将压缩后的数据发回客户端
- echo $output;
我已经尽量在代码中使用注释来说明其工作了。
将这个文件放到保存CSS/Javascript文件的目录下,然后在需要使用原来的css/javascript文件的地方如下调用:
- <link rel="stylesheet" href="http://your.domain.com/css/index.php?css=style.css" type="text/css">
或者这样:
- <script src="http://your.domain.com/css/index.php?js=common.css" type="text/javascript">
就可以了。
可能你会问,为什么要这么做?为什么不直接使用Apache的mod_deflate模块来做输出时的压缩呢?原因有三个。
- 缺省安装Apache是不会安装mod_deflate模块的,如果你的代码跑在一台你不能触及Apache设置的主机上,你将不得不用这里的办法;
- 这样可以让我们在编写代码时,尽量加入注释,以便使得代码自我解释,方便多人(或者自己在将来的某个时刻)进行维护,而注释在输出的时候,可以用PHP字符串处理功能干掉;
- 更重要的是,我们可以将多个css文件或者多个js文件一次性输出到客户端;
太晚了,第三点的详细解释随后补上,睡觉去了~~~zz~~ZZZ
[2009-12-12 继续补充]
我们知道,HTTP通讯协议其实是一个很“昂贵”的协议,每次访问服务器上的单个资源,都需要重新经过一次协议握手,其中客户端向服务端发送的请求数据,还包括cookies的内容,以及很多附加的有用数据。而一个页面一般是由多个资源构成的,例如页面文件本身、css文件、js文件、图片文件等等。我们应该尽量减少资源的数量和体积,来减少客户端与服务端的交互。
考虑到现今的网页,一般都会使用多个css文件来控制页面布局及外观。其实,完全可以将其合并为一个文件,这样客户端也就只需要发送一次请求即可。我们可以采用下面的方法:
- <link rel="stylesheet" href="http://your.domain.com/css/index.php?css=layout.css,style.css,color.css" type="text/css">
这样,我们一次性将服务器上的三个css文件发送给客户端了(当然,代码要略作调整,需要内部分解参数,然后读取三个文件到一个buffer中,再压缩输出,还要考虑最后更新时间采用哪个文件的,等等,不过这都是小问题)。
js文件也可如此处理。
目前有一个评论!
![Apex[有所思,有所志]](http://apex.ncksoft.com/wp-content/themes/deepwater/images/dw_site_logo.png)
匿名 说:
牛!