Will a script continue to run even after closing a page? - php

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?

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.

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();

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.

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;

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.

Related

What happens if user aborted by php process exiting browser in the middle?

While PHP Settings of ignore_user_abort is set to False by default,
Assuming i have the following code:
1 1ms $user->giveMoney(500)
2 2ms $user->sendNotification("You got 500")
3 1ms $user->takeCoins(200)
What if the user aborted the browser after exactly 3ms ? would line 3 be executed?
Yes, it will, seeing as the code you've posted doesn't seem to be producing any output, and you're asking about the behavior in a client-server context. As mentioned in the docs:
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've highlighted some key words: this setting deals with PHP when it's being used for command line scripts. You mention a client, closing his/her browser. There's no TTY, so this setting can be false or true, it won't change a thing.
In your case, though, the man states that:
PHP will not detect that the user has aborted the connection until an attempt is made to send information to the client. Simply using an echo statement does not guarantee that information is sent, see flush().
That is to say: the script will keep on running until actual output is really sent to the client. Only then can PHP determine whether or not the connection to the client is still alive. If it isn't then your script will halt.
So unless there is some actual output being sent in that second line of code, and any output buffers are flushed, then yes, the third line will execute. If output is sent, then the script will probably halt.
But if you really want to prevent that third statement from being executed in case of a lost connection, then perhaps call connection_aborted after the second method returns:
$user->sendNotification("You got 500");
if (connection_aborted())
exit(0);//no error code, just exit
$user->takeCoins(200);
You can control that behaviour with http://php.net/manual/en/misc.configuration.php#ini.ignore-user-abort
At the configuration level (e.g. on a .htaccess file) you can set the flag:
php_flag ignore_user_abort 1
At the script level (valid for that script only) you can call this function:
ignore_user_abort(1)
NOTE: The documentation is a bit misleading. ignore_user_abort works ALSO on the server. See also this page for more references.

How ajax works?

I have 2 pages. One is form.php and ajaxprocessing.php
When user clicks on submit button on form.php, it will call the ajaxprocessing.php using ajax. This ajaxprocessing.php has a loop of say 50,000 times to do database insert query or some function.
My question is, even when, if the user clicks the submit button in form.php and closes the browser or shut down the PC, will the ajaxprocessing.php will still continue to execute in server?
How does it works behind the scene?
By default, PHP execution will terminate if the client disconnects. So if your ajax call times out or disconnects, then the PHP will stop running. This behavior can be changed by turning on the configuration setting ignore_user_abort.
From the comments in php.ini:
; If enabled, the request will be allowed to complete even if the user aborts
; the request. Consider enabling it if executing long requests, which may end up
; being interrupted by the user or a browser timing out. PHP's default behavior
; is to disable this feature.
; http://php.net/ignore-user-abort
A way to test if the script keeps running would be to insert something like this in the bottom of your PHP script.
mail('your#email.com', 'Script done', 'The script is now done');
This will send you an e-mail when the script is done - if sendmail is installed on the server of cause. This way you will know if the script keeps running after you close the browser.

How to run shell script with live feedback from PHP?

How would I execute a shell script from PHP while giving constant/live feedback to the browser?
I understand from the system function documentation:
The system() call also tries to automatically flush the web server's
output buffer after each line of output if PHP is running as a server
module.
I'm not clear on what they mean by running it as a 'server module'.
Example PHP code:
<?php
system('/var/lib/script_test.sh');
Example shell code:
#!/bin/bash
echo "Start..."
for i in {1..10}
do
echo "$i..."
sleep 1
done
echo "Done."
What this does: It will wait about 10 seconds and then flush to the output buffer.
What I want this to do: Flush to the output buffer after each line of output.
This can be done using popen() which gives you a handle to the stdout of whatever process you open. Chunks of data can be sent to the client using ob_flush(), the data can be displayed using an XHR.
One option is to write to a file in the shell script, on each step to say where it's up to. On your web page, use an ajax call every X seconds/minutes. The ajax call will call a PHP script which reads the status file and returns the status or completed steps.
The advantage to this approach is the page live information will be available to multiple visitors, rather than just the one that actually initiated the shell script. Obviously that may or may not be desirable depending on your needs.
The disadvantage of course is the longer the ajax interval, the more out of date the update will be.

How to handle an abandoned PID file when the user cancels a script?

This is more of a question about best practices. My server allows users to convert fonts from one format to another using FontForge. To prevent collisions, only one font conversion is allowed at any given instance.
When one user initiates a conversion, a PID file is created which acts as a lock. If another user tries to initiate a conversion while the first conversion is still running, then the script will pause for a moment and check for the PID file again.
This repeats until the first process removes the PID file, thus unlocking access to FontForge. However, if the first user cancels the script before it finishes (by pressing the stop button on their browser), then the script exits before the PID file is removed. The second user will never be able to proceed.
What is the best way to handle this?
Looking at this PHP Man page:
http://php.net/manual/en/features.connection-handling.php
I quote:
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. This behaviour can be set
via the ignore_user_abort php.ini directive as well as through the
corresponding php_value ignore_user_abort Apache httpd.conf directive
or with the ignore_user_abort() function. If you do not tell PHP to
ignore a user abort and the user aborts, your script will terminate.
The one exception is if you have registered a shutdown function using
register_shutdown_function(). With a shutdown function, when the
remote user hits his STOP button, the next time your script tries to
output something PHP will detect that the connection has been aborted
and the shutdown function is called. This shutdown function will also
get called at the end of your script terminating normally, so to do
something different in case of a client disconnect you can use the
connection_aborted() function. This function will return TRUE if the
connection was aborted.
Stop watching for the PID file to go away. Start using flock so the operating system will clean up the lock if you exit prematurely.
Example code from http://tuxradar.com/practicalphp/8/11/undefined:
<?php
$fp = fopen("foo.txt", "w");
if (flock($fp, LOCK_EX)) {
print "Got lock!\n";
sleep(10);
flock($fp, LOCK_UN);
}
?>
Also, http://php.net/manual/en/function.flock.php.

Not Waiting for Response from an AJAX Request

Suppose I make an AJAX HTTP Request from jQuery to a backend PHP script. The request is made, the PHP script starts running and doing its magic. Suppose I then change to another website, away from the site where the original AJAX Request was made. As well, I do this before the PHP script finishes and has time to do a HTTP Response back. Does the PHP script finish running and doing its thing even though I've switched to another website before I got the HTTP Response?
So the order is this.
I'm on website www.xyz.com
I have a jQuery handler that kicks off an AJAX request to blah.php
blah.php starts running
I go to website www.abc.com soon after without waiting for a response from blah.php
What's going on with blah.php? Is execution still going on? Did it stop? I mean it didn't get a chance to respond so...
This may depend on your server configuration, but in general the script will continue to execute despite a closed HTTP connection.
I have tested this with Apache 2 + PHP 5 as mod_php. I would expect similar behaviour with PHP as CGI and with other webservers but do not know for certain.
The best way to determine for certain on your configuration is, as #tdammers suggests: set up a test script something like the following and monitor the log.
<?php
error_log('Test script started.');
for ($i = 1; $i < 13; $i++) {
sleep(10);
error_log('Test script got to ' . (10 * $i) . ' seconds.');
}
error_log('Test script got to the end.');
?>
Access this script (at /test.php or whatever) then before you get any results, hit stop on your browser. This is equivalent to navigating away before your XHR returns. You could even have it as the target of an XHR and navigate away.
Then check your error log: you should have a start and then messages every 10 seconds for two minutes and an end. You can modify how high $i gets to ensure your script will reach its anticipated maximum execution time if you'd like to test that too.
You don't have to use error_log() - you could write to a file, or make some other persistent change on the server that can be checked without needing to keep the client connection open.
The script execution time may stop before then because of the max_execution_time php.ini directive - but in any case this should be distinct from when the webserver times out.
Try ignore_user_abort(true);
ignore_user_abort(true);
it should not abort proccessing of your code
You might want to check out the answers to This Question.
Basically when you make your ajax call to a php function which calls the exec() function as shown in the answers to that question, you'll get an ajax response almost immediately, since your php function doesn't actually need to process anything. This way, it shouldn't matter if the user leaves the page.
Here's a small example:
ajax call in html file: $.ajax({url: 'blah.php'});
blah.php file: exec('bash -c "exec nohup setsid php really_slow_script.php > /dev/null 2>&1 &"');
And then finally in really_slow_script.php, just include the actual code you want to run.
I successfully used this kind of logic to allow users to post an already uploaded video from their account on my website to youtube. (The video had to be sent to youtube, and since videos are generally large files, I didn't want the user to have to wait while the video was being uploaded to youtube)
Navigating away will trigger a disconnect message on the server. The implications of that entirely depends on what what your server has been configured to do.
By default, the server will be set up so that a disconnect will not interrupt the way that the program functions. It is possible, however, to make it so that a user disconnect will trigger the function which has been registered with register_shutdown_function, garbage collection will occur, and the script will terminate.
Because it is something which can be configured several different places, it might be easiest to just run a test, but this is a php.ini directive. If you want to configure this on a global level, you can set ignore_user_abort = Off in php.ini. If you want this on a site-specific level, you can use php_value ignore_user_abort off in the htaccess in the parent directory of the current site. Otherwise you can use ignore_user_abort(false);.
Of course, there is no guarantee on a shared server that you have control of htaccess or php.ini, so you might just need to use ignore_user_abort(false);.

Categories