压缩HTML,CSS和...的最佳方法JS已禁用mod_deflate和mod_gzip

时间:2008-09-07 16:23:12

标签: php html apache compression

我在运行Apache 2的共享主机上有几个站点。我想压缩传递给浏览器的HTML,CSS和Javascript。主机已禁用mod_deflate和mod_gzip,因此这些选项已经用完。不过我可以使用PHP 5,所以我可以使用它的gzip组件。

我目前将以下内容放在我的.htaccess文件中:

  

php_value output_handler ob_gzhandler

但是,这只会压缩HTML并省略CSS和JS。

是否有一种可靠的方式透明地压缩CSS和JS的输出而无需更改每一页?我搜索过谷歌并提供了一些解决方案,但我还没有找到一个解决方案。如果有人可以提出他们知道可行的解决方案,那将非常感激。

注意, The Definitive Post on Gzipping your CSS 中的方法2 看起来是一个很好的解决方案,但我无法让它发挥作用。还有其他人成功使用过这种方法吗?

5 个答案:

答案 0 :(得分:7)

对于延迟感到抱歉 - 这对我来说是忙碌的一周。

假设:

  • .htaccesscompress.php
  • 位于同一文件中
  • 要压缩的静态文件位于static子目录

我通过在.htaccess中设置以下指令开始我的解决方案:

RewriteEngine on
RewriteRule ^static/.+\.(js|ico|gif|jpg|jpeg|png|css|swf)$ compress.php [NC]

您的提供商必须允许您覆盖mod_rewrite个文件中的.htaccess个选项。 然后compress.php文件本身可能如下所示:

<?php

$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );

if( !file_exists($file) && strpos($file, $basedir) === 0 ) {
    header("HTTP/1.0 404 Not Found");
    print "File does not exist.";
    exit();
}

$components = split('\.', basename($file));
$extension = strtolower( array_pop($components) );

switch($extension)
{
    case 'css':
        $mime = "text/css";
        break;
    default:
        $mime = "text/plain";
}

header( "Content-Type: " . $mime );
readfile($file);

您当然应该在switch语句中添加更多mime类型。我不想让解决方案依赖于pecl fileinfo扩展或任何其他神奇的mime类型检测库 - 这是最简单的方法。

至于保护脚本 - 我会对文件系统中的实际路径进行转换,因此不会破解“../../../etc/passwd”或其他shellcript文件路径。< / p>

那是

$basedir = realpath( dirname($_SERVER['SCRIPT_FILENAME']) );
$file = realpath( $basedir . $_SERVER["REQUEST_URI"] );

片段。虽然我非常确定其他层次结构中除了$ basedir之外的大多数路径都会在它们到达脚本之前由Apache处理。

另外,我检查生成的路径是否在脚本的目录树中。 像pilif建议的那样添加缓存控制的标题,你应该找到解决问题的方法。

答案 1 :(得分:4)

我的所作所为:

  • 我将脚本分别放在jscss目录中的样式表中。
  • 在Apache配置中,我添加如下指令:

    <Directory /data/www/path/to/some/site/js/>
        AddHandler application/x-httpd-php .js
        php_value auto_prepend_file gzip-js.php
        php_flag zlib.output_compression On
    </Directory>
    <Directory /data/www/path/to/some/site/css/>
        AddHandler application/x-httpd-php .css
        php_value auto_prepend_file gzip-css.php
        php_flag zlib.output_compression On
    </Directory>
    
  • js目录中的gzip-js.php如下所示:

    <?php
        header("Content-type: text/javascript; charset: UTF-8");
    ?>
    
  • ... css目录中的gzip-cs.php如下所示:

    <?php
        header("Content-type: text/css; charset: UTF-8");
    ?>
    

这可能不是最优雅的解决方案,但它肯定是一个简单的解决方案,只需要很少的改动并且效果很好。

答案 2 :(得分:1)

您可以通过mod_rewrite试试运气。

创建一个脚本,该脚本将本地静态文件名作为输入,例如, $_SERVER['QUERY_STRING']并以压缩形式输出。许多提供商不允许使用mod_rewrite文件配置.htaccess,或者完全禁用它。

如果您之前没有使用重写,我建议您使用优秀的初学者指南,例如this one。 这样,您可以使apache将所有静态文件请求重定向到php脚本。例如,style.css将被重定向到 compress.php?style.css

对于您接受的输入始终非常谨慎,或者您手上有XSS漏洞!

答案 3 :(得分:1)

无论你做什么,都要小心客户端的缓存:

浏览器会尝试各种技巧来最小化带宽,HTTP协议中有很多方法可以做到这一点,所有这些都是由apache处理的 - 如果你只是服务于本地文件。

如果你不是,那么这是你的责任

至少看一下所有当前浏览器都支持的ETag和If-Modified-Since机制,似乎是查询服务器获取更新内容的最强大的方法。

使用If-Modified-Since-Header向浏览器提供CSS文件的一种可能方法是这样的(关闭PHP默认发送的任何非缓存头的空头):

$p = 'path/to/css/file'
$i = stat($p);
if ($_SERVER['HTTP_IF_MODIFIED_SINCE']){
    $imd = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if ( ($imd > 0) && ($imd >= $i['mtime'])){
        header('HTTP/1.0 304 Not Modified');
        header('Expires:');
        header('Cache-Control:');
        header('Last-Modified: '.date('r', $i['mtime']));
        exit;
    }
}
header('Last-Modified: '.date('r', $i['mtime']));
header('Content-Type: text/css');
header('Content-Length: '.filesize($p));
header('Cache-Control:');
header('Pragma:');
header('Expires:');
readfile($p);

代码将使用浏览器发送的if-modified-since-header来检查自浏览器发出之日起服务器上的实际文件是否已更改。如果是这样,则发送文件,否则返回304 Not Modified,浏览器不必重新下载整个内容(如果它足够智能,它也会将解析后的CSS保留在内存中)。

还有另一种机制,涉及服务器为每个内容发送一个唯一的ETag-Header。客户端将使用If-None-Match标头发送回来,允许服务器不仅决定上次修改的日期,还决定内容本身。

这只会使代码更复杂,所以我把它留了出来。 FF,IE和Opera(也可能是Safari)都会在收到带有Last-Modified标头的内容时发送If-Modified-Since标头,所以这样可以正常工作。

另请注意,某些版本的IE(或其使用的JScript-Runtime)仍然存在GZIP传输内容的问题。

喔。我知道这不是问题的一部分,但Acrobat在某些版本中也是如此。我在使用gzip传输编码提供PDF时遇到了白屏的案例和案例。

答案 4 :(得分:1)

当用户请求CSS和JavaScript文件时,您可以动态地抓取它们,而不是动态gzip。只要Apache使用正确的标题为它们服务,你就是金色的。

例如,在Mac OS X上,在命令行上压缩文件非常简单:

gzip -c styles.css > styles-gzip.css

可能不是那种适合你的工作流程。