Source for file cron_exec.php
Documentation is available at cron_exec.php
* >c:\php4\php cron_exec.php
* >c:\php4\php-cli cron_exec.php
require_once dirname(__FILE__ ). '/../qp_config/_config.php';
require_once $inc_path . '_main.inc.php';
* @global integer Quietness.
* 1 suppresses trivial/informative messages,
* 2 suppresses success messages,
{ // called through Command Line Interface, handle args:
if( isset ( $_SERVER['argc'], $_SERVER['argv'] ) )
$argc = $_SERVER['argc'];
$argv = $_SERVER['argv'];
{ // may not be set for CGI
echo $argv[0], ' - Execute cron jobs for ', $app_name, "\n";
echo " -q --quiet: Be quiet (do not output a message, if there are no jobs).\n";
echo " This is especially useful, when running as a cron job.\n";
echo " You can use this up to three times to increase quietness.\n";
echo " Successful runs can be made silent with \"-q -q\".\n";
echo 'Invalid option "'. $v. '". Use "-h" or "--help" for a list of options.'. "\n";
{ // This is a web request:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<link rel="stylesheet" type="text/css" href=" <?php echo $rsc_url ?>css/basic.css">
<p>This script will execute the next task in the cron queue.
You should normally call it with the CLI (command line interface) version of PHP
and automate that call through a cron.</p>
* The following will feel a little bloated...
* BUT it is actually a pretty nifty design to prevent double execution of tasks without any transaction!
* The trick is to rely on the primary key of the cron__log table.
// Get next task to run in queue which has not started execution yet:
FROM T_cron__task LEFT JOIN T_cron__log ON ctsk_ID = clog_ctsk_ID
WHERE clog_ctsk_ID IS NULL
AND ctsk_start_datetime <= '. $DB->quote( date2mysql($localtimenow) ). '
ORDER BY ctsk_start_datetime ASC, ctsk_ID ASC
$task = $DB->get_row( $sql, OBJECT, 0, 'Get next task to run in queue which has not started execution yet' );
cron_log( 'There is no task to execute yet.', 0 );
$ctsk_ID = $task->ctsk_ID;
$ctsk_name = $task->ctsk_name;
cron_log( 'Requesting lock on task #'. $ctsk_ID. ' ['. $ctsk_name. ']', 0 );
$DB->halt_on_error = false;
$DB->show_errors = false;
$sql = 'INSERT INTO T_cron__log( clog_ctsk_ID, clog_realstart_datetime, clog_status)
VALUES( '. $ctsk_ID. ', '. $DB->quote( date2mysql($localtimenow) ). ', "started" )';
// Duplicate query for tests!
// $DB->query( $sql, 'Request lock' );
if( $DB->query( $sql, 'Request lock' ) != 1 )
{ // This has no affected exactly ONE row: error! (probably locked -- duplicate key -- by a concurrent process)
$DB->halt_on_error = true;
cron_log( 'Could not lock. Task is probably handled by another process.', 2 );
if( !empty( $task->ctsk_repeat_after ) )
{ // This task wants to be repeated:
// Note: we use the current time for 2 reasons: 1) prevent scheduling something in the past AND 2) introduce variety so that everyone doesn't run his repeated tasks at the same exact time, especially pings, pollings...
$new_start_datetime = $localtimenow + $task->ctsk_repeat_after;
$sql = 'INSERT INTO T_cron__task( ctsk_start_datetime, ctsk_repeat_after, ctsk_name, ctsk_controller, ctsk_params )
VALUES( '. $DB->quote(date2mysql($new_start_datetime)). ', '. $DB->quote($task->ctsk_repeat_after). ', '
. $DB->quote($ctsk_name). ', '. $DB->quote($task->ctsk_controller). ', '. $DB->quote($task->ctsk_params). ' )';
$DB->query( $sql, 'Schedule repeated task.' );
$DB->halt_on_error = true;
cron_log( 'Starting task #'. $ctsk_ID. ' ['. $ctsk_name. '] at '. date( 'H:i:s', $localtimenow ). '.', 1 );
if( empty($task->ctsk_params) )
// The job may need to know its ID (to set logical locks for example):
$cron_params['ctsk_ID'] = $ctsk_ID;
call_job( $task->ctsk_controller, $cron_params );
// Record task as finished:
$timestop = time() + $time_difference;
$sql = ' UPDATE T_cron__log
SET clog_status = '. $DB->quote($result_status). ',
clog_realstop_datetime = '. $DB->quote( date2mysql($timestop) ). ',
clog_messages = '. $DB->quote($result_message) /* May be NULL */. '
WHERE clog_ctsk_ID = '. $ctsk_ID;
$DB->query( $sql, 'Record task as finished.' );
// Detect timed out tasks:
$sql = ' UPDATE T_cron__log
SET clog_status = "timeout"
WHERE clog_status = "started"
AND clog_realstart_datetime < '. $DB->quote( date2mysql( time() + $time_difference - $cron_timeout_delay ) );
$DB->query( $sql, 'Detect cron timeouts.' );
{ // This is a web request:
echo '<p><a href="cron_exec.php">Refresh Now!</a></p>';
echo '<p>This page should refresh automatically in 15 seconds...</p>';
echo '<!-- This is invalid HTML but it is SOOOOOO helpful! (Delay will be triggered when we reach that point -->';
echo '<meta http-equiv="Refresh" content="15" />';
|