Stream output from a PHP script
Call flush() after each line you want delivered immediately. If your
script or its framework has PHP's own output buffering turned on, call
ob_flush() first to empty that layer, then flush() to push the bytes
out of the process.
websocketd --port=8080 php ./count.php
<?php
for ($count = 1; $count <= 5; $count++) {
echo $count . "\n";
flush();
usleep(500000);
}
Connect a client and the five numbers arrive half a second apart. Output buffering explains why a runtime holds output back when stdout is a pipe.
The two layers, and which call empties which
PHP can hold your output in two separate places, and they need different calls.
The first is PHP's own output buffer, an internal store that
ob_start() turns on and that some frameworks and some php.ini
settings turn on for you. While it is active, echo writes into that
store and nothing leaves the process. ob_flush() empties it.
The second is the buffer belonging to the layer underneath, which holds
bytes that have left PHP's output buffer but not yet reached the pipe.
flush() empties that one.
Calling both, in that order, covers either arrangement:
<?php
echo "ready\n";
ob_flush();
flush();
ob_flush() emits a notice if no output buffer is active, so guard it
when you are not sure:
<?php
echo "ready\n";
if (ob_get_level() > 0) {
ob_flush();
}
flush();
If you want no buffering at all rather than a flush at every write, turn it off once at the top instead:
<?php
while (ob_get_level() > 0) {
ob_end_flush();
}
Open the file with <?php, never <?
A file that begins with <? rather than <?php is using the short
open tag, an abbreviated form that PHP only recognises when the
short_open_tag setting is on. That setting is off in a default
installation.
When it is off, PHP does not treat <? as the start of code. It treats
the whole file as literal text and prints your source back out. Your
program never runs.
From websocketd's side nothing looks wrong. Your script produced output, websocketd forwarded it, and the client received it. The symptom is a browser showing PHP source code, or showing output that never changes, which is easy to mistake for a buffering problem when in fact no PHP executed at all.
Always open the file with the full tag:
<?php
echo "this actually runs\n";
Check which configuration is in play with php -i | grep short_open_tag.
The command-line PHP binary often reads a different php.ini from the
one your web server uses, so a script that works under a web server can
still fail here.
Each line needs a trailing newline
websocketd sends a WebSocket message when it reads a newline, so echo
without one leaves the line held rather than sent. echo $count . "\n"
above supplies it. This is a separate requirement from flushing, and
either one alone produces the same silence in the browser. Message
framing
has the rule.
Next
- Output buffering is the reason flushing is necessary.
- Message framing covers the newline requirement.
- Debug a script shows how to see what is really arriving, which distinguishes a short-tag failure from a buffering one immediately.