30

if i call a php file via jquery ajax, that contains a script to do some stuff that takes a while — for instance uploading a big video — and then I close the page: does the php script keep loading the video or not?

Francesco
  • 24,839
  • 29
  • 105
  • 152

5 Answers5

20

See here: http://php.net/manual/en/function.ignore-user-abort.php

int ignore_user_abort ([ bool $value ] )

Sets whether a client disconnect should cause a script to be aborted.

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

There also is a PHP configuration option of the same name: http://php.net/manual/en/misc.configuration.php

By default, if you do nothing, according to the PHP manual the default is to abort the script. http://php.net/manual/en/features.connection-handling.php

NECESSARY UPDATE

It seems I (unknowingly) tricked my way to "reputation points", because I did NOT supply the (correct) answer, but here it is now thanks to testing and continued nudging from "mellamokb":

Quote: "Ok, I took a look at the PHP source code and, if I didn't miss anything, I now have the answer. The "ignore_user_abort" flag is only checked when PHP receive an error trying to output something to the user. So, in my understanding, there is no way to interrupt code which doesn't produce any output."

Okay, I wasn't totally off, but it is important to know that it all depends on whether or not your script produced any output!

If you read THIS, also DO check out the comments below.

Mörre
  • 5,699
  • 6
  • 38
  • 63
  • thanks the ignore-user-abort does exactly what i was looking for – Francesco May 13 '11 at 20:33
  • 1
    @Mörre: OK. I was angry and upset because it went against everything I understood. I'm sorry :) So I had to test it out. Now please explain this. I wrote a PHP script to generate a file every second for 30 seconds. I ran the script from my browser (IE), then after the fifth 5 file, I closed the browser. The script continued to run on the server until all 30 files were generated. Tell me how that reconciles? That's exactly what I thought would happen, and what I was saying in my answer... (which came from experience, I hope is somewhat valuable??) – mellamokb May 13 '11 at 20:39
  • 1
    @Mörre: So then I added `ignore_user_abort(false);` to the top of my PHP script and ran again... same result. Please explain. – mellamokb May 13 '11 at 20:41
  • I have no idea. As I said in several comments I did NOT test it but referred to the docs. In that sense I can't be wrong, only the PHP manual is ;-) Anyway, can you find out (phpinfo() maybe?) what the configuration setting is (if not in php.ini, to find out what's the actual value on your server). – Mörre May 13 '11 at 20:43
  • So what happens with "true" then? I'm curious (as I said in several responses, I don't know, only read the PHP manual). – Mörre May 13 '11 at 20:46
  • 1
    @Mörre: `ignore_user_abort` is set to `Off` (false) in my `phpinfo`... It has always worked this way in PHP, ASP, ASP.Net, CGI, everything. If the browser is closed, and something is stuck in an infinite loop, I have to restart IIS. This is called experience. Furthermore, if you're right, then why do we have all these issues with unclosed sessions and questions on SO and other places about determining if the user has closed their browser? There usually is no solution given (except catching `onbeforeunload` event which doesn't always work - and that's *client* side). – mellamokb May 13 '11 at 20:46
  • @Mörre: Exact same thing happens with `true`. – mellamokb May 13 '11 at 20:49
  • @Mörre: I think the real confusion here is not that a browser is not a TCP/IP connection as I said. I really meant that it acts differently than a TCP/IP connection. Browsers are meant to be stateless, so the communication is not real-time like two applications talking to each other over the Internet. A client requests a page, then waits. The server generates the page, and doesn't talk to the client until the page is ready. You can do stuff like `flush()`, but there's so many layers of buffering that almost always has no effect... So PHP knows nothing until already finished anyway. – mellamokb May 13 '11 at 20:59
  • @Mörre: I think the most insightful explanation that probably says better what I'm trying to say is @ircmaxwell's comment on @Tadeck's post. – mellamokb May 13 '11 at 21:00
  • What would be interesting to know is whether using connection_aborted/connection_status functions inside the script reveals correct (termination) info even in no-output case, so that the script can stop on its own? – Mörre May 13 '11 at 21:03
  • @Mörre: BTW, my test script was also generating output for every file written, and the same thing still happened. It has to be a substantial amount of output, like 4KB or whatever the buffer chunk size is. If you generate lots of output and call every `flush()` method available in the library between operations, you **may** be able to stop the script when you close the browser. Still not guaranteed in any way. – mellamokb May 13 '11 at 21:03
  • @Mörre: I tried everything I could. I used `ob_implicit_flush()`, `flush()`, `ob_flush()`, `ignore_user_abort()`, `connection_aborted()`, `connection_status()`, spit out 4KB of data between every file (and I actually see this data added to the browser output every second real-time!) with FF and IE, and in every case, if I hit the stop button or close the entire browser, the code keeps happily running until all of the files have been created without exception. I tried all of the suggestions given in the relevant comments on the `PHP` doc pages with no change. – mellamokb May 13 '11 at 21:12
  • 3
    @Mörre: So to conclude. You are absolutely technically correct. But I am practically correct, for what really happens in real-life usage. Most of the time no connection status update is given to the PHP script until the PHP script is entirely finished, at which point it is irrelevant because there's nothing left to cancel. – mellamokb May 13 '11 at 21:13
  • Yes, that's why I had updated the answer. Very good outcome from the point of view of anyone reading all of this I'd say. I can't give you any rep. points for working so hard and doing all that testing... ;-( – Mörre May 13 '11 at 21:20
  • @MörreNoseshine sorry , my mistake the comment was intended to mellamokb – Repky Feb 26 '16 at 19:05
  • @mellamokb your script continued to run until all 30 file were generated because the default max exec time is set to 30 seconds :) if you will try to generate 31 one file you will see the 31 file is not generated (unless you explicitly specify set_time_limit(31) - Warning This function has no effect when PHP is running in safe mode. (from manual) ) you can try run this on your server (cli or web) and it will stop after 30s (despite you close your browser or not) – Repky Feb 26 '16 at 19:05
