ob_gzhandler

(PHP 4 >= 4.0.4、PHP 5、PHP 7、PHP 8)

ob_gzhandlerob_start 回调函数,将输出缓冲区压缩到 gzip 格式

说明

ob_gzhandler(string $data, int $flags): string|false

ob_gzhandler() 将用作 ob_start() 的回调函数,用于帮助将 gz 编码数据发送到支持压缩网页的网络浏览器。实际发送压缩数据前,ob_gzhandler() 将确定浏览器接受哪种类型的编码(“gzip”、“deflate”或都不接受),然后根据情况返回输出。支持所有浏览器,因为由浏览器发送正确标头以表明其接受压缩网页。如果浏览器不支持压缩页面,此函数将返回 false

参数

data

flags

返回值

示例

示例 #1 ob_gzhandler() 示例

<?php

ob_start
("ob_gzhandler");

?>
<html>
<body>
<p>这应该是一个压缩页面。</p>
</body>
</html>

注释

注意:

ob_gzhandler() 需要 zlib 扩展。

注意:

不能同时使用 ob_gzhandler()zlib.output_compression。另外请注意,使用 zlib.output_compression 优于 ob_gzhandler()

另请参见

  • ob_start() - 启用输出缓冲
  • ob_end_flush() - 清除(发送)活动输出处理的返回的值并关闭活动输出缓冲

添加说明

用户提交的说明 29 条说明

Jer
14 年前
我刚花 5 个小时来对付我应用程序中的一个错误,结果是

<?php
// 避免使用
ob_start("ob_gzhandler");
// 与
header('HTTP/1.1 304 Not Modified');

// 或最终使用
ob_end_clean();
?>

当设置了 304 头时,W3C 标准要求响应主体为空。如果启用了压缩,即使你的输出完全为空,它至少也会包含一个 gzip 流头。

这会以一种非常微妙的方式影响 Firefox(当前版本 3.6.3):响应主体非空而获取到 304 的请求之一会将其响应置于该主体的前面。在我这个案例中,这是一个 css 文件,导致样式完全无法渲染,这使问题显现出来。
przemekryciuk at gmail dot com
15 年前
实现 gzip 压缩的最简单方法是
<?php
if(!ob_start("ob_gzhandler")) ob_start();
?>
如果浏览器不支持 gzip,ob_start("ob_gzhandler") 将返回 FALSE,然后会调用常规的 ob_start();
daijoubu at videotron dot ca
20 年前
关于 Davey 前面提到的内容

ob_start(array('ob_gzhandler',9));

无效。输出大小完全不受影响,保持不变。

ob_gzhandler 压缩级别使用 zlib.output_compression_level,其默认值为 -1,即级别 6。

要动态更改压缩级别,只需使用 ini_set
<?php
ini_set
('zlib.output_compression_level', 1);
ob_start('ob_gzhandler');
echo
'This is compressed at level 1';
?>
mariusads[at]helpedia[dot]com
18 年前
请注意,正如其他用户已经提到的那样,如果 PHP 开始标签 "< ?" 之前有字符,则压缩会失败。

当使用 Ultraedit 等编辑器以 UTF-8 格式保存文件时也会发生这种情况。请确保使用已定义的选项 UTF-8 NO BOM 保存文件,或删除 BOM,否则这两个 UTF BOM 字符将被写到文件开头。
Tony Piper
19 年前
我刚刚花了 30 分钟 wondering why my browser wasn't getting the gzipped version :-O

如果你正在使用 Google Web Access,除非你告诉 GWA 忽略特定的站点,否则你的页面将解压后传递给浏览器。

显而易见,真的。
m at rtij dot nl
19 年前
所有版本的 MSIE 都有一个 bug,它们不缓存 gzipd 内容。如果你的应用程序依赖于缓存,那么请记住这一点。最后,我做了

<?php

// These are so benificial, they default to true.
if (!isset($use_page_cache))
$use_page_cache = 1;
if (!isset(
$use_compression))
$use_compression = 1;

// Add browsers here as we must detect them. Opera is an oddball, if we don't detect
// it specifically, it will turn up as MSIE

$browser="other";
if (isset(
$_SERVER['HTTP_USER_AGENT'])) {
$agent = $_SERVER['HTTP_USER_AGENT'];
if (
eregi("opera",$agent)){
$browser="opera";
}elseif(
eregi("msie",$agent)){
$browser="msie";
}
}

