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.
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 } }
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).
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.
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!
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.
This tuto is not clear enough
Every Yii's tuto are too succinct for newbies ! (And I am one of them..)
I think it's simple but I can't understand every step because no example are given, no location are precised, etc. !
How to permit command to communicate with model ?..
... Please, can you underpine your tuto ? :/
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.