16

A PHP Script running through a web server will not stop until:

  • someone kill the server
  • the server kill the php scrip

When the user abort the script, PHP will continue until it try to send something back to the browser.

For example still script will continue fore ever even if the user abort:

while(true){
    echo 'go'.PHP_EOL;
}

It will go on forever because the "echo", will write into the buffer, and the buffer will not be sent to the browser until the script finish, which will never happen.

The following script will stop as soon as the user abort:

while(true){
    echo 'go'.PHP_EOL;
    flush();
    ob_flush();
}

This script will stop, because flush() and ob_flush() will force PHP to send its buffer to the browser, which will stop the PHP script if the user has aborted. The function ignore-user-abort() will force PHP to ignore the abort in this case.

Moreover if you are using PHP session, they are another tricky situation. For example, if you are doing AJAX, and you actually send two AJAX request to a PHP script and that PHP script has need of session with session_start(). The first AJAX query will work normally, however the second one will have to wait until the first call is finish, because the first script has a locked on the session. The first script could eventually prematurely release the session with session_write_close();

zzarbi
  • 1,832
  • 3
  • 15
  • 29
  • "This script will stop, because flush() and ob_flush() will force PHP" - that's not (necessarily) so, see the long tail of comments on my answer to this question (rather than my answer itself). – Mörre May 13 '11 at 21:22
4

By default no. See Connection Handling documentation, especially:

You can decide whether or not you want a client disconnect to cause your script to be aborted. Sometimes it is handy to always have your scripts run to completion even if there is no remote browser receiving the output. The default behaviour is however for your script to be aborted when the remote client disconnects.

Tadeck
  • 132,510
  • 28
  • 152
  • 198
  • 11
    This is correct, however with the one caviet. PHP will not know about the disconnect until it tries to send data to the client. So if you do 30 minutes of preprocessing without any output and kill the browser 1 minute in, the 30 minutes will complete. – ircmaxell May 13 '11 at 20:12
2

The script will run the time set by max_execution_time (default is 30s)

Warning This function has no effect when PHP is running in safe mode. There is no workaround other than turning off safe mode or changing the time limit in the php.ini. Note: The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real. quote from http://php.net/manual/en/function.set-time-limit.php

you can test this by running

<?php 
unlink('cocorico.txt'); 
while(true){ 
    file_put_contents('cocorico.txt', microtime(true).PHP_EOL, FILE_APPEND); 
} 

and it will stop after 30s (despite you close your browser or not) you can get you default exec time by echo ini_get('max_execution_time'); and can be set like set_time_limit(3); The answer marked as accepted is only correct about the ignore_user_abort but don't panic that your "fail" scripts will run forever if you don't set max exec time to 0 - unlimited;

Repky
  • 596
  • 7
  • 8
1

From my little understanding of how these stuff works. By the point of view of the HTTP protocol I would say yes, the script would keep running, because the browser just sends a request to the server asking for the page, then the server starts executing the script and does not sends or receives information from the browser untill the script is done loading and producing the html output, and just then the server sends the resulting output to the browser and has done the job.

See, there is no way for a browser to "tell" the server that the user is not viewing the page anymore through the HTTP protocol. However, the HTTP protocol runs on top of the TCP connection through stream sockets, the TCP connection is kept alive till one of the ends choses to abort the connection (or a certain timeout is reached), now I really don't know how the browser handles this. The browser could just open a connection, send a request and close the connection, then the server waits for the script and sends the response on another connection. Or the browser could open a connection, KEEP this connection alive till the server responds on the same connection. If the thing works that way then the server would really have a way to know if the user is not viewing the page anymore simply by checking if the connection is still alive or has been shutdown by the client. So that would be a no.

Dunno much about that tho.

Delta
  • 4,308
  • 2
  • 29
  • 37
  • Yeah... Cool... please, tell me more. Cause to me it seems like you said the same damn thing that I did in your above comment. – Delta May 13 '11 at 20:30
  • Nope, I don't assume that, did you read all of my answer? Hey, retoric question... I mentioned that I didn't know if the connection was kept alive or not, and I said that if it IS kept alive, then the answer is no. Please pay more atention to what you are reading on the next time. – Delta May 13 '11 at 20:36
  • So... Resuming the whole thing... You just added nothing and confirmed I was right in one of my hypotesis... Now get some sleep. – Delta May 13 '11 at 20:40
  • @Mörre: See my comment to your answer. I did a couple of tests because I couldn't believe you and this has always been my experience. Please explain the results I found. – mellamokb May 13 '11 at 20:43
  • (I deleted my comments, I had misunderstood the answer) – Mörre May 13 '11 at 20:54
  • That's fine Morre, so it seems like the server is able to know if the user has closed the connection if the TCP connection is dropped, however, as mellamokb noticed, that doesn't necessarely means that the server is going to stop the script when it notices the closed connection... and it seems like at least apache doesn't care about that. And also there is that keep-alive HTTP header that the bowsers sends, so if the user closes a tab the browser is not going to drop the TCP connection, right? – Delta May 13 '11 at 21:01
  • Well, that's something I never thought about (had no reason, and no nudge). I'd assume the kept-alive connections belong to the tab. Can't see too much sense in keeping them, unless the tabs are all for the same site. Would be interested in a definitive answer now that we got started. – Mörre May 13 '11 at 21:08