headers_sent会告诉我何时将输出发送到浏览器。然而,可能没有发送任何身体,例如302重定向。
如何在register_shutdown_function上下文中说明哪些内容已发送到浏览器,或至少是Content-Length
内容。
答案 0 :(得分:1)
如果是PHP脚本,则apache不会设置内容lenght标头。这是因为网络服务器无法知道这一点,因为内容是动态创建的。但是标题必须在之前发送。因此,获取内容长度的唯一方法是生成它,获取它的长度,发送标题然后发送内容。
在PHP中,您可以使用ob_*
一组函数(输出缓冲)来实现此目的。像这样:
ob_start();
echo 'hello world'; // all your application's code comes here
register_shutdown_function(function() {
header('Content-Length: ' . ob_get_length());
ob_end_flush();
});
警告如果您使用gzip
编码转移,这将不可靠。已发布a workaround on the PHP web site,
此外,您可能需要知道输出缓冲区可以嵌套在PHP中。如果我上面的例子中有另一个ob_start()
调用,那么你最终会在浏览器中看不到任何内容,因为只有内部缓冲区被刷新(进入外部缓冲区)
以下示例对此进行了处理。为了简化过程,它只是多次覆盖标题,这不应该是性能问题,因为header()
基本上是一个简单的字符串操作。 PHP 仅在某些输出之前或脚本末尾发送标题。
以下是经过测试的gzip安全代码,并且嵌套的非闭合缓冲区可靠运行:
ob_start('ob_gzhandler');
echo 'hello world';
// another ob_start call. The programmer missed to close it.
ob_start();
register_shutdown_function(function() {
// loop through buffers and flush them. After the operation the
// Content-Lenght header will contain the total of them all
while(ob_get_level()) {
header('Content-Length: ' . ob_get_length(), TRUE);
ob_end_flush();
}
});