How To Run PHP Code In The Background
PHP Asynchronous Programming
You could update the configuration file for apache, or whatever web server you're running, to increase the amount of time a script page is allowed to run and then use php's ini_set("max_execution_time", seconds) to increase the amount of time php will allow a script to run.
Or you could use a session variable to mark the last position of the script and then use meta-refresh to start the script at the last position.
Or you could try an asynchronous call by using php's exec command.
Asynchronous Example
Here's an oversimplified example. Let's say that you've been charged with resizing all the images in the Products folder. You decide to write some fancy php script to iterate through all the sub-folders and resize each image. Everything works beautifully on your test server with 50 images and 10 sub-directories. You upload your script to the live server, with a couple thousand images, and attempt to run it. After about 5 minutes the page times out and only about 200 images were resized.
Now what? One possible solution is to create two pages, one that does all the image resizing, image_resize.php, and another that calls that page, resize_exec.php using the exec command.
resize_exec.php
<%
$command = "/usr/bin/php4 -f /var/www/myweb/image_resize.php";
exec( "$command > /dev/null &", $arrOutput );
%>$command is a linux/debian command for running a php page through a command line. Normally, exec() will wait for the script to finish running and will return any output to the array $arrOutput, like error messages. However, by adding " > /dev/null ", the exec() will not wait for the script to finish, allowing the php script to run in the background.
Your image_resize.php script is now able to run completely to the end.
What to watch for
- On the page that does the actual work, be sure to use ini_set("max_execution_time", seconds) to increase the amount of time php will allow your page to run.
- Be sure to use absolute paths for the command line and the working page.
- Make sure that permissions are set up correctly to allow the php command line to run.
- The command line and " > /dev/nul/" works with linux/debian. This may be different, depending on your system.
- This example will not work with windows, although it may be possible to do same thing using a similar method.
Additional Features
What if you wanted to keep track of the image resize process. One idea is to have image_resize.php update a text file with the percent done as it's running. Then on the resize_exec.php page, have a little bit of ajax that reads that file every few seconds and displays it on the page.
You could also have image_resize.php send out an e-mail informing you that it has finished.



Its actually the '&' which tells a job to run in the background on linux, the > /dev/null just sends the output of the command to a black hole. So the $arrOutput argument is not needed as it will never get populated.
anyway, nice idea about running the php interpreter in the background.
Left by martin | Oct. 1, 2007 at 1:00am
Are you sure this is wise?
I'm sure in an admin tools type thing where only a few people might be spawning this process, but for something where the public will be hitting it, your going to get killed.
The better approach would be to build up a queue of files, either in a db or something that can be moved to the network in case you need to scale up to multiple web servers. Set up some shell scripts, you can even write them in php. Cron's timing resolution only works on minute intervals, so you'll have to write something that runs as a background daemon, not too hard and can even be written in php. The daemon would basically load up a queue of files ever x seconds and do whatever it is you needed it to do.
Seems like a lot more work, but it isn't really and it's scalable, so it's worth the little more effort it takes. Unless, of course, this is for an admin or low usage tool.
Left by Jon Gilkison | Oct. 1, 2007 at 2:27am
It's worth noting that you could use the fork() command to spawn a parent-less process to do something similar.
Additionally you could run PHP with the async_send ini setting enabled which I believe will continue running the child PHP process even when a disconnect has been made to Apache.
Left by James | Oct. 1, 2007 at 3:29am
Thanks for the advice Martin. While testing, I remove the "> /dev/nul", so that I can see any debugging code that is outputted to $arrOutput.
Jon, yes, it is not a good idea to have this publicly available, thanks for pointing that out. The scripts I've written are only available in admin tools, and I also make sure to do some security checks on the page that is calling it. I also like your idea about the queue of files and the daemon.
James, the fork() command sounds like a good idea, I will definitely take a look at it. Thanks for explaining the async_send ini setting, it seems there's not much documentation on that directive.
Left by Ken at SC | Oct. 1, 2007 at 9:24am
If you have shell access, just run your script at the command line. You may have to write it a little differently. I do this a lot with some maintenance scripts that I then schedule with cron.
Left by Oscar | Oct. 1, 2007 at 9:41am
As per your example, you could also force a regeneration of a specific thumb when it is requested. In the majority of cases (depending on traffic load and such) would be sufficient.
Left by Elijah | Oct. 11, 2007 at 11:01pm
Thanks Oscar and Elijah.
Elijah, forcing a regeneration of a specific thumb when it's requested would definitely be more efficient, and I would use this method for this example on a real website.
Left by Ken at SC | Oct. 12, 2007 at 3:26pm
How stable is this? Could you use is for scheduling a mailing two weeks, two days, two hours from now? has anyone ay experience with this?
Left by Edward Granville | May. 6, 2008 at 4:48pm
This is very stable as long as you have all the absolute paths correct. Also, you could also create a file for storing the output of the command line so you can check to see if there were any errors. See the example below...
exec( "$command > /tmp/command_dump.txt &", $arrOutput );
Left by Ken at SC | May. 9, 2008 at 11:47am
"$command >& /dev/null &" will be correct without outputting errors
Left by Andrew Vorobyov | Jun. 29, 2008 at 9:32am
Leave a Comment