I have a long-running script and want to use output buffering to send output to the browser periodically.
I'm confused, because I've read a number of questions on here that said to use this:
while (...) {
ob_start();
// echo statements
ob_end_flush();
}
But that didn't work for me. I also tried this:
while (...) {
ob_start();
// echo statements
ob_flush();
flush();
ob_end_flush();
}
But that didn't work either. The only thing that seems to work is this:
while (...) {
ob_end_clean();
ob_start();
// echo statements
ob_flush();
flush();
}
Why do I have to call ob_end_clean() first in order for output buffering to work?
Probably it depends on the rest of your code.
For me the following code works without a problem:
<?php
header( 'Content-type: text/html; charset=utf-8' );
$x = 1;
while ($x < 10) {
echo $x."<br />";
ob_flush();
flush();
sleep(1);
++$x;
}
You can use ob_implicit_flush() but it makes you don't need to run flash() each time you run ob_flush() so above code can be changed to:
<?php
header( 'Content-type: text/html; charset=utf-8' );
$x = 1;
ob_implicit_flush(true);
while ($x < 10) {
echo $x."<br />";
ob_flush();
sleep(1);
++$x;
}
You should also look at your header(). If in any of above codes I remove/comment line with header all the content will be displayed after scripts ends execution. Output buffering won't work as expected
You do it the wrong way. This will do it:
while (...) {
// echo statements
flush();
}
Make sure, your Webserver is configured to delegate the Output without own cache. Output Buffer ob_start is only needed, if you want to get the output later as string.
Also take a look at ob_implicit_flush, which will automaticly perform a flush on output.
Related
I have a index.php file as below:
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // optional
ob_start();
for($i=1; $i<100; $i++) {
echo $i . "."; echo ('Text the user will see'); echo '<br>';
}
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Will not work
flush();
// At this point, the browser has closed connection to the web server
// Do processing here
sleep(20);
file_put_contents ('test.txt', 'test', FILE_APPEND);
If i run on browser localhost/index.php its work, because it can show 'text the user will see' on screen and no need wait 20 seconds. But if i call it with ajax like as below:
$.ajax({
url: "index.php"
});
It cant show 'text the user will see' for me. And it is work after waited 20 seconds.
How can i fix them. Thank you
I just tried your code using this jquery code in all major browsers and all worked, they closed the connection and displayed result:
$.ajax({
url: "index.php"
}).done(function(data) {
$('#remote').html(data);
});
<?php
ob_start();
echo "<body><p>Hello "
if ($condition) {
header( "Location: http://www.google.com/" );
exit;
}
echo " World!</p></body>";
ob_end_flush();
?>
When $condition is true I get this:
<body>Hello
What I want is when $condition will be true then go to Google!!!
I don't know what is happening, can you explain or give me a solution!?
Thanks.
Just add ob_end_clean(); before the header call.
Everything should work, just put an ; after echo "<body><p>Hello" and you will be fine..
If I were you, I would have started what might go wrong first then do the processing.
An example
$exit_condition_1 = some_value1;
$exit_condition_2 = some_value2;
if($exit_condition_1 == false){
//Redirect
//Exit
}
if(!$exit_condition_2){
//Redirect
//Exit
}
//start the buffer ob_start()
//show some HTML
//flash the buffer ob_end_clean()
there is no point of starting the buffer then if something goes wrong close it and redirect. Just do value testing at the begining then process the request.
An example: lets say that you want to view a product's info and you have a function that will do that
function view_product($product_id){
if(!$product = getProductById($product_id)){
//product does not exist, redirect
}
if(the user does not have enough access rights){
//show a message maybe
//redirect
}
//everything is alright then show the product info
}
To resolve a similar situation where a function was using ob_start() and there was header("Location: http://www.example.com"); after that but erring "already sent...", I replaced the header(... call with
echo "<script> window.location.href = 'https://www.example.com' </script>"
and it worked in that particular case (all that was needed was a just page redirect anyway).
Something seems wrong with my php script, but I have no idea what it is. The only possible thing that seems to be wrong is something to do with the cache, but I am not sure. Here's my script, I'll tell you what's happened below the code:
<?php
set_time_limit(0);
header('Content-Type:text/event-stream');
$prevmod=$lastmod=filemtime('chattext.txt');
function waitformod(){
global $lastmod;
global $prevmod;
while($prevmod==$lastmod){
usleep(100000);
clearstatcache();
$lastmod=filemtime('chattext.txt');
}
echo 'data:'.file_get_contents('chattext.txt').PHP_EOL.PHP_EOL;
flush();
$prevmod=$lastmod;
}
while(true){
waitformod();
}
?>
This is supposed to be used with the JavaScript EventSource and send the contents of chattext.txt whenever it is modified. The file does not output anything, however. I think it is because of the infinite loop. Is there any way to fix this?
Does something like this work better?
<?php
set_time_limit(0);
header('Content-Type:text/event-stream');
$prevmod = $lastmod = filemtime('chattext.txt');
function waitformod(){
global $lastmod;
global $prevmod;
while($prevmod == $lastmod) {
usleep(100000);
clearstatcache();
$lastmod = filemtime('chattext.txt');
}
echo 'data:'.file_get_contents('chattext.txt').PHP_EOL.PHP_EOL;
flush();
$prevmod = $lastmod;
}
while(1) {
waitformod();
}
Your current code looks like it reads the file, outputs it, waits for it to change, and then terminates.
I was trying to get codeigniter to output text as the script was working but couldn't get it to work. I have search on here and google and seen using ob_end_flush(); and flush(); and also along with adding more bytes so the browser can output. But none of that is working in CI 2.x. If anyone has had luck with this, thanks in advance
I have tried
function test()
{
ob_end_flush();
echo "test1";
ob_start();
sleep(3);
ob_end_flush();
echo "test1";
ob_start();
sleep(3);
ob_end_flush();
echo "test1";
ob_start();
}
With no luck. The script waits 6 seconds then spits everything out at once. I would like it to echo the output to the screen then wait 3 seconds then output the next echo then wait another 3 seconds etc.
I tried this today and didn't worked either. Then I looked at the core's output class and there was a private _display() function. I figured that the output is collected before it's displayed into some variable then at last this function is called. So before my code in the controller method, I added this line:
$this->output->_display("");
and then ran the code. It worked. So your modified function would be like this :
function test()
{
$this->output->_display("");
ob_end_flush();
echo "test1";
ob_start();
sleep(3);
ob_end_flush();
echo "test1";
ob_start();
sleep(3);
ob_end_flush();
echo "test1";
ob_start();
}
The issue you're having with Code Igniter specifically is that there is already an output buffer in effect. Preceding your test with the following snippet will get you out of php-level buffering at least:
// try to bust out of output buffering
while(ob_get_level()) {
ob_end_flush();
}
ob_end_flush();
As noted by #Wesley, this can still be undermined by your server's configuration, but in my current setup I can stream output back after busting out of all output buffers.
check your server api with
echo phpinfo();
if you found your server api
Server API : CGI/FastCGI
in CentOS Add below line in "/etc/httpd/conf.d/fcgid.conf"
OutputBufferSize 0
Restart your Apache server and try below code
ob_start();
for($i = 0; $i < 10; $i ++) {
echo $i;
echo '<br />';
flush();
ob_flush();
sleep(1);
}
Code:
echo "1";
sleep(1);
echo "2";
sleep(1);
echo "3";
What am trying to do is have the script echo "1" in the screen wait for one second then display "2" etc... As is the script waits for 2 seconds then displays all content at one. All i know about this is that it has do to with buffering
Disable output buffering by flushing at the beginning of script, and activate implicit output buffer flushing. This should do it:
ob_implicit_flush(true);
ob_end_flush();
for ($i=0; $i<5; $i++) {
echo $i.'<br>';
sleep(1);
}
Use ob_start(); to catpure the output in combination with ob_flush(); flush(); to send it out to the browser, periodically.
So your example would become:
ob_start();
echo "1";
ob_flush(); flush();
sleep(1);
echo "2";
ob_flush(); flush();
sleep(1);
// ...
I don't think this is the classy way to do something like this. These kind of stuff needs to be done in client side with javascript not server side with php.