if (
$use_compression && !( $use_page_cache && $browser == "msie")) {
// Turn on compression, makes quite a difference in bandwith usage.
// However, MSIE (all versions) have a bug with compression and caching. So for MSIE
// it's either compression or caching. We choose caching.
ob_start('ob_gzhandler');
}

session_cache_limiter("must-revalidate");

session_start();

// ... put stuff in $content ...

if ($use_page_cache) {
// MD5 is slow, however with a fast server (PIII or better) we should be OK
$hash = md5($content);
$headers = getallheaders();
if (isset(
$headers['If-None-Match']) && ereg($hash, $headers['If-None-Match']))
{
header('HTTP/1.1 304 Not Modified');
exit;
}
header("ETag: \"$hash\"");
}

print
$content;

?>
jazfresh at SPAM-JAVELIN dot hotmail dot com
20 年前
在 set_error_handler 笔记中,描述了一种技术,用于在向用户显示这些错误之前捕获所有错误(即使是解析错误),使用特殊的错误处理程序和输出处理程序。如果该输出处理程序在输出缓冲区中检测到致命错误,则在向用户显示该错误之前会将其捕获并予以处理。如果未检测到错误,则原样显示输出缓冲区(即不压缩)。

如果你正在使用此方法,你仍然可以使用 ob_gzhandler 的压缩功能。但是,你必须指定一个模式参数(我在 RedHat9 上使用 4.2.2)。模式值会影响自动添加哪些标题(Content-Encoding 等)。对我来说,“5”的值可行。“0”或丢弃参数会导致 Mozilla 下显示空白屏幕。

php?

function my_output_handler(&$buffer) {
// 检测输出中的错误
if(ereg("(error</b>:)(.+) in <b>(.+)</b> on line <b>(.+)</b>", $buffer, $regs)) {
my_error_handler(E_ERROR, $regs[2], $regs[3], $regs[4]);
// ...
// ... 在此处插入你的错误处理...
// ...
return '发生内部错误.';
} else {
// 页面在未出现任何错误的情况下渲染,因此可压缩
// 并输出。
return ob_gzhandler($buffer, 5);
}
}
?p>
xn at bnw dot com
22 年前
如果您在 ob_start("ob_gzhandler") 之后调用 ob_end_clean(),仍然会发送 "Content-Encoding: gzip" 标头(假设浏览器支持此编码)。如果您未再次使用 ob_gzhandler 回调函数调用 ob_start(),则输出不会被压缩,但标头会说它已压缩。这样会导致 Mozilla(截至版本 2002032808)显示空白页。
maratd at gmail dot com
16 年前
有人之前提到过 MSIE 不会缓存压缩内容。这是错误的。他对信息来源误读了。事实上, IE 无论如何都会缓存压缩内容。下面是邮件列表中的引用

事实上,COMPRESSED 响应总是获取缓存的原因
无论是否存在 "Vary:" 字段名
正是因为我所怀疑的那样... 这是因为 MSIE
决定它必须缓存以
"Content-Encoding: gzip" 接收的响应,因为它必须有一个
磁盘(缓存)文件以便执行
解压。

来源: http://lists.over.net/pipermail/mod_gzip/2002-December/006826.html
ronald at hidden dot com
15 年前
您好,

如果您正在使用 apache,我认为您最好使用 apache 的压缩功能,因为这也将压缩静态文本文件(css、js、html 等),并且它将保持您的 php 代码清洁。

请参见 https://httpd.apache.org/docs/2.0/mod/mod_deflate.html 以获得优秀的指南。

对于其他 Web 服务器,我敢肯定它们有同等服务器。

致意,罗纳德
lapoint2 at msu dot edu
18 年前
那么为什么 Web 服务器不默认执行此操作呢?
如果我执行以下操作,这对我有效
ini_set('zlib.output_compression_level', 3); ob_start("ob_gzhandler");
或甚至只是
ob_start("ob_gzhandler");

我执行了 3 级压缩,我认为默认值为 6,我不想对服务器施加太大负载。对于 895k 文件(我的最大文件),压缩级别为
1 = 189k
3 = 178k
4 = 163k
6 = 156k(我相信如果您遗漏 ini_set,则 6 为默认值)
9 = 155k
我使用 http://www.whatsmyip.org/mod_gzip_test/ 来检查大小。

供您参考:这适用于 Movable Type 3.x 中的动态文件(我在 3.2 中测试它),我在 mtview.php 文件的第一行中输入了上述命令。

此处获取更多信息: http://www.whatsmyip.org/forum/viewtopic.php?t=43

