Final update
Seems like I did make a very simple error. Since I already have a stream implementation I can just not start reading from the stream :D
I'm trying to achieve fire-and-forget like functionality in PHP.
From php.net
<?php
ignore_user_abort(true);
header("Content-Length: 4");
header("Connection: Close");
echo "abcd";
flush();
sleep(5);
echo "Text user should not see"; // because it should have terminated
?>
This works if I open the script with a browser. (shows "abcd").
But if I open it with file_get_contents
or some stream library it will wait for ~5 seconds and show the second text as well.
I'm using PHP 5.2.11 / Apache 2.0
Update
I seems there is some confusion about what I'm trying to accomplish.
I don't want to hide output using output buffers (that's stupid). I want to have the client terminate before the server starts a possibly lengthy process (sleep(5)
) and I don't want the client to wait for it (this is what fire-and-forget means, sort off).
The use of output buffers is merely a side effect. I've amended the sample code without the use of output buffers.
What I don't understand is: why does this script behave differently when accessing it from the browser vs. fetching it in PHP with file_get_contents("http://dev/test.php")
or some stream library? What I've seen in testing is that for开发者_如何转开发 instance stream_get_contents
will actually block for 5 seconds before it returns any output at all, the is quite the opposite of what I want.
Update2
Some more results:
- The browser somehow responds to the
flush()
. I can't figure out how to replicate this behavior with streams in PHP, my streams keep blocking. - I've tried
fread
and found that it behaves similar tostream_get_contents
. - Specifying a
maxlength
has no effect, it will still block for ~5 seconds. - Changing the blocking mode has no effect (other than generating a bunch more calls
to stream_get_contents()
). It will wait ~5 seconds before returning anything. stream_set_read_buffer
has no effect (tested on a PHP 5.3.5 sever)
The second portion of text is showing up because you're stopping output buffering with ob_end_flush()
and ob_end_clean()
. When that happens PHP outputs content as normal. Try something like the following:
<?php
ob_start(); // turn on output buffering
print "Text the user will see.";
ob_flush(); // send above output to the user and keep output buffering on
print "Text the user will never see";
ob_end_clean(); // empty the buffer and turn off output buffering. your script should end here.
?>
It's important for ob_end_clean()
to appear at the end of the script. It empties the buffer and does not send its contents to the user, thus keeping everything after ob_flush()
hidden.
How do you access the script using file_get_contents? How do you access it with your browser? If you access the script without "http://", of course it will never get executed. Use the same URL as in the browser.
Edit:
The browser will render the page even before the connection is closed. Even if you flush, I don't think the connection is closed. You can fire up Wireshark and check. stream_get_contents and file_get_contents will block until they have all the output. Even if you flushed, they can't be sure that there isn't more content. Since the content-length header didn't seem to make {file,stream}_get_contents return earlier, you probably need to implement your own buffering, ala. fopen, read, fclose.
Seems like I did make a very simple error. Since I already have a stream implementation I can just not start reading from the stream :D
精彩评论