我在尝试使用 php 输出压缩时遇到问题,我已经搜索了很多小时,但我仍然没有任何线索......
让我们看一个简单的脚本:
<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
if(function_exists('ob_gzhandler'))
{
ob_start('ob_gzhandler');
}
else {
ob_start();
}
echo $response;
ob_end_flush();
这是我在互联网上找到的一种方法,它曾经对我有用......但不再(我不知道为什么)。
如果我在调用此脚本时查看 http 标头:
请求:
Host: 192.168.51.191
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cache-Control: max-age=0
响应:
Connection: Keep-Alive
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:19:07 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: PHP/5.5.12
你可以看到响应没有压缩(Firebird 给了我一个 0.06ko 的响应),服务器使用分块编码发送响应。
我尝试了另一种方法来发送压缩响应:
<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
$replyBody = gzencode($response, 9, FORCE_GZIP);
header("Content-Encoding: gzip");
echo $replyBody;
响应标头如下(请求标头始终相同):
响应:
Connection: Keep-Alive
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:29:01 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
Transfer-Encoding: chunked
X-Powered-By: PHP/5.5.12
如您所见,这与第一种方法中的行为基本相同。
然后如果我尝试这个:
<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
$replyBody = gzencode($response, 9, FORCE_GZIP);
echo $replyBody;
我收到看起来像压缩响应(随机字符)的东西,输出大小为 0.03ko.
这里对应响应 http 标头:
Connection: Keep-Alive
Content-Length: 31
Content-Type: text/html
Date: Tue, 26 Jan 2016 15:32:46 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12
X-Powered-By: PHP/5.5.12
它让我认为压缩部分工作正常,因为输出大小已减小(它显然不可读,因为浏览器无法知道它是压缩内容)。
这就是我迷路的地方...
如果我理解正确,当我手动发送压缩数据(使用 gzencode)时,如果我设置标题"内容编码:gzip",网络服务器/php 似乎在将其发送到浏览器之前将其解压缩???怎么可能?
为什么它将其作为"分块"数据发送而不是设置内容长度标头?
我尝试在响应中手动设置内容长度; 它不会改变任何东西(它不会出现在响应标头中,我仍然会有一个"分块"响应。
我在某处看到我必须在发送其他数据或标头之前编写"Content-Length"标头以避免"分块"响应,我尝试过并且仍然有相同的结果。
我认为这可能是我的 php 测试脚本开头的 BOM 字符的问题,但它在没有 BOM 编码的情况下以 UTF-8 保存,所以我认为这不是问题所在。
我在我的开发计算机(使用 wampserver)和生产环境 (IIS) 上遇到了这个问题,以前它在两台服务器上工作。
我在使用多个浏览器时遇到了这个问题,我检查了我之前用小提琴手写的响应大小。
有没有人看到问题可能在哪里?
提前致谢
如果我是你,我会通过以下清单。
1. 检查是否已安装zlib
扩展。
ob_gzhandler
需要zlib
扩展才能工作。没有它,它只是静默地回退到默认设置。
2. 验证您的php.ini
中是否未启用zlib.output_compression
。
如此处所述,即使zlib.output_compression
优先于ob_gzhandler()
,您也不能同时使用两者。所以你的代码变成了..
if (extension_loaded('zlib') && !ini_get('zlib.output_compression')){
ob_start('ob_gzhandler');
}
3.检查标头是否已发送,例如,在 ob_start(ob_gzhandler)
这将防止压缩输出被检测为这样。例如。在代码中的某个位置<?php
或echo
之前具有某些字符。
4. 确保除了 apache( mod_deflate
中的 gzip 之外,您没有使用上述所有内容。这只会导致输出被双重压缩,这很可能会混淆浏览器。