在几个站点上我读到某些浏览器不喜欢经过压缩的 CSS。
psychones at ifrance dot com
22 年前
[email protected] 揭示的问题

当您进行全局调用时,会产生真实的问题
ob_gzhandler,例如在包含配置中
文件,您希望发送非 gzip 内容,无论出于何种原因...

要解决它,

在全局调用 ob_gzhandler 后放置此代码

include("conf_that_call_ob_gzhandler.php");
-->ob_end_clean();
-->header("Content-Encoding: none");

如果您尝试在 ob_gzhandler 调用
之前或在缓冲输出期间覆盖标头,则它将不起作用。
(在 ob_gzhandler 调用时可能会擦除,在
缓冲期间不允许)。

希望这有帮助
walter
15 年前
在我的框架内有一个经过测试过的模块(即在制作环境中运行了几年),称为“fastpage”,它负责为请求频繁的内容进行缓存和 gzip 压缩。它会分别缓存每个唯一页面的 gzipped 和非 gzipped 版本,然后根据浏览器的“Accept-encoding 标头”返回相应版本。

使用方法是
$page_spec = array($dependent,$variables,$go,$here);
if(!fastpage_display('content_id',$page_spec)) {
... 在此处制作页面 ...
fastpage_displayed('content_id',$page_spec);
}

不幸的是,在 IE8 beta(在 IE8 模式下或在 IE7 仿真模式下),未解压 fastpage 启用的内容。IE 会请求该内容,服务器日志文件会显示 200 状态码和正确的字节数,并且 IE 不会显示任何错误。然而,CSS 不会应用,Javascript 也不会执行。

我目前能找到的唯一方法是完全禁用该浏览器中的 gzip。用户代理字符串是:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727

在 Firefox(Windows、Linux、Mac)和 Safari 中的相同输出运行良好。

版本是:zlib 1.2.3-r1 / php 5.2.6-r7 / lighttpd 1.4.20

上面提到的“已在 IE7 中修复”评论太不靠谱了...
jsnell at e-normous dot com
17 年前
如果您想禁止错误(例如在标头已发送的情况下),而且您不想编写或修补 error_handler,则需要创建一个中间回调

function ob_gz_handler_no_errors($buffer)
{
@ob_gzhandler($buffer);
}

ob_start('ob_gzhandler_no_errors');
nicolas dot grekas+php at gmail dot com
17 年前
以下是有关内容的一些说明

-“mode” arg 接受一个位字段,该字段由 PHP_OUTPUT_HANDLER_START、PHP_OUTPUT_HANDLER_CONT 和 PHP_OUTPUT_HANDLER_END 组成。有关示例,请访问 https://php.net/manual/fr/ref.zlib.php#56216。下方 jazfresh 推荐的值 (5) 是对的,因为 5 == PHP_OUTPUT_HANDLER_START | PHP_OUTPUT_HANDLER_END。

-在输出缓冲处理程序内部调用时,当浏览器不支持压缩页面时,ob_gzhandler 不会返回 false。它反而会返回原始字符串。
spam_this at zleelz dot com
17 年前
在编写脚本进行分发时,我通常会将以下不推荐使用的超级全局变量“置空”,这样使用脚本的用户将无法使用它们。
<?php
$HTTP_GET_VARS
= null;
$HTTP_POST_VARS = null;
$HTTP_COOKIE_VARS = null;
$HTTP_POST_FILES = null;
$HTTP_SERVER_VARS = null;
?>

但是,在使用 ob_start('ob_gzhandler') 时,其中一个超级全局变量不知怎地会禁用此功能。

我发现是 $HTTP_SERVER_VARS 导致了这个问题。

<?php
ob_start
('ob_gzhandler');

$HTTP_GET_VARS = null;
$HTTP_POST_VARS = null;
$HTTP_COOKIE_VARS = null;
$HTTP_POST_FILES = null;
/**
* 引发问题
*/
//$HTTP_SERVER_VARS = null;
?>

我不知道它为什么这样做,我只是想指出这一点。
richard at mf2fm dot com
18 年前
根据手册,如果 ob_gzhander 检测到浏览器无法支持 deflate 或 gzip,它会返回 FALSE。这意味着如果你使用 ob_start("ob_gzhandler"),任何不支持 gzip/deflate 的浏览器都会收到一个空白页面吗?

我在让 IE6 显示压缩页面时遇到了问题并且添加了一个测试

<?php

if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler");

else
ob_start();

?>

ob_gzhandler 检测到对无损压缩无效支持时,应返回输入内容保持不变而不是 FALSE 吗?
mazsolt at yahoo dot com
20 年前
如果您希望将输出发送到接受 GZIP 的浏览器(尚未设置缓冲回调 ob_start("ob_gzhandler")),则可以使用 gzencode() 函数。

header("Content-Encoding: gzip");
echo gzencode("some output", 9, FORCE_GZIP);
brewthatistrue at plzYnoAspamHorOevilO dot com
20 年前
我在尝试正确启用 GZIP 压缩时遇到了很多问题。
第一次载入时一直出现空白页面,但后续页面能正常载入。
我尝试了各种我不明白的 ob_flush 和 ob_end_clean 以及其他内容。我对 PHP 的不同版本以及 GZIP 压缩的不同方法感到彻底困惑。

最后,我让它工作了(也许以后我会明白)。
我最终使用了 phpBB 的代码(剥离了非 GZIP 内容,并进行了微小的修改)。
http://phpbb.com/

index.php
------------
<?php
require_once('top.php');

echo
"<html>\n<head>\n<title>Gzip Test</title>\n<body>\n<h1>testing</h1>\n</body>\n</html>";

require_once(
'bottom.php');
?>

gz_header.php - 取自 phpBB 的 page_header.php
--------------
<?php
$phpver
= phpversion();

$useragent = (isset($_SERVER["HTTP_USER_AGENT"]) ) ? $_SERVER["HTTP_USER_AGENT"] : $HTTP_USER_AGENT;

if (
$phpver >= '4.0.4pl1' && ( strstr($useragent,'compatible') || strstr($useragent,'Gecko') ) )
{
if (
extension_loaded('zlib') )
{
ob_start('ob_gzhandler');
}
}
else if (
$phpver > '4.0' )
{
if (
strstr($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip') )
{
if (
extension_loaded('zlib') )
{
$do_gzip_compress = TRUE;
ob_start();
ob_implicit_flush(0);

header('Content-Encoding: gzip');
}
}
}
?>
gz_footer.php - taken form phpBB's page_tail.php
------------
<?php
// 在需要时压缩缓冲输出并将其发送到浏览器
if ( $do_gzip_compress )
{
//
// 来自 php.net!
//
$gzip_contents = ob_get_contents();
ob_end_clean();

$gzip_size = strlen($gzip_contents);
$gzip_crc = crc32($gzip_contents);

$gzip_contents = gzcompress($gzip_contents, 9);
$gzip_contents = substr($gzip_contents, 0, strlen($gzip_contents) - 4);

echo
"\x1f\x8b\x08\x00\x00\x00\x00\x00";
echo
$gzip_contents;
echo
pack('V', $gzip_crc);
echo
pack('V', $gzip_size);
}

exit;
?>

我必须承认,我没有看到它在 opera 7.11 中工作。也许我会弄清楚这一点。
如果有任何我应该更改的内容,请给我发送电子邮件,我就可以编辑我的帖子
匿名
21 年前
当使用 ob_start("ob_gzhandler") 时,请注意,必须刷新输出缓冲区才能调用 ob_gzhandler 回调函数。

这可能并不总是发生。例如,如果您使用 ob_get_contents() 将输出缓冲区复制到一个字符串中以便进一步操作,然后使用 ob_end_clean() 默默丢弃缓冲区,则输出缓冲区永远不会被“刷新”,因此永远不会调用 ob_gzhandler 回调函数,并且您的页面不会被压缩。

例如,如果您使用 PHP Fusebox 架构/框架,就会出现这种情况。
nospam at 1111-internet dot com
21 年前
zlib.output_compression 和 ob_gzhandler 之间的差异

zlib.output_compression 与脚本执行并行运行 - 从脚本接收到任何输出就开始压缩,并在每次缓冲区(默认 4K)变满时向客户端发送数据。ob_gzhandler(实际上是 'ob_start("ob_gzhandler");')在脚本刷新(或通常是退出)之前不会开始压缩,并且会一次性发送整个压缩文档 - 这会更容易导致延迟的感知。

优点:zlib.output_compression

另一方面,ob_gzhandler 为您提供脚本级控制,允许您有选择性地使用它或在特定情况下设置后再取消设置它。尽管一些文档与此相反,但看起来无法在脚本级设置或取消设置 zlib.output_compression;相反,您必须在全局(php.ini 中)或在您的 Web 服务器配置或 .htaccess 文件中设置它,可能仅使用 FilesMatch 类型机制控制会应用哪些脚本或不会应用哪些脚本 - 对于大型项目这可能会变得难以控制 - 特别是那些使用 PHP 来生成图像以及除正常文本输出外的其他非文本输出的项目。

优势:ob_gzhandler

净优势:取决于您的特定需求。我现在正在尝试 zlib.output_compression,但我怀念 ob_gzhandler 提供的灵活性。

附注,下面是一个展示 zlib.output_compression 条件设置语法的 Apache 1.3.* httpd.conf/.htaccess 文件片段

<FilesMatch "\.(php|html?)$">
# 使用 php_value 打开它,同时将缓冲区设置为 2K
php_value zlib.output_compression 2048
# 或者仅仅使用 php_flag 打开它
# php_flag zlib.output_compression On
</FilesMatch>
dsugar100 at dolphinsoft dot com
21 年前
我注意到,如果您将 zlib.output_compression 的 PHP 设置设置为“开”,并且您尝试使用 ob_gzhandler 处理器对其执行 ob_start () 操作,那么在 PHP 4.2.3 中,您在浏览器中获得的输出将会乱码。我猜测输出缓冲正在压缩将要发送的输出,然后 zlib 再次执行,而浏览器只对其进行一次解压。

但使用任何一种方法,您都将获得相同的结果(来自脚本的压缩输出)
isoma at altavista dot net
22 年前
RFC 2616 建议更正确地压缩文档的方式是使用 gzip 传输编码而不是 gzip 内容编码。然而,可能不建议使用这个方法,因为它对这种方法的客户端支持非常有限。

当您来从浏览器保存文件时,这种差异最为明显。如果它是 gzip 内容编码,那么浏览器应该(而且很可能)保存它为 gzip 格式。如果它是 gzip 传输编码,那么浏览器应该先对它进行解压。
junior at jaj dot com
22 年前
要使其正常工作,您必须使用“--with-zlib”编译 PHP。如果您不这样做,您将不会收到任何错误,它只是不会真正压缩任何东西。这是一个惊人的事情。对于一小段处理器时间,您可以极大地降低您的脚本的带宽需求。在很多情况下这个事项都不应当使用。
davey at its-explosive dot net
21 年前
若要传递指定应使用什么级别的压缩的第二个参数到 ob_gzhandler()(我假设它与压缩二进制一样是 1-9,其中 9 使用最多的处理器和执行时间,4 是标准 IIRC),你必须像下面这样调用 ob_start()

ob_start(array('ob_gzhandler',9));

- Davey
aki at robotnik dot net
21 年前
如果你收到类似
“输出处理程序 'ob_gzhandler' 不能重复使用”
的错误,如果你正在使用
"ob_start("ob_gzhandler");"

检查你的 php.ini 文件,它应该像下面这样

output_buffering = Off ; delete the 4096k value
output_handler =
zlib.output_compression = Off
tehjosh at gamingg dot net
17 年前
faisun at sina dot com
如果你阅读输出缓冲,你将看到如果输出缓冲的回调返回 false,这就指示 PHP 输出原始的未修改的字符串。这就是 ob_gzhandler() 在编码不受支持时返回 false 的原因。当 ob_start("ob_gzhandler") 被使用且编码不受支持时,ob_gzhandler() 将返回 false,PHP 输出原始的未压缩字符串。

jsnell at e-normous dot com
输出缓冲回调函数接受多达两个参数,因此这或许更适合你的情况

<?php
function ob_gz_handler_no_errors($buffer, $mode)
{
@
ob_gzhandler($buffer, $mode);
}

ob_start('ob_gzhandler_no_errors');
?>

然而,如果你尝试取消由已发送的头部引起的错误,在任何输出发送之前,尽早启动输出缓冲会更好。
grange (at) club-internet (dot) fr
19 年前
可能显而易见,但如果你使用 ob_start("ob_gzhandler"),确保不会在前面意外地 echo 任何内容:这可能是 '<?php' 之前的空行或者包含文件或甚至错误中 '?>' 之后的空行。

否则,只有部分内容(ob_start() 之后发送的内容)会被压缩,这会让客户端感到困惑。

使用 php.ini 或 Apache 配置文件(使用 php_flag 指令)中的 zlib.output_compression 设置压缩在这方面更安全。
Anonymous
19 年前
无论是什么环境,你必须不得检查用户代理字符串来了解是否启用了压缩。HTTP 定义了 Accept-Encoding 头正是出于这样的目的,你在启用压缩之前必须检查它。
To Top