Setting environment vars for Codeigniter commandline

If you are not using environments for your CodeIgniter development, you're really missing out on a simple but effective tool. No need to change config settings to work locally, then try to remember to set them back before pushing out to your testing and live servers. (If you haven't used this before, catch up with it here )

Codeigniter uses a simple but generally effective trick for determining environments - your web server. Simply set your environment variable on each machine, and it will detect this and load the correct set of config files. It does this in the main CodeIgniter.php file:


if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
{
	require(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
}
else
{
	require(APPPATH.'config/constants.php');
}

But...what about when you aren't using your web server? How do you load the environment from your command line when you wish to do cron jobs or similar?

The answer is quite easy, but let's take this opportunity to learn a little more about the code that runs the command line functionality, deep in our URI.php code class.

The URI class works hand in hand with the Router class to determine how to turn your url request into a controller method call. The _fetch_uri_string() function decides what type of request is being made, and (in our case) seeing that it is from the cli, calls this simple function:

protected function _parse_argv()
{
	$args = array_slice($_SERVER['argv'], 1);
	return $args ? implode('/', $args) : '';
}

to remove the "php" from the command and piece the rest of it back together before handing it off to _set_uri_string() and back to the router. So what we would like to do is add one more argument that tells our app what environment to set.

However, looking at the above code, you see that we have a problem. The "php" command must go first, where it is removed, but then all the other arguments are imploded together. So we're going to need to intercept the arguments and grab our environment. What's more, we're going to need to do it before we call the Codeigniter.php file, because that's when we decide which set of config files to use (look back up at the top if you don't remember this), and even earlier than that for error reporting - our main index.php file, as high up as we can go.

So let's do some very basic php coding to capture the request and manipulate it as we like:


/*
Our goal is to send:
    php index.php cron daily_tasks important_job 123 --env production

and have it run http://mysite.com/cron/daily_tasks/important_job/123 
using the production environment

*/

// it's in two places - let's be smart	
define('DEFAULT_ENV', 'development');

// detects if it is a command line request
if ((php_sapi_name() == 'cli') or defined('STDIN'))
{
	$environment = DEFAULT_ENV;
	if (isset($argv)) 
	{
		// grab the --env argument, and the one that comes next

		$key = (array_search('--env', $argv));
		$environment = $argv[$key +1];

		// get rid of them so they don't get passed in to our method as parameter values

		unset($argv[$key], $argv[$key +1]);
	}  
  	define('ENVIRONMENT', $environment);
} 

if (!defined('ENVIRONMENT')) define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : DEFAULT_ENV);

Now we can set all our cron jobs with the additional parameter to tell it which configuration to use!

A Note: getopt() was a cleaner option than my $argv code, but it has only been available on Windows since 5.3, and even with 5.4 I found it to be unreliable. The code above won't win any beauty contests, but it will work just about anywhere.

Hope that helped!

Contact me