简体   繁体   English

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

[英]How to get Content-Length at the end of request?

headers_sent will tell me when output was sent to the browser. headers_sent会告诉我何时将输出发送到浏览器。 However, it can be that no body was sent, eg 302 redirect. 但是,可能是没有正文被发送,例如302重定向。

How do I tell in register_shutdown_function context what content has been sent to the browser, or at least what was Content-Length . 我如何在register_shutdown_function上下文中知道已将什么内容发送到浏览器,或者至少是什么Content-Length

The content lenght header will no being set by apache if it is a PHP script. 如果内容长度标头是PHP脚本,则不会由apache设置。 This is because the webserver can't know about this as the content is dynamically created. 这是因为在动态创建内容时,Web服务器无法得知。 However the headers have to sent before the body. 但是,标头必须在正文之前发送。 So the only way to get the length of the content is to generate it, obtain it's length, send the header and then send the content. 因此,获取内容长度的唯一方法是生成内容,获取内容长度,发送标头然后发送内容。

In PHP you can use ob_* set of functions (output buffering) to achieve this. 在PHP中,可以使用ob_*函数集(输出缓冲)来实现此目的。 Like this: 像这样:

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

Warning This will be unreliable if you are using gzip encoded transfer. 警告如果您使用的是gzip编码的传输方式,这将是不可靠的。 There has been posted a workaround on the PHP web site , 已经在PHP网站上发布了解决方法

Also you might need to know that output buffers can be nested in PHP. 另外,您可能需要知道输出缓冲区可以嵌套在PHP中。 If there is another ob_start() call in my example above than you'll end up seeing nothing in the browser because just the inner buffer gets flushed (into the outer one) 如果在上面的示例中还有另一个ob_start()调用,那么您最终将不会在浏览器中看到任何内容,因为仅刷新了内部缓冲区(进入了外部缓冲区)

The following example takes care on this. 以下示例对此有所注意。 In order to ease the process it just overwrites the header multiple times, which shouldn't be a performance issue as header() is basically a simple string operation. 为了简化此过程,它只是多次重写标头,这不应该是性能问题,因为header()基本上是一个简单的字符串操作。 PHP sends the headers only before some output or at the end of the script. PHP仅在某些输出之前或在脚本末尾发送标头。

Here comes the code which has been tested gzip safe and works reliable with nested unclosed buffers: 这是经过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();
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM