PHPCron: Running scheduled tasks from PHP on a web server
Downloads for the software described here are available on the downloads page.
This software is a work in progress and should not be considered complete or secure.
What is PHPCron?
PHPCron is a simple PHP script which lets you run multiple tasks on a schedule or timer. It can be run either from the command-line or via a web browser. Its behaviour is very similar to the popular cron program for UNIX.
Why?
Running scheduled tasks is a frequent requirement for web sites. For example, we use PHPCron at Deviant Audio (the radio station is now defunct) to monitor our radio streams' availability, send out invoices automatically when payments are due and so on.
Some web hosts provide you with access to cron services, but many don't. With this simple script, you can run scheduled tasks even without cron access, and that is its primary purpose.
How it works
PHPCron reads a list of scheduled tasks you define and runs continuously in the background, sleeping until it is time for the next task to execute. The task is run and PHPCron goes back to sleep again.
PHPCron can be called with parameters to make it start, stop or restart. In general it will not stop running unless you stop it or the machine is rebooted.
From a web server environment, PHPCron returns a status report to the browser when you call it but continues running on the server after the web browser has finished fetching the report, so you are free to close the browser window immediately.
Installation
PHPCron has been tested on PHP 5.1 and above but may work on earlier versions of PHP 5.
- Download the file from the downloads page and decompress it into a folder.
- Open
cron.config.phpand set the location of yourcrontabfile and the other files listed, as well as your email address for administrative reports.- The pidFile and exitFile must be in a folder that is writable by PHP and/or your web server (eg. Apache, IIS). Depending on the security configuration of your server, this may mean that you must give the folder "world" write permissions. You can set this with most FTP clients, or if you have shell access you can type
chmod 777 cronwherecronis the folder you extracted PHPCron into. If you set the file permissions incorrectly, PHPCron will give unexpected behaviour when you try to start, stop or restart it. To reset PHPCron after you make corrections to the file permissions, deletecron.lockandcron.exitif they exist, and call PHPCron with thekillparameter (see below). - The
crontabfile must be writable by your web server if you are planning to use the web-based interface to edit your scheduled tasks. Use the same technique as in the previous step to make the file world writable if necessary. - The
crontabfile should not be readable from a web browser, for security reasons. You can protect the file from being read either by moving it to a folder on the server that is not accessible via the web, or by using the web server's access control features. With Apache in its default configuration, you can create an.htaccessfile in the same folder you extracted PHPCron into, with the following contents:
Order Deny,Allow Deny from All
This will prevent the folder contents from being read by a web browser.
- The pidFile and exitFile must be in a folder that is writable by PHP and/or your web server (eg. Apache, IIS). Depending on the security configuration of your server, this may mean that you must give the folder "world" write permissions. You can set this with most FTP clients, or if you have shell access you can type
- Unauthorised users should not be able to use PHPCron over the web. For this reason it is strongly recommended that you use an access control technique like HTTP Authentication on the folder you extracted PHPCron into, to require users to enter a valid username and password before they are able to access PHPCron. If you don't restrict access to PHPCron, anybody can open the URL in their web browser and start or stop PHPCron, or edit your scheduled tasks. A hacker can create a simple task like:
* * * * * rm -rf *
to delete your entire web site or user account contents on a poorly secured web server.
Setting up your scheduled tasks
Scheduled tasks are called cronjobs in technical parlance. You can set up cronjobs in PHPCron in one of two ways:
- Edit the
crontabfile directly (either by editing it locally and uploading it to your web server via FTP, or by using a shell editor likevion your web server). - Use the web interface to edit it. If you installed PHPCron at
http://www.yourdomain.com/cron, openhttp://www.yourdomain.com/cron/cron.php?editin your web browser to display the editing interface. Full instructions on the available syntax in thecrontabfile are given in the interface.
The crontab file format is identical to that used by UNIX's cron utility; full documentation can be found at Wikipedia's Cron page.
PHPCron must be restarted for changes to the crontab to take effect. The web interface contains a link that will cause PHPCron to restart if it is already running, after you commit changes.
Usage from a web browser
PHPCron is called by opening the URL:
http://www.yourdomain.com/path/to/cron/cron.php?param
where param is a parameter to supply. If no parameter is supplied, PHPCron will attempt to start up if it is not already running.
Usage from the command-line
PHPCron is called by running the following command:
php cron.php --param
where param is a parameter to supply. If no parameter is supplied, PHPCron will attempt to start up if it is not already running.
Parameters
status- gets the running state of PHPCronedit- edits thecrontabfile (web browser only)kill- kills any running instances of PHPCron (execution of scheduled tasks will stop)force- kills any running instances of PHPCron and starts one new instance (equivalent to restarting; causes changes to thecrontabfile to take effect). Restarting in this way may result in a delay of upto 60 seconds when called from a web browser. Be sure to wait until the browser finishes fetching the page before closing the browser window.
System tasks vs PHP tasks
The cronjobs specified in the crontab file are shell commands just as with UNIX's cron utility. This means that you can execute any shell command available on your server under the web server's user privileges (or under your own user privileges when running from the command-line). You can also run shell scripts you have written or uploaded to the server.
If you want to retrieve/cache a web page every half an hour, for example, you might create an entry like:
0,30 * * * * wget -O /path/to/save/location http://somedomain.com/page/to/retrieve
If you want to create a backup of your web site once a day at 9am, you might create an entry like:
0 9 * * * tar -czf /path/to/save/location/backup.tar.gz /path/to/web/site
What if you want to run PHP scripts on a timer? It's simple! To run a PHP script from a shell command you just type php name_of_script.php where name_of_script.php is the script you want to run.
To run DoSomething.php every 2 hours on the first 7 days of each month, create an entry like:
0 */2 1-7 * * php DoSomething.php
What if you want to run a small snippet of PHP that's not worth storing in a .php file? You can run embedded code using PHP's -r switch. To send yourself an email on Monday mornings at 8am using PHP:
0 8 * * 1 php -r "mail('myemail@address.com', 'Subject line', 'Body of email');"
When writing embedded PHP code it's important to bear a couple of things in mind:
- The code must appear on one line, with each statement separated by semi-colons (
;). - The last statement must also be terminated by a semi-colon.
- The entire code snippet must be quoted (
"..."). - The dollar sign (
$) is interpreted specially by the shell; to ensure it is processed properly by PHP as a variable identifier, you must put a backslash (\) before each dollar sign or the code will not run properly.
Supplied examples
The download includes two simple cronjobs.
The first runs test.php every minute, which simply appends a line to a text file stating when the script was executed (the target file must be writable by your web server).
The second runs on the last minute of each hour (xx:59), and uses embedded PHP to email you a status report on PHPCron's health. It demonstrates the correct syntax for multi-statement embedded PHP code using variables.
Limitations and caveats
Due to restrictions imposed by the Windows security model, PHPCron cannot be run in an Apache web server environment on Windows (command-line operation works normally).
PHPCron keeps a process running continuously on the web server. While the process spends most of its time sleeping, some web hosts may not be happy about having long-running user processes on their machines.
Some technical details of the code itself
The information in this section is not important for using PHPCron, it is only relevant for those interested to know how it works.
Some interesting tricks are used to make PHPCron run in the background after the web browser has returned, to keep it running, and to ensure there is only one instance.
set_time_limit(0)ensures the PHP script will not auto-terminate after a certain length of time. By default, PHP scripts are killed if they run for more than 30 seconds to prevent badly behaved scripts from disrupting the server.- The function
is_web_environmentin PHPCron usesargcandargvto auto-detect whether a web browser or command-line instance has been started. ignore_user_abort()is used to allow the PHP script to continue running after the web browser has finished fetching its output.Pragma,Cache-ControlandConnection: closeheaders are used to ensure PHPCron's output isn't cached, and to close the connection to the browser as soon as the output has been sent.- pid and exit files are used to track PHPCron. The pidFile exists if an instance is already running, and is checked for existence when subsequent instances are started to prevent multiple instances. The exitFile exists if running instances should be terminated, and PHPCron checks for the presence of this file every minute, quitting and deleting it if it exists.
register_shutdown_function()is used to make sure the pidFile and exitFile are deleted when the script ends even if it is aborted, crashes or is killed by an administrator (for example, withkill -9at the shell prompt). This ensures correct behaviour of PHPCron on subsequent calls.- On UNIX/Linux, cronjob output is redirected to
/dev/nullso that each cronjob runs in the background and control is returned to PHPCron before the job has finished (no stalling). This redirection requirement is a quirk of PHP'sexec()function. - When using PHPCron from a web browser,
Content-Lengthis used to tell the browser how many bytes of output there will be from PHPCron in advance. PHPCron buffers all of its output using PHP'sob_*()functions and usesob_get_length()when the output is completely formed to determine the number of bytes to specify inContent-Length. As soon as the specified number of bytes have been received by the browser, it closes the connection. This prevents the browser from hanging permanently when PHPCron goes into its main sleep/cronjob cycle. - The web-based crontab editor negates
magic_quotes_gpcandmagic_quotes_sybasephp.ini settings.
Conclusion
I hope you find PHPCron a useful utility. Please be careful with your security settings, PHPCron is dangerous in the wrong hands! If you have any feedback, please feel free to leave comments below or email me via the contact page!
Printer-friendly version- 8451 reads
Post new comment