How to make PHP generate Chunked response

2019-01-06 12:08发布

I googled for this problem but there is no answer for it.

I want my PHP script to generate HTTP response in chunked( http://en.wikipedia.org/wiki/Chunked_transfer_encoding). How to do it?

Update: I figured it out. I have to specify Transfer-encoding header and flush it.

header("Transfer-encoding: chunked");
flush(); 

The flush is necessary. Otherwise, Content-Length header will be generated.

And, I have to make chunks by myself. With a helper function, it is not hard.

function dump_chunk($chunk)
{
    echo sprintf("%x\r\n", strlen($chunk));
    echo $chunk;
    echo "\r\n";
}

9条回答
smile是对你的礼貌
2楼-- · 2019-01-06 12:29

A PHP response will always be chunked if you don't specify a content-length header, and a flush occurs. (which will happen automatically after x bytes, just don't know exactly how much).

This is a weird thing to care about. Is this some kind of academic/learning exercise or is there a real world problem you're trying to solve?

查看更多
做自己的国王
3楼-- · 2019-01-06 12:29

The output buffer will not be sent to the browser until it is full. The default size is 4096 bytes. So you either need to change the buffer size or pad your chunks. Also, the browser may have it's own minimum buffer before the page is displayed. Note that according to the Wikipedia Article about chunked encoding, sending a 0\r\n\r\n chunk terminates the response.

If you want to change the output buffering size setting, I read that you cannot use ini_set('output_buffering', $value). Instead, change the output buffering setting by adding the following to your php.ini file.

php_value output_buffering 1024

Here's an example of padding your chunks

header("Transfer-Encoding: chunked");
header("Content-Encoding: none");

// Send chunk to browser
function send_chunk($chunk)
{
    // The chunk must fill the output buffer or php won't send it
    $chunk = str_pad($chunk, 4096);

    printf("%x\r\n%s\r\n", strlen($chunk), $chunk);
    flush();
}

// Send your content in chunks
for($i=0; $i<10; $i++)
{
    send_chunk("This is Chunk #$i.<br>\r\n");
    usleep(500000);
}

// note that if you send an empty chunk
// the browser won't display additional output
echo "0\r\n\r\n";
flush();

Here's a short version that demonstrates 0\r\n\r\n\ terminating the output:

$output = "hello world";
header("Transfer-Encoding: chunked");
header('Content-Encoding: none');
printf("%x\r\n%s\r\n", strlen($output), $output);
ob_flush();
print("0\r\n\r\n");
ob_flush();
flush();
sleep(10);
print('POST PROCESSING');
查看更多
女痞
4楼-- · 2019-01-06 12:31

You should be able to use:

<?php header("Transfer-Encoding: chunked");

but you'll have to ensure yourself that the output follows the specifications.

查看更多
smile是对你的礼貌
5楼-- · 2019-01-06 12:31

Andriy F.'s solution worked for me. Here's a simplified version of his answer:

function dump_chunk($chunk)
{
    echo $chunk;
    flush();
    ob_flush();
}

header('Content-Type: text/html; charset=UTF-8');

flush();

for ($i = 0; $i < 3; $i++) {
    dump_chunk('Sending data chunk ' . ($i + 1) . ' of 1000 <br />');
    sleep(1);
}

Although I don't understand why the ob_flush() call is needed. If someone knows, please comment.

查看更多
地球回转人心会变
6楼-- · 2019-01-06 12:35

Working sample as of 16.02.2013

<?php

function dump_chunk($chunk) {
    //echo sprintf("%x\r\n", strlen($chunk));
    echo sprintf("\r\n");
    echo $chunk;
    echo "\r\n";
}

ob_start();
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Title</title>
    </head>
    <body>
        <?php
        ob_end_flush();
        flush();
        ob_flush();
        for ($i = 0; $i < 5; $i++) {
            sleep(1);
            dump_chunk('Sending data chunk ' . ($i + 1) . ' of 1000 <br />');
            flush();
            ob_flush();
        }
        sleep(1); // needed for last animation
        ?>
    </body>
</html>
查看更多
相关推荐>>
7楼-- · 2019-01-06 12:36

This has gotten a little vauge... if you don't mind big assed chunks, (0x1000 octets or so), then yes, PHP will make them.

<?php

while (true) {
    # output data
    flush()
    usleep(pow(2,18));
}
?>

PHP will generated the numbered sections, etc.

If you want to send tiny little chunks, as you might do with an AJAX client... well, I've combined the OPs question, with some research on PHP.NET, and it does look like he was on to a good thing.

$ echo -en "GET /chunked/ HTTP/1.1\r\nHost: ec\r\n\r\n" | nc localhost 80

HTTP/1.1 200 OK
Date: Wed, 23 May 2012 13:03:01 GMT
Server: Apache/2.2.9 (Debian) PHP/5.3.5-1 with Suhosin-Patch mod_ssl/2.2.9 OpenSSL/0.9.8o
X-Powered-By: PHP/5.3.5-1
Transfer-encoding: chunked
Content-Type: text/html

14
Teachers have class.
50
We secure our friends not by accepting favors but by doing them.
            -- Thucydides
48
Vulcans never bluff.
            -- Spock, "The Doomsday Machine", stardate 4202.1
31
All kings is mostly rapscallions.
            -- Mark Twain
41
Reappraisal, n.:
    An abrupt change of mind after being found out.
49
He who knows, does not speak.  He who speaks, does not know.
            -- Lao Tsu

Whether or not it will eventually squeeze out it out's own (incorrect) chunk count, remains to be seen... but I saw no sign of it.

<?php
header("Transfer-encoding: chunked");
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)  ob_end_flush();
ob_implicit_flush(1); flush();

function dump_chunk($chunk)
{
  printf("%x\r\n%s\r\n", strlen($chunk), $chunk);
  flush();
}

for (;;) {
  $output = array();
  exec("/usr/games/fortune", $output);
  dump_chunk(implode("\n", $output));
  usleep(pow(2,18));
}
?>
查看更多
登录 后发表回答