PHP 手动 GZip 编码
我正在使用 Page Speed 测试我的网站,结果约为 70/100。启用压缩是减慢速度的第一个也是最重要的因素。
我知道我可以通过修改 php.ini 以自动执行此操作,但我对手动方法(gzencode
)更感兴趣。
问题是所有浏览器都无法打开网站(Firefox:“无法显示您尝试查看的页面,因为它使用了无效或不受支持的压缩形式。”,Chrome:“303,ERR 内容编码”等。 )或者它们显示编码的字符串。
Live Headers 显示浏览器接受编码,并且响应已设置内容类型,但仍然失败。
GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 5827
Vary: Accept-Encoding
private function _compress($data) {
//return trim(preg_replace(array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'), array('>','<','\\1'), $data));
$supportsGzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
ob_start();
if ($supportsGzip) {
echo gzencode(trim(preg_replace('/\s+/', ' ', $data)), 9);
} else {
echo $data;
}
$content = ob_get_contents();
header("content-type: text/html; charset: UTF-8");
header("cache-control: must-revalidate");
$offset = 60 * 60;
$expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($expire);
header('Content-Length: ' . strlen($content));
header('Vary: Accept-Encoding');
ob_end_clean();
echo $content;
}
如果我将内容编码更改为 zlib,我会得到编码的字符串:
‹������ÕZÿsÛ¶ÿW^‘¥²o‘¨/–-Ë–Ú؉_Ôµ•õÚ_v I°I‚!A©j–Öºnçÿb·»%ÍÚë²nëå?‘þ›=€¤L)’,ÛIw>ŸEâxïáƒ÷°ùÞ½O¶Ÿï߇Žtlؼµ·» $kŸ•¶ ã^ã<܃•\¾� Ÿº—\¸Ô6ŒûŽ”^Õ0z½^®WÊ ¿m4ÅjÅ°…XÎ’©Ã¦ænS·]#ÌÕF-|8LRPL²ìIÈ»5²-\É\™mô=FÀŒJ5"Ù—RóÝ�³Cý€ÉZ([ÙŠb%¹´YýÑãáîcx}±iD´˜¿KV#4”á§x>¬°à®íÒ ãpÅËæî1øÌ®‘@öm
我不再关心压缩,因为我想知道为什么它不起作用。
干杯,
I was testing my website with Page Speed and the result was around 70/100. Enable Compression was the first and most important factor in slowing it down.
I know that I can do that by modifying the php.ini to automatically do that but I was more interested in the manual method (gzencode
).
The problem is either all browsers fail in opening the website (Firefox: "The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.", Chrome: "303, ERR Content Encoding", etc.) or they display the encoded string.
Live Headers shows that the browser accepts the encoding, and the response has the content type set, but it still fails.
GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 5827
Vary: Accept-Encoding
private function _compress($data) {
//return trim(preg_replace(array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'), array('>','<','\\1'), $data));
$supportsGzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
ob_start();
if ($supportsGzip) {
echo gzencode(trim(preg_replace('/\s+/', ' ', $data)), 9);
} else {
echo $data;
}
$content = ob_get_contents();
header("content-type: text/html; charset: UTF-8");
header("cache-control: must-revalidate");
$offset = 60 * 60;
$expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($expire);
header('Content-Length: ' . strlen($content));
header('Vary: Accept-Encoding');
ob_end_clean();
echo $content;
}
If I change the Content-Encoding to zlib, I get the encoded string:
‹������ÕZÿsÛ¶ÿW^‘¥²o‘¨/–-Ë–Ú؉_Ôµ•õÚ_v I°I‚!A©j–Öºnçÿb·»%ÍÚë²nëå?‘þ›=€¤L)’,ÛIw>ŸEâxïáƒ÷°ùÞ½O¶Ÿï߇Žtlؼµ·» $kŸ•¶ ã^ã<܃•\¾� Ÿº—\¸Ô6ŒûŽ”^Õ0z½^®WÊ ¿m4ÅjÅ°…XÎ’©Ã¦ænS·]#ÌÕF-|8LRPL²ìIÈ»5²-\É\™mô=FÀŒJ5"Ù—RóÝ�³Cý€ÉZ([ÙŠb%¹´YýÑãáîcx}±iD´˜¿KV#4”á§x>¬°à®íÒ ãpÅËæî1øÌ®‘@öm
I don’t really care anymore about getting the compression as much as I want to know why its not working.
Cheers,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,我认为这是因为你试图压缩一个空字符串。
我按照你提供的脚本获取了它,并在 FF 和 IE 中运行它。
两者都失败了,FF 说存在问题(就像你所描述的)。
然而,我随后注意到 $data 是一个空字符串。
当我在文件顶部设置
$data = "Some test data.";
时,它立即起作用(浏览器显示“Some test data.”),并在 Firebug 中检查,我可以看到正确的标头。编辑: 另外,只是指出,您的
if ($supportsGzip) {
有点奇怪,因为您的 else 条件实际上应该回显$data,而不是<代码>$内容。
编辑:好的,根据您上面修改后的函数,有两个关键问题。
主要问题与您通过调用 ob_end_clean() 清除标头这一事实有关。 PHP 文档 上的评论指出“ob_end_clean() 确实丢弃标头”。
这意味着您在调用 ob_end_clean() 之前设置的任何标头都将被擦除。此外,您修改后的函数也不会发送 gzip 编码标头。
我必须说,这里可能甚至不需要使用 ob_start 和相关函数。尝试以下
操作:这适用于 IE 和 FF,但我没有时间测试其他浏览器。
如果您确实必须使用 ob_start 和相关函数,请确保在调用
ob_end_clean()
后设置标头。Well, I think it's because you're trying to compress an empty string.
I took your script as you gave it, and ran it in FF and IE.
Both failed, and FF said that there was an issue (like you described).
However, I then noticed $data is an empty string.
When I set
$data = "Some test data.";
at the top of the file it worked immediately (browser displayed "Some test data."), and checking in Firebug, I can see the correct headers.Edit: Also, just to point out, your
if ($supportsGzip) {
is a bit odd, because your else condition should actually echo out$data
, not$content
.Edit: Okay, based on your revised function above, there are two key problems.
The primary problem has to do with the fact that you're wiping out your headers by calling
ob_end_clean()
. A comment on the PHP Docs states that "ob_end_clean() does discard headers".This means any headers you set before calling
ob_end_clean()
will get wiped. Also, your revised function doesn't send a gzip encoding header, either.I must say that there is probably no need to even use ob_start and related functions here, either. Try the following:
This works in IE and FF, but I didn't have time to test other browsers.
If you really must use ob_start and related functions, make sure you set your headers after you call
ob_end_clean()
.我建议使用 http://php.net/manual/de/function .ob-gzhandler.php,这对我来说是开箱即用的:
在我的index.php中,我只是将其放在一些输出之前:
并且它对其进行编码!
I'd suggest to use http://php.net/manual/de/function.ob-gzhandler.php, this works out of the box for me:
In my index.php I just place this before some output:
And it encodes it!
一些事情:
您可能想添加另一个标头:
header('Content-Encoding: gzip');
您正在使用 ob_end_clean,它会删除所有回显/打印的内容而不将其发送到浏览器。根据您想要执行的操作,您可能需要使用 ob_flush。
--然后再试一次:)
A few things:
You probably want to add another header:
header('Content-Encoding: gzip');
You are using ob_end_clean, which deletes all echoed/printed content without sending it to the browser. Depending on what you're trying to do, you may want to use ob_flush instead.
To make sure your output is buffered and handled (and compressed if you use PHP's output buffering compression), make sure all echo/print statements are placed BETWEEN the ob_start and ob_flush sttements.
--and then try it again :)