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.

  1. Download the file from the downloads page and decompress it into a folder.
  2. Open cron.config.php and set the location of your crontab file 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 cron where cron is 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, delete cron.lock and cron.exit if they exist, and call PHPCron with the kill parameter (see below).
    • The crontab file 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 crontab file 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 .htaccess file 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.

  3. 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 crontab file directly (either by editing it locally and uploading it to your web server via FTP, or by using a shell editor like vi on your web server).
  • Use the web interface to edit it. If you installed PHPCron at http://www.yourdomain.com/cron, open http://www.yourdomain.com/cron/cron.php?edit in your web browser to display the editing interface. Full instructions on the available syntax in the crontab file 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 PHPCron
  • edit - edits the crontab file (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 the crontab file 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_environment in PHPCron uses argc and argv to 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-Control and Connection: close headers 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, with kill -9 at the shell prompt). This ensures correct behaviour of PHPCron on subsequent calls.
  • On UNIX/Linux, cronjob output is redirected to /dev/null so 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's exec() function.
  • When using PHPCron from a web browser, Content-Length is 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's ob_*() functions and uses ob_get_length() when the output is completely formed to determine the number of bytes to specify in Content-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_gpc and magic_quotes_sybase php.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!

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <b> <i> <u> <pre> <sup> <sub> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.

Latest articles