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_en
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>
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.
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));
}
?>
You should be able to use:
<?php header("Transfer-Encoding: chunked");
but you'll have to ensure yourself that the output follows the specifications.
I needed to do two additional things to get this to work. Call ob_start if an object had not yet been started. And also echo out a long empty string. The browser requires a certain amount of content to be sent in it's first chunk it appears.
header('Content-Encoding', 'chunked');
header('Transfer-Encoding', 'chunked');
header('Content-Type', 'text/html');
header('Connection', 'keep-alive');
if (ob_get_level() == 0) ob_start();
echo str_pad('',4096)."\n";
ob_flush();
flush();
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');