如何在请求结束时获取Content-Length?

时间:2014-02-12 19:37:52

标签: php

headers_sent会告诉我何时将输出发送到浏览器。然而,可能没有发送任何身体,例如302重定向。

如何在register_shutdown_function上下文中说明哪些内容已发送到浏览器,或至少是Content-Length内容。

1 个答案:

答案 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();
    }
});