Yii 1.1: Implementing cron jobs with Yii

27 followers

There are two ways to run a cron job:

  • Emulate browser.
  • Run PHP in CLI (console) mode.

Emulating browser

This way is a simplest one since you can use existing controller action.

Add one of the following to your crontab:

GET http://example.com/cron/
wget -O - http://example.com/cron/
lynx --dump http://example.com/cron/ >/dev/null

In spite of this method is simple, there are drawbacks. If we are doing some kind of intensive job, one who know the URL can kill your application sending a lot of requests to it.

You can pass a parameter and check it in your action to make URL harder to find:

if($_GET['key']!='my_secret_key') die();

but this will not solve the problem completely.

Using console application

The best way is to create a console application.

Let's create a console command class /protected/commands/TestCommand.php:

class TestCommand extends CConsoleCommand {
    public function run($args) {
        // here we are doing what we need to do
    }
}

Creating entry script cron.php:

defined('YII_DEBUG') or define('YII_DEBUG',true);
 
// including Yii
require_once('path/to/yii/framework/yii.php');
 
// we'll use a separate config file
$configFile='path/to/config/cron.php';
 
// creating and running console application
Yii::createConsoleApplication($configFile)->run();

Configuration file should look like this:

return array(
    // This path may be different. You can probably get it from `config/main.php`.
    'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
    'name'=>'Cron',
 
    'preload'=>array('log'),
 
    'import'=>array(
        'application.components.*',
        'application.models.*',
    ),
    // We'll log cron messages to the separate files
    'components'=>array(
        'log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CFileLogRoute',
                    'logFile'=>'cron.log',
                    'levels'=>'error, warning',
                ),
                array(
                    'class'=>'CFileLogRoute',
                    'logFile'=>'cron_trace.log',
                    'levels'=>'trace',
                ),
            ),
        ),
 
        // Your DB connection
        'db'=>array(
            'class'=>'CDbConnection',
            //
        ),
    ),
);

In your crontab add:

php /path/to/cron.php test

Where test is a command name.

Total 5 comments

#15569 report it
viet at 2013/11/22 04:22am
can't run cron

i run "/usr/bin/php /var/www/html/cron/app/console.php myCron testCron" in command line is ok.but i insert to crontab with "01 * * * * root /usr/bin/php /var/www/html/cron/app/console.php myCron testCron" is not run. I have a mail in root. Error: Unknown action: testCron

Usage: /var/www/html/cron/app/console.php mycron Actions: testCron

help me.

#10307 report it
fleuryc at 2012/10/18 11:48am
Isn't this article outdated?

Hi!

Comparing this wiki page, and the Console Applications article in the Definitive Guide, I feel like it seems a bit obsolete, and that with the latest versions of Yii, you would't be doing this the same way.

I mean, I guess now we would be using Console Command Action.

Cheers!

#6608 report it
jpablo at 2012/01/20 04:11pm
Advantage of browser emulation

Browser emulation has an important advantage. It avoids to deal with diferent PHP versions from web and CLI and diferent php.ini. Sometimes a script works as expected from the web broser and fails in a command line execution. Or vice versa.

Running all the processes in the same way (through the web server PHP module) ensures a consistent behavior.

#2601 report it
Sarke at 2011/01/22 08:17am
Safe way to emulate the browser

I had to use the web interface when running a cron job because I needed access to the same APC cache, which isn't available from the command line... long story.

Instead of using a $_GET['secret_key'] type of thing, I ended up doing this simple check instead:

if ($_SERVER['SERVER_ADDR'] != '127.0.0.1')
    throw new CHttpException(403,'Access denied.');

This ensures that the request is coming from the local server and not from the outside, and can't be guessed or compromised.

Then I set up the cron job like this:

wget http://127.0.0.1/cron/

The drawback of course is that you can't access it from a browser manually, but this can easily be done by checking if the user is logged in (something that is hard to fake from the command line).

#2000 report it
sebas at 2010/10/28 09:31am
You can also make it run only one time every XXXX minutes
public function actionIndex{
    $oldtime = Yii::app()->getGlobalState('lastCronTime',0);
    if ($oldTime + 60*60 <time){ // your code can be executed
        // put your code here.
    }else{
        //You can log the income request here
    }
}

Leave a comment

Please to leave your comment.

Write new article
  • Written by: samdark
  • Category: How-tos
  • Yii Version: 1.1
  • Votes: +30 / -1
  • Viewed: 50,522 times
  • Created on: Oct 26, 2010
  • Last updated: never
  • Tags: cron, cli