6

Why this dummy script keeps running event if the client closes the browser (so the connection to the server)?

while ( true )
{
    sleep( 1 );
    file_put_contents( '/tmp/foo' , "I'm alive ".getmypid()."\n" , FILE_APPEND );
}

It's unexpected to me according to this. Also this example doesn't seem to work.

And set_time_limit with a non-zero parameter simply does nothing.

I'd like some clarifications.

cYrus
  • 2,976
  • 6
  • 29
  • 47

2 Answers2

9

If you try to write some output to the browser in that loop, you should find the script aborts if the connection has been terminated. This behaviour is hinted at in the documentation for ignore_user_abort

When running PHP as a command line script, and the script's tty goes away without the script being terminated then the script will die the next time it tries to write anything, unless value is set to TRUE

I tried a few experiments myself, and found that even if you do attempt some browser output, the script will keep running if the output buffer isn't full yet. If you turn output buffering off, the script will abort when output is attempted. This makes sense - the SAPI layer should notice the request has been terminated when it tries to transmit the output.

Here's an example...

//ensure we're  not ignoring aborts..
ignore_user_abort(false);

//find out how big the output buffer is
$buffersize=max(1, ini_get('output_buffering'));


while (true)
{
    sleep( 1 );

    //ensure we fill the output buffer - if the user has aborted, then the script
    //will get aborted here
    echo str_repeat('*', $buffersize)."\n";

    file_put_contents( '/tmp/foo' , "I'm alive ".getmypid()."\n" , FILE_APPEND );
}

That demonstrates what triggers the abort. If you had a script which was prone to enter an endless loop with no output, you could use connection_aborted() to test whether the connection is still open.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • @cYrus: What have you tried. Please reflect that in your questions code. You need to disable ignore user abort. The default setting is on IIRC. – hakre Jul 14 '11 at 19:50
  • @Paul: Thanks it works! But does some data is actually sent from server to client this way? – cYrus Jul 14 '11 at 20:59
  • Well no, because the connection is aborted! All I'm demonstrating above is that the script won't abort until the SAPI layer attempts to flush the buffer. If you've a specific reason to be checking for client-side abort, check connection_aborted() – Paul Dixon Jul 14 '11 at 21:10
  • I mean before the abort (client closes the browser). Well, according to `wireshark` data is actually sent: `*...`. Anyway this fix my problem, thank you! – cYrus Jul 14 '11 at 22:04
1

set_time_limit only restricts the time spent in php code. Most of the time(I'd guess >99.9%) in your program is spent in system calls, writing data to a file and sleeping.

ignore_user_abort only aborts when you're writing something to the client (not in a local file) - there's simply no way you can distinguish an unused and a terminated connection otherwise in TCP, unless the client excplicitely terminates the connection with an RST packet.

phihag
  • 278,196
  • 72
  • 453
  • 469
  • That explains `set_time_limit`, writing something doesn't make any changes. – cYrus Jul 14 '11 at 19:38
  • Writing to the *output* is needed to trigger the user abort sensing IIRC. -- http://www.php.net/manual/en/features.connection-handling.php – hakre Jul 14 '11 at 19:41
  • @hakre Yes, of course random local files have no effect on TCP connections. Updated. – phihag Jul 14 '11 at 19:46