How To Run A PHP Script In The Background
If you have a PHP script that takes a while to execute (for example, long database operations or file format conversions), you might want to run it in the background so that the rest of your page still loads fast. In this post I’ll describe two ways to do this.
Launching a background process
One approach is to launch a new instance of the PHP interpreter as a background process. On a UNIX-based system this can be done with a single line of code :
exec ("/usr/bin/php path/to/script.php >/dev/null &");
To launch a background process in an OS-independent fashion you’d can use the function below (snatched from this post) -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function launchBackgroundProcess($call) { // Windows if(is_windows()){ pclose(popen(’start /b ‘.$call.”, ‘r’)); } // Some sort of UNIX else { pclose(popen($call.‘ /dev/null &’, ‘r’)); } return true; } function is_windows(){ if(PHP_OS == ‘WINNT’ || PHP_OS == ‘WIN32′){ return true; } return false; } |
If you use one of these methods you can pass data to the PHP script using command line arguments.
The main disadvantage of this approach is that the command to execute ($call) is still platform-dependent. Also, the path to the PHP executable may be different on various servers.
Using an asynchronous HTTP request
If the PHP script that needs to be executed is available on the Web, you can easily run it in the background by requesting the URL and dropping the connection right away, so you don’t need to wait until it’s done processing. You can also pass information to the script in the usual way – as URL parameters.
Here’s a function that will submit an asynchronous POST query to the specified URL (this works similar to how a web form is submitted) -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function backgroundPost($url){ $parts=parse_url($url); $fp = fsockopen($parts['host'], isset($parts['port'])?$parts['port']:80, $errno, $errstr, 30); if (!$fp) { return false; } else { $out = "POST ".$parts['path']." HTTP/1.1\r\n"; $out.= "Host: ".$parts['host']."\r\n"; $out.= "Content-Type: application/x-www-form-urlencoded\r\n"; $out.= "Content-Length: ".strlen($parts['query'])."\r\n"; $out.= "Connection: Close\r\n\r\n"; if (isset($parts['query'])) $out.= $parts['query']; fwrite($fp, $out); fclose($fp); return true; } } //Example of use backgroundPost('http://example.com/slow.php?file='. urlencode('some file.dat')); |
Assuming that the target script is located on the same server as the calling script, this function is fast, plus it should work on any operating system.
By the way, I recommend to put a call to ignore_user_abort(true) right at the top of the backgroud script to make sure it’s not terminated when the connection is closed. Disabling the time limit with set_time_limit(0) can also be useful.
Need more?
If for some strange reason you can’t use the aforementioned tricks, you could also launch the script from the client side by using AJAX. This is what I do in my link checker plugin for WordPress. Another possibility is to store the tasks that need to be done in a database and periodically run the script using cron.
Related posts :
Hi there,
I have a background task running in exact the same way you have in your example. Though the point is that I wan’t the script to popup a page or dialog or whatever when it’s done.
1. So a visitor clicks and genarates a request which is being executed on the background.
2. The visitor keeps surfing on different pages.
3. No matter wich page he is, when the script is done he should see a popup or whatever that tells him/her that (in my case) the pdf is created and can be downloaded.
What would be the best way to do this…is there a way to do this?
Thank you!
I think the easiest solution in this case is to use AJAX. Assuming that …
1. All requests are logged somewhere (e.g. a database).
2. You know which request corresponds to which user (e.g. using a cookie or session variables).
3. The background script can set some kind of “completed” flag for the request when it’s done, or the completeness can be verified in some other way.
You can create a small PHP script that accepts the request’s ID (or somesuch) as a parameter, checks whether it’s done and outputs 1 if yes and 0 if no (just an example, you could use other values, JSON or even XML).
Then add a small piece of JavaScript to every page that will query the aforementioned PHP script and notify the user if the processing is done. It could also display a new window, redirect to a page etc. I’d recommend putting this script in the footer of the page and only using it when there is a request being processed.
If you’re not familiar with AJAX, here are some useful links –
* What is AJAX? [Wikipedia]
* The jQuery library (with some useful AJAX functions)
* jQuery tutorials
Thank you White Shadow,
That should be the best way indeed. The whole website is kinda ajax so, it should not be a problem to implement.