PHP script doesn't exit on browser exit
Asked Answered
D

2

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.

Dreher answered 14/7, 2011 at 19:24 Comment(1)
You're ignoring user abort while not doing any sort of output to the client.Lutist
U
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.

Upwards answered 14/7, 2011 at 19:27 Comment(4)
@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.Lutist
@Paul: Thanks it works! But does some data is actually sent from server to client this way?Dreher
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()Upwards
I mean before the abort (client closes the browser). Well, according to wireshark data is actually sent: *.... Anyway this fix my problem, thank you!Dreher
H
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.

Helicopter answered 14/7, 2011 at 19:32 Comment(3)
That explains set_time_limit, writing something doesn't make any changes.Dreher
Writing to the output is needed to trigger the user abort sensing IIRC. -- php.net/manual/en/features.connection-handling.phpLutist
@Lutist Yes, of course random local files have no effect on TCP connections. Updated.Helicopter

© 2022 - 2024 — McMap. All rights reserved.