Yesterday I was planing a CronScript to run every night and do some processing tasks. I was coding over Code Igniter (CI) and had my application structured to fit the MVC model.
CronScripts are usually small scripts that do some maintenance to the database, send e-mails, clean cache files, generate reports and other periodic tasks or longer tasks.
After done my script algorithms, I starting thinking how can I get the information from the database. Many of the information that I need from the DB were already done in the models use with CI. However, this models are based in the CI environment and don’t run without it. Other catch is that CI was developed to work over an HTTP connection. So, we need to make a connection, use the TCP stack, check the security, creating access logs and most important for big jobs, deal with timeout issues. In the recent versions of CI, the only thing that really matters is one information from the $_SERVER array. By default the CI uses the PATH_INFO property, but you can configure CI to use REQUEST_ID, to select witch controller and method to run. This way we can easily emulate this information and run a CI script without a browser and an HTTP connection. I also set DOCUMENT_ROOT property emulating a browser and allowing file system manipulation without know the real_path.
In fact, is really easy to run the CI environment from a cronjob or command line. There are some steps you must follow:
- Copy the index.php file, that is the file that starts the CI environment, from the DOCUMENT_ROOT and give it a different name. I call it bot.php.
- Now you have to do some changes to the copied file in order to execute it from the command line/cronjob. You can start by removing the timeout expiration. This is a really “pain in the ass” when we want to process a lot of data. So, add this line to the top of the file:
// remove execution timeout
- Then you must emulate the browser by setting the value that CI uses to select the contoller/method that it will run. You can do it statically but I did it using an argument, allowing this file to run several scripts. This way you create an entry point from many cronjobs. Just for sanity check, you may had some verifications to the argument passed. This is unnecessary to protect from direct connections to the bot.php file, because when you use CI you have to set mod_rewrite and if you configure it well you will have almost any URL pointing to index.php, but it can be useful for value format mistakes.
// emulate the browser setting path_info passed by argument
if (!$argc || $argc!=3 || !eregi(“^([^\\’\”;]*)$”,$argv) || !eregi(“^([a-zA-Z0-9/\\_ -:.]*)$”,$argv)) exit;
$_SERVER[“PATH_INFO”] = $argv;
// emulate browser setting DOCUMENT_ROOT
$_SERVER[“DOCUMENT_ROOT”] = $argv;
- In my case, I put the bot.php just besides the index.php. So, I don’t need to change the system_folder variable neither the application_folder one. However, if you put it in an inner folder you must adjust these paths.
- Now you are able to use the CI environment resources, the controllers, libraries and models that you want. At this time you may code your controllers and methods and run them as a cronscript from the cronjob/command line. Don’t forget to protect your cronscript controller from connection from a web browser. To do this you must only add the following code to your controller constructor.
if($_SERVER[’SCRIPT_FILENAME’] != ‘bot.php’)
Now that you can run CI scripts from the command line or from a cronjob that you added to the crontab like following:
# execute cronjob every day at 2am
00 02 * * * /usr/local/bin/php5 $HOME/system/scripts/clean_cache.php
Thanks for user Thoer and Mhort from code igniter Wiki for the great job. Check the CI wiki post.