PHP网站提速

分类: 代码人生 | 214 次点击 | 发表评论
由 Apex 发表于

最近在研究网站提速、搜索引擎优化等技术,打算将一些技巧逐步分享,这里先说说提速。

对于基于PHP构建的网站,一个可行的方法是将网络上传输的内容减少。一是压缩,二是如果内容没有发生变化,则不发送内容到客户端,而是让客户端使用缓存的数据。虽然说现在网络速度已经比较快了,但是考虑到网页大部分都是文本内容,压缩率还是相当可观的,一般来说,构成网页的文本内容如HTML/CSS/JS等,使用gzip压缩可以达到60%以上的压缩率。这样,一个简单的网站页面每次访问也可减少60KB以上的网络传输量。而压缩操作速度是很快的,一个100KB的页面文本,压缩耗时在3毫秒以下,基本可以忽略。

我打算先从css/javascript文件入手。下面来看一段代码:

下载: index.php
  1. <?php
  2.  
  3. // Created by Apex
  4. // http://apex.ncksoft.com/archives/279
  5.  
  6. define('FILE_TYPE_UNKNOWN', 0);
  7. define('FILE_TYPE_CSS', 1);
  8. define('FILE_TYPE_JS', 2);
  9.  
  10. // 这个PHP文件将会放到与css和js文件同一个目录下,方便文件定位
  11. $this_path = dirname( realpath(__FILE__) ).DIRECTORY_SEPARATOR;
  12.  
  13. // 根据URL请求来决定后续发生什么样的header到客户端
  14. $type = FILE_TYPE_UNKNOWN;
  15. $fname = '';
  16. if(isset($_REQUEST['css']))
  17. {
  18.     $type = FILE_TYPE_CSS;
  19.     $fname = $_REQUEST['css'];
  20. }
  21. else if(isset($_REQUEST['js']))
  22. {
  23.     $type = FILE_TYPE_JS;
  24.     $fname = $_REQUEST['js'];
  25. }
  26. else
  27. {
  28.     exit();
  29. }
  30.  
  31. // 对参数进行判断
  32. if(empty($fname))
  33. {
  34.     exit();
  35. }
  36.  
  37. // 指定的文件应该存在,否则什么都不输出
  38. $fname = $this_path . $fname;
  39. if(!is_file($fname))
  40. {
  41.     exit();
  42. }
  43.  
  44. // 得到文件内容,并获取文件最后修改时间
  45. $output = file_get_contents($fname);
  46. $fmtime = filemtime($fname);
  47.  
  48. // 如果该客户端不是第一次希望获取此文件,则会有如下变量
  49. if(isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]))
  50. {
  51.     // 这个变量里面放着客户端所缓存的这个文件的最后修改时间
  52.     $checktime = $_SERVER["HTTP_IF_MODIFIED_SINCE"];
  53.     $checktime = strtotime($checktime);
  54.  
  55.     // 比较一下时间,如果文件没有改动过,则无需发送文件内容(通过发送304响应码来完成)
  56.     if($fmtime <= $checktime)
  57.     {
  58.         header('HTTP/1.1 304 Not Modified');
  59.         exit();
  60.     }
  61. }
  62.  
  63. // 一个额外处理,将css文件中的注释全部去掉。如何去掉js的注释,还没有做。 :)
  64. if(FILE_TYPE_CSS == $type)
  65. {
  66.     $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
  67. }
  68.  
  69. // 重要:只有服务端的PHP加载了zlib模块,且客户端支持获取gzip压缩数据的情况下,我们才进行压缩
  70. if(
  71.     !headers_sent() &&
  72.     extension_loaded("zlib") &&
  73.     strstr($_SERVER["HTTP_ACCEPT_ENCODING"],"gzip")
  74. )
  75. {
  76.     // 9 代表最强压缩
  77.     $output = gzencode($output, 9);
  78.     // 告诉客户端我们发送的数据是压缩过的
  79.     header("Content-Encoding: gzip");
  80.     // 下面这个header不太清楚其含义,貌似用于通知缓存服务器或者代理服务器(如果有的话)做某些操作吧,请达人告诉我
  81.     header("Vary: Accept-Encoding");
  82.     // 告诉客户端压缩后的数据长度,因为压缩后的数据是二进制的,客户端需要这个数据来决定接收多少数据后可以结束
  83.     header("Content-Length: ".strlen($output));
  84. }
  85.  
  86. // 告诉客户端我们本次发送的数据是什么内容,注意编码格式,如果你的不是utf-8编码,要进行修改
  87. if(FILE_TYPE_CSS == $type)
  88. {
  89.     header ("content-type: text/css; charset: utf-8");
  90. }
  91. else if(FILE_TYPE_JS == $type)
  92. {
  93.     header ("content-type: text/javascript; charset: utf-8");
  94. }
  95.  
  96. // 重要:告诉客户端这个文件的最后修改时间,这样客户端下次访问此文件时,才会将这个时间再发回服务器,以便服务器进行判断
  97. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $fmtime) . ' GMT');
  98. header('Etag: "' . md5($_SERVER['REQUEST_URI']).'"');
  99.  
  100. // 将压缩后的数据发回客户端
  101. echo $output;
  102. ?>

我已经尽量在代码中使用注释来说明其工作了。

将这个文件放到保存CSS/Javascript文件的目录下,然后在需要使用原来的css/javascript文件的地方如下调用:

  1. <link rel="stylesheet" href="http://your.domain.com/css/index.php?css=style.css" type="text/css">

或者这样:

  1. <script src="http://your.domain.com/css/index.php?js=common.css" type="text/javascript">

就可以了。

可能你会问,为什么要这么做?为什么不直接使用Apache的mod_deflate模块来做输出时的压缩呢?原因有三个。

  1. 缺省安装Apache是不会安装mod_deflate模块的,如果你的代码跑在一台你不能触及Apache设置的主机上,你将不得不用这里的办法;
  2. 这样可以让我们在编写代码时,尽量加入注释,以便使得代码自我解释,方便多人(或者自己在将来的某个时刻)进行维护,而注释在输出的时候,可以用PHP字符串处理功能干掉;
  3. 更重要的是,我们可以将多个css文件或者多个js文件一次性输出到客户端;

太晚了,第三点的详细解释随后补上,睡觉去了~~~zz~~ZZZ

[2009-12-12 继续补充]

我们知道,HTTP通讯协议其实是一个很“昂贵”的协议,每次访问服务器上的单个资源,都需要重新经过一次协议握手,其中客户端向服务端发送的请求数据,还包括cookies的内容,以及很多附加的有用数据。而一个页面一般是由多个资源构成的,例如页面文件本身、css文件、js文件、图片文件等等。我们应该尽量减少资源的数量和体积,来减少客户端与服务端的交互。

考虑到现今的网页,一般都会使用多个css文件来控制页面布局及外观。其实,完全可以将其合并为一个文件,这样客户端也就只需要发送一次请求即可。我们可以采用下面的方法:

  1. <link rel="stylesheet" href="http://your.domain.com/css/index.php?css=layout.css,style.css,color.css" type="text/css">

这样,我们一次性将服务器上的三个css文件发送给客户端了(当然,代码要略作调整,需要内部分解参数,然后读取三个文件到一个buffer中,再压缩输出,还要考虑最后更新时间采用哪个文件的,等等,不过这都是小问题)。

js文件也可如此处理。

目前有一个评论!


  1. 匿名 说:

    牛!

敬请留言:

您可以使用下列XHTML标签:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>