Category:Config | Category:Config -> Community | Category:Config -> Cron
This is a clear cut & paste from a discussion on the forum about using the CI inside of a cron Script. The original post. The author of the Idea is the user Mhort
Here is how I run cron scripts in the CI environment, it ended up being very easy:
cron scripts are generally going to be doing maintenance things such as database updates, cache file management, sending emails, etc. Things with generated output like emails I want to come from view files. The db updates will use existing data models. cache file cleaning will use custom CI libraries. Therefore, it is important to me to have the CI environment available to my cron script.
What is not necessary is an HTTP connection. Why involve the web server? All you are doing is adding an unnecessary TCP stack setup and teardown, creating unwanted access_log entries, not to mention more security checks and timeout issues.
The slight problem is that CI expects an HTTP connection environment to make everything work happy. But actually, all CI really needs for a cron script is the PATH_INFO. That is how CI knows what controller/method to use, etc. So, we can emulate this.
First, make a directory for your cron scripts. I just used scripts and put it in the same directory that my CI system folder is in. Then, copy the index.php file from your DOCUMENT_ROOT (the script that normally initiates a connection to CI from a web browser) to the scripts directory, and rename it to something meaningful, such as clean_cache.php.
Now, we edit this file and make some slight adjustments. First, we don’t want the script to timeout during execution, so somewhere toward the top we add:
set_time_limit(0);
Next, we need to set the path to the system folder, if it isn’t correct:
$system_folder = "../system";
Next, we need to let CI know what controller/method we want to access, and any other URI variables we need. Normally this happens in the URL, so we emulate it by setting PATH_INFO manually:
$_SERVER['PATH_INFO'] = '/cron/cleancache';
However, if the config uri protocol is set to REQUEST_URI, then CI doesn’t use PATH_INFO, so instead, emulate REQUEST_URI manually:
$_SERVER['REQUEST_URI'] = '/cron/cleancache';
Next, you create a cron.php controller (in the system/controllers dir) with a cleancache method, and make it do what it needs to do. load libraries/models/etc, execute them, then exit. What you don’t want to happen is output anything. Just make sure you don’t echo any content to stdout (echo, loading views, etc.) If you are sending emails, you would load a view file, but return the contents to a variable instead of displaying it (pass true as third param), then run through normal procedures for sending emails.
One thing to be aware of regarding security, you probably don’t want anyone accessing /cron/cleancache from a web browser, so in the cron.php controller constructor, you may want to do some kind of check to make sure we are coming from a cron script. Probably the easiest method would be to test the SCRIPT_FILENAME variable:
if($_SERVER['SCRIPT_FILENAME'] != 'clean_cache.php')
exit;
Once everything looks good, add your crontab entry to execute the script, and there you have it!
Sample cronjob:
# execute cronjob every day at 2am
00 02 * * * /usr/local/bin/php5 $HOME/system/scripts/clean_cache.php
Easy Cron Script for loading CI
For those who don’t mind about loading additional TCP/IP stacks then the wget function works fine. It allows you to run CI scripts via cron:
0 13 * * * wget http://yourdomain.com/codeigniter/yourclass/yourparameters 2>&1;
An Alternative Method For Cron Jobs
I came to this wiki entry looking for a way to execute cron jobs, these suggestions are clearly good, but since I didn’t want to hack CI and we’ve disabled wget on our servers for security reasons I came up with this:
1. Create a CI script that does what you need it to and which you would like to run as a cron job.
2. Create a new folder outside your CI installation
3. Edit your .htaccess file to allow access to the new folder (if you’re using .htaccess with mod_rewrite)
4. Create a new php file in your folder (mine was called get_news.php)
5. Add something similar to the following to this file:
$fp = fsockopen("www.yourdomain.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET /cron/update/get_news HTTP/1.1\r\n"; //The codeigniter url you need to run as a cron job
$out .= "Host: www.yourdomain.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
Then add this file to the cron tasks on your server. This file will be called as a cron job, and will open the appropriate CI file as if it was being called via a GET request. Obviously this isn’t the most secure solution, but if your cron job doesn’t have much need for security (mine was just retrieving an xml feed) it should suffice.
Yet Another Method For Cron Jobs (!hack)
In case none of the methods above work (i.e. issue with $_SERVER or inability to use curl/file_get_contents()/include on some hosts), you can make your cron work by directly hacking the URI class.
Assuming that you only have one class/method to run (called for example cronjob/run), here is the hack:
1. create a whole new CI environment (feat. system & application & index.php etc.) in a separate folder dedicated to cron jobs (let’s call it “cronjobs”)
2. in cronjobs/system/libraries/URI.php look for function _fetch_uri_string() and modify it the following way
BEFORE:
function _fetch_uri_string()
{
if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
{
// If the URL has a question mark then it's simplest to just
// build the URI string from the zero index of the $_GET array.
// This avoids having to deal with $_SERVER variables, which
// can be unreliable in some environments
if (is_array($_GET) AND count($_GET) == 1)
{
$this->uri_string = key($_GET);
return;
}
...
AFTER:
function _fetch_uri_string()
{
if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
{
$this->uri_string = 'cronjob/run';
return;
// If the URL has a question mark then it's simplest to just
// build the URI string from the zero index of the $_GET array.
// This avoids having to deal with $_SERVER variables, which
// can be unreliable in some environments
if (is_array($_GET) AND count($_GET) == 1)
{
$this->uri_string = key($_GET);
return;
}
...
Then run your CRON task on cronjobs/index.php
That’s it!
