As part of the same project that resulted in my last posting, I needed to write several processes that would be managed by cron. In the past, at the Yahoo contract, we had come up with a way to do this involving a customized version of the basic CakePHP index.php file. However, his required us to place the cron code on the main controllers, and extra protections to ensure that the code was inaccessible from the main web interface. I was never thrilled with the solution, but it was the best we had at the time.
So for this project, I looked into the concept of ‘Shells’, which are basically command-line interfaces to a CakePHP application. It quickly became obvious that this was the best way to go about handling the cron jobs for a CakePHP application. It allows you to place all your sensitive cron code completely out of reach of the web facing part of the application, increasing security and decreasing complexity. It’s really quite simple as well.
The process is basically outlined in this section of the CakePHP manual, and should be simple enough to follow. The end result is code like this:
class BillingShell extends Shell { var $uses = array('OrderLineItem', 'Division'); function main() { echo "Please specify which billing task to run. Currently, the only choice is 'daily'.\n\n"; } function daily() { date_default_timezone_set('America/Denver'); App::Import('Component','Cbg'); $this->Cbg = new CbgComponent(); $this->create_invoices(); $this->process_invoices(); } // Other functions not shown }
And you can run it as a cron like this:
# m h dom mon dow command */5 * * * * /full/path/to/cakeshell billing daily -app /full/path/to/app









Hi
just wanted to say thanks for this – you have some good cakephp & web development help on your site.
There are several other people who advocate using a duplicate index.php method to do this cron task, but yours made me surer that it is the better way (secure and cakeish method of developing!).
thanks,
Luke, Glasgow, Scotland.
Glad it helped. Shells work much better than an alternate dispatcher, for sure.
Hi,
iam not sure, but why did you run the method daily any 5 minutes via cron ?!
best regards
andreas
It’s just a random example. My real instance of that particular code runs once a day at 5 AM.
I am a little confused by the path statements as I am not much of a Unix person. So I am trying to determine how to build the path statement for my app that is on a shared host.
I think the path to my application looks like this: /myproject.mydomain.com where the /app and /cake and /vendors folders reside.
The path to my vendors folder at the root of the site is: /myproject.mydomain.com/vendors/shells
Inside this shells folder is my file reminders.php with two actions; lof and other.
Would my cron statement look like this?:
*/5 * * * * /myproject.mydomain.com/vendors/shells reminders lof -app /myproject.mydomain.com
Is it necessary to make the BASH script as outlined in the Cookbook at 3.13.2?
Thanks in advance for your help! Great article!
Odds are, there’s directories above the ‘myproject.mydonmain.com’, although I can’t say for sure. If you have terminal access, go into that directory, and type ‘pwd’. That will show you the full path to get there.
That cron statement looks reasonable. Test all cron commands from the commandline first, to make sure they work.
As for the bash script the cookbook talks about, I don’t bother. It results in a warning at the top of your shell output, but it doesn’t bother me. If it bothers you, make the script.
Getting closer!
I was able to do as you suggested. I didn’t know I could log in via Terminal (OS X) to Dreamhost. My revised cron job command looks like this now:
/home/myusername/myproject.mydomain.com/vendors/shells reminders lof -app /home/myusername/myproject.mydomain.com
Dreamhost is sending me a message that ../vendors/shells “is a directory”, but the shell does not appear to be running.
When I run the command from the command line in Terminal I get the same message: “is a directory”.
Again suggestions ObiWan?
Sorry I didn’t catch it the first time. The first path needs to be the path that leads to cake_core/console/cake.
In your case, that would appear to be:
/home/myusername/myproject.mydomain.com/cake/console/cake
Let me know if that helps.
Also, the second path should include your app directory.
Incremental progress…
I ran this command from Terminal using your input above:
/home/myusername/myproject.mydomain.com/cake/console/cake reminders lof -app /home/myusername/myproject.mydomain.com/app
The entire contents of the shell were displayed on the terminal console screen and then this:
Error: Class RemindersShell could not be loaded[monrovia]$
Monrovia is the name of the server I am assigned to on Dreamhost. Hmmm… Is this a symptom of not having cake in the path for my user id? My user id has shell access with a shell type of /bin/bash, whatever that means.
I very much appreciate your help!
That error tells me that there’s something wrong with the class definition of the shell. Mind putting it up in a pastebin?
Sure! Here it is:
http://bin.cakephp.org/view/608307067
The code for the actions ‘lof’ and ‘sendMail’ also exist in my controller. I was testing via a URL to debug the database fetch and sending of the message. It works there very well. I am trying to automate the process and would then take the code out of the controller.
Hopefully it is not too fouled up. Thank you for taking a look! If you want, you may e-mail me directly if this clogging up your blog entry too much. Thank you!