我在尝试使用php输出压缩时遇到问题,我已经搜索了许多小时,但仍然没有任何线索...
让我们看一个简单的脚本:
<?php
$response = "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh";
if(function_exists('ob_gzhandler'))
{
ob_start('ob_gzhandler');
}
else {
ob_start();
}
echo $response;
ob_end_flush();
这是我在互联网上发现的一种方法,它曾经对我有用……但现在已经不复存在了(我也不知道为什么)。
如果我在调用此脚本时查看http header :
要求 :
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;
响应 header 如下(请求 header 始终相同):
回复 :
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 header :
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)时,如果我设置标题“Content-Encoding:gzip”,则webserver/php似乎先将其解压缩,然后再将其发送到浏览器中?这怎么可能 ?
以及为什么将其作为“块状”数据发送而不是设置Content-Length header ?
我尝试在响应中手动设置Content-Length;它没有任何改变(它不会出现在响应头中,我仍然会有一个“块状”响应。
我发现某个地方必须发送“Content-Length” header ,然后再发送其他数据或 header ,以避免“分块”响应,我尝试了一下,但结果仍然相同。
我以为在我的php测试脚本的开头可能是BOM字符有问题,但是它没有BOM编码就保存在UTF-8中,所以我不认为这是问题。
我的开发计算机上(使用wampserver)和生产环境(IIS)中都存在此问题,以前它在两台服务器上均有效。
我在使用多个浏览器时遇到了这个问题,并且检查了我之前用fiddler编写的响应大小。
有人知道问题可能在哪里吗?
提前致谢
最佳答案
如果我是你,我将通过以下 list 。
1 。检查是否安装了zlib
扩展名。ob_gzhandler
needs the zlib
扩展名可以正常工作。没有它,它只会默默地退回到默认设置。
2 。确认不要在zlib.output_compression
中启用 php.ini
。
如here所述,即使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压缩之外,还没有使用上述所有内容。这只会导致输出为 double gzip压缩的,这很可能会使混淆浏览器的。
关于PHP-输出压缩问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35018386/