PHP: Streaming
I need to check large database on server and show checked percent on client. In simple way i just need to get response from server after each second, so i tried.
Use HTTP Streaming
test.php
echo 'Start ';
for ($i = 1; $i <= 10; ++$i) {
echo $i.str_repeat(' ', 8192);
ob_flush();
flush();
sleep(1);
}
echo 'End';
open test.php in browser we will see that php print number after each second.
PHP not push anything to browser until it's buffer is full (PHP buffer is about 8kb, server and browser have buffer size too, also about 8kb and it work same way with php buffer).
So we need str_repeat(' ', 8192) to fill buffer each time.
They said that ob_flush(); and flush(); will push data to browser but it not seem to work for me, even i already try some config like:
// code from here http://stackoverflow.com/a/7975179
// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
// Get the curent level
$level = ob_get_level();
// End the buffering
ob_end_clean();
// If the current level has not changed, abort
if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
PHP auto push to browser because buffer is full in each time,
and because if we remove str_repeat(' ', 8192), that code will not work.
I still use ob_flush(); and flush(); to be sure.
Use Ajax Atreaming (XHR Streaming)
The only diffirence with HTTP Streaming is we use xhr request rather than http request. That mean we use ajax to request (request in ajax is xhr request) to test.php rather than access test.php direct by browser. index.php
<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script>
var last_response_len = false;
$.ajax({
type: 'GET',
url: 'test.php',
xhrFields: {
onprogress: function(e)
{
var this_response, response = e.currentTarget.response;
if(last_response_len === false) {
this_response = response;
last_response_len = response.length;
} else {
this_response = response.substring(last_response_len);
last_response_len = response.length;
}
$('body').append(this_response.trim() + ' ');
}
}
});
</script>
open index.php in browser and we got same result.
Use WebSocket (the best way)
// TODO