Codeigniter: Setting ENVIRONMENT configuration via Environment Variable

Created on 3 Mar 2012  Â·  33Comments  Â·  Source: bcit-ci/CodeIgniter

Setting ENVIRONMENT configuration via Environment Variable CI_ENV (in .htacess with SetEnv)

In your .htaccess:
SetEnv CI_ENV development

In your index.php
$env = getenv("CI_ENV");
$env_default = "development";
if ($env === false) { $env = $env_default; }
define('ENVIRONMENT', $env);

Most helpful comment

Hi All,
I am new to PHP I am facing an issue. I have a constant file where I have kept my constant file.

All 33 comments

This is a good tip but it doesn't belong in the core because not everyone can set environment variables. And not every one uses Apache.

if you don't use environment variable, don't worry, you can change $env_default = "development"; like now.
Every system has environment usually has variable.
If you use php-cli you can set environment variable in your shell.
In lighttpd you have directive like setenv.add-environment
in nginx you can use the directive like env ... and so on.
i'm really interested in your feedback.

Roberto, when multiple environment support was integrated with CodeIgniter, one of the wishes was that the way the environment is determined, is left to the individual developer. As @ericbarnes, every environment is different and it's not up to us to force people to use a certain method for determining the environment.

[quote]Every system has environment usually has variable.[/quote]

Even so not everyone uses hosting where the can change internals like this.

ok but this code:
$env = getenv("CI_ENV");
$env_default = "development";
if ($env === false) { $env = $env_default; }
define('ENVIRONMENT', $env);
permits you to manage your environment in the codeigniter classic way.
If you want to use "production": you can change $env_default to "production".
If you want to use "development": you can change $env_default to "development".
This is the same like today.
BUT the value added of this solution is that enable some developer to manage the environment with environment variable.
So, the developer can choose the way to define the environment: or changing the index.php (like today) or managing env var.

But if you don't agree with me... it's ok ;) It was just my personal suggestion. :)

That code is crazy complicated, if we do this we'll use this one:

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

I am tempted to do this with 3.0 but will need to run it past the team.

I think hard-coding the environment is a terrible idea. Honestly, do you expect the index.php to be edited for different environments? That completely defeats the object of having automated deployments!

There should be a choice of how the environment is determined. Config file entry, Webserver environment variable, etc. can all be accommodated without too much trouble. In fact, why not allow for a custom function? That would allow for a lot of flexibility.

$config['environment_detection_function'] = 'myEnvironmentFunction';
`

Let me again say that you have the ability to do whatever you like in the index.php, including reference a function. We don't need to explicitly state a callback as a string, just use a callback.

define('ENVIRONMENT', function(){ 
    // whatever
};

If you can't use PHP 5.3 then just declare a function then return it. This doesn't need to be overcomplicated, you're just setting a value to a string and you can do that in a bazillion ways in this file.

Of course you can do anything to index.php, however my point is that _by default_ CI should have this kind of thing be configurable. I don't see why anyone with 100 websites should have to patch index.php on all of them just because something that should be configurable is hard-coded.

Is modifying a config file hard coding?

The index.php is a "bootstrap" file and should be treated just as much "your territory" as the config files themsevles. It's not hacking, or patching, or being weird, it's just something you can modify.

I've seen HTTP_HOST switch statements, IP checks, all sorts of stuff. THAT is why we dont automatically enforce any logic.

Also, setting it to development by default kept things backwards compatible with 1.x, which is nice.

Our difference of opinions here comes down to you thinking modifying the index.php is a hack. Let me assure you, it really is not.

I agree with opensourceame !

@philsturgeon
Considers the following case : Upgrade to a new version of CI.

If you copy your index.php, you loose your modifications on this file...

Another case : You deploy your application in production
If you copy your index.php --> Big security problem (Your application is now configured as development) -> error_reporting(E_ALL)

It would be preferable to have a file : environment_rules.php in which you can define your environment.

Benefits :

  • Easier to deploy
  • Easier to upgrade

I don't consider "index.php" as my territory... Because CI team could modify this file for each new version of CI...
And as you said : "index.php" is a "bootstap file", not a "config file"...

If you override your database.php file then you will automatically loose your database config. How is that different?

We change how some of that works each time too. This is why most developers use version management and don't just copy ZIP files around wiping out random changes.

If you upgrade CodeIgniter that code will be replaced. Unless you back it up, or reapply the changes. This is the same as index.php.

Ok, we've reach a point were different philosophy encounter :

  • the manner of deploying
  • upgrading the framework
  • configuration

But think about other projects like an OS Kernel, software for example...

Is the bootstrap file a configuration file ?

In the future, if you add other configurable "things" in index.php...

What are you going to tell about the config folder to other users ?

  • In index.php you can configure "bla bla bla"
  • And in config/ folder you can configure DB, ROUTES etc...

Now, there is two place for configuration... index.php and the config/ folder...

config/ is where config goes.

index.php is a bootstrap file which in pretty much any framework is editable.

In there you can change the logic for how error reporing is handled. You can update paths so that APPPATH is somewhere different or BASEPATH has a different name.

Here is mine:

http://d.pr/i/lQl6

Since v1.0 of CodeIgniter you have always had a configurable index.php. Look, it even says half way down the file:

// --------------------------------------------------------------------
// END OF USER CONFIGURABLE SETTINGS.  DO NOT EDIT BELOW THIS LINE
// --------------------------------------------------------------------

To say that modifying index.php so that your personal ENV detection logic is available is a hack, is to say that CodeIgniter has ALWAYS been doing things wrong in index.php - which I disagree with.

I am perfectly content with modifying a bootstrap file to contain a few lines of logic. If you replace this file when you upgrade then that was silly. If you blindly replace ANY files that are not in version control then that is VERY silly. The framework should not have to protect you from silly mistakes like that.

I think that Version Control / blindly replace any file is NOT the subject of the discussion. (I use version control everyday)
And that's not because something is made from the beginning... that's not a mistake...

Application folder is dedicated to application...
System folder to CI

Index.php -> to ?

First part -> config
Next part -> system

Yes, correct.

Phil, I'm not sure why you're comparing editing config.php / database.php to hard coding. Is it because you're editing a PHP file? Would you take the view that editing a YAML / XML / JSON config file is the same as hard coding?

On that note it's my opinion that sticking config in a PHP file is rather dated and cumbersome and CI would do well to adopt smarter techniques of defining configs. For example, defining config in a YAML file allows my
Symfony and Python apps to share common settings such as DB connection details.

Yes, other frameworks let you edit the bootstrap file, but I've yet to see any other framework _require_ you to modify the bootstrap file before you can deploy to a production environment. IMO a developer should be able to upgrade core files in a framework without _having_ to edit them afterwards.

Looks like we're going to have a long conversation about this. Ok, let's look at the definition of hard-coding:

Hard-coded: Unchangeable. Hard-coded features are built into the hardware or software in such a way that they cannot be modified.

Hard coding the environment would be to set it to a specific value throughout the entire framework, but as it stands the value can be modified very easily in the "Configurable" area of the bootstrap file meaning that statement is not accurate.

You've randomly brought up YAML as an option, which is lovely but it's slow as hell to parse. Why throw in an extra format when PHP is pretty good at assigning values to variables?

Mainly here I have to ask what it is that you want. It started with a conversation about setting the ENVIRONMENT automatically, but guessing automatically is not cool and it's easy to "configure" this in your bootstrap file, so we started talking about config options.

I'm pointing out we don't need callbacks just for an if statement, and you're suggesting that editing the configurable area in the index.php is bad (even though CodeIgniter has always had a configurable area, and will always allow config in there for APPPATH and BASEPATH).

So, what is the current problem (as you use version control and understand that replacing files means potential loss of change). If this environment detection went into config.php would you be happier? How would you expect config.php to be found without setting this earlier on? We wouldn't even know what value APPPATH had without having configurable options in index.php, meaning the config file would never be found.

How about a general catch-all reference in the bootstrap index.php to a separate file containing your own code you wish to run at bootstrap time so that you can keep your stuff separate from CI's stuff, and CI not overwriting any values you have set?

When upgrading CI I'd love to just cp or rsync the new index.php to my project without having to think twice about carefully comparing the two files and merging back my own code. As Phil rightly pointed out, there are people that do a number of funky things in their bootstrap file - I'm one of them, but some separation between my stuff and CI's stuff would be lovely. Wouldn't providing a separate play place for setting your own variables using your own style and methodology fulfill a few desires being discussed here?

OK consider this: if I ionCube encode or HPHP compile a CI project I cannot deploy the same files to two different environments because the environment is set in the bootstrap. Likewise, I may want a sysadmin or deployment tool with read-only access to the code to be able to deploy and configure the project in different environments. Again, with an environment hard-coded into the bootstrap that's impossible.

Basically I'm saying that I believe a framework should be designed in such a way that it can be deployed to multiple environments on the assumption that the files are unalterable after deployment.

Regarding YAML, parsing is extremely quick if you use the PECL extensions, and you can always fall back to a native PHP parser if the extension isn't loaded. Plus, it's trivial to cache parsed YAML / JSON / XML configs to native PHP if necessary. There's no need to force anyone to use YAML but I think you should consider making it optional, as other frameworks have done.

@opensourceame So use environment variables as you suggested! You CAN do it your way, or the way I suggested in comments above, or you can check IP addresses, or check domain names, or use one of 50 available methods to detect which "environment" it is.

CodeIgniter is about giving people choices and assuming nothing. Assuming people will only want to change the environment in a single specified method is not cool, but you can set up your own however you like.

As for YAML, yes I know we could implement a parser - there are several options including PECL and PEAR code, but we don't require either of those for core functionality in this project. We could implement an existing library like the Zend_Config class does, but that is slow as hell. Reading a PHP file is OBVIOUSLY much quicker than reading YAML and more flexible too, so no YAML for CodeIgniter.

I like the way CodeIgniter handles environments – there’s only been a few occasions where I’ve re-used the same method, most of the time I’ve had to build something custom.

I think the confusion here seems to be some of you think you have to hardcode the environment into the public/index.php file. You don’t, but you have to hardcode your solution in – using whatever variables you want to – and that’s no different to any other framework. I don’t always like using .htaccess to decide this as is used in FuelPHP, because some projects .htaccess needs to be modified as the project develops, so I’d rather set it by URL.

Here’s FuelPHP’s “hardcoded” solution in app/bootstrap.php:

Fuel::$env = (isset($_SERVER['FUEL_ENV']) ? $_SERVER['FUEL_ENV'] : Fuel::DEVELOPMENT);

It’s in the App directory, so won’t get replaced when I upgrade the Core. So just replace:

define('ENVIRONMENT', 'development');

with

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

as per Phil’s suggestion – you’ve got the same solution. Considering that index.php already has $application_folder = 'application'; in it, you can’t overwrite it since version 1.x because it’ll screw up whatever settings you’ve already set.

I think Eric’s point that not everybody uses Apache is the best reason not to include a solution like this, and even if they do, they can’t always set environments.

This whole conversation has got big and ignored what I said originally

Like I said above:

... if we do this we'll use this one:

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

I am tempted to do this with 3.0 but will need to run it past the team.

This difference of opinion seems to indeed come from different ways of deploying CI based applications, and where and how to set the right configuration. I think that in the end while what Roberto proposes sounds interesting, it ultimately seems of limited extra value.

Why? Well, as Phil reminds us, index.php usually needs to be customised for each application and new deployment, and I think also between development of an app and production use, which makes it of less use to worry about having to check and potentially modify it upon newly deploying, or updating.

What is important is clearly marking what you might have to tweak for different situations, and possibly separating them depending on when you'd have to change their values.You will always (I think) have something like index.php, and then some further configuration because, again, depending on he circumstances you might have to change one thing about the working environment, or another, and someone else will want to modify other bits.

For me, ideally, app configuration would be only in the application/config folder, while changes between development and production, or individual deployment, would be, I think, in index.php.

In that light perhaps some part of application/config/ does not fit inside the application folder. Some of it depends on the nature of the application (that fits, like autoload.php, most of routes.php), other bits are environment dependant and could perhaps go somewhere else together with ENV discussed here, or values need to be tweaked per deployment (db authentication).

For me the most glaring file with this problem is, unsurprisingly, application/config/config.php, which mixes all three and more; app: index file; deployment: Site URL & URI PROTOCOL; session variables, machine:encryption key, language, Allowed URL charachers - either app, or deployment, or machine.

But as I indicated here: it might depend on circumstances when you'd have to change them: can you choose your dbname,id, etc, or not, for example - you don't always have perfect control over how you deploy and thus a separation will never be clean for all situations. As Phill says:
"We wouldn't even know what value APPPATH had without having configurable options in index.php, meaning the config file would never be found"
.- unless you want to hardcode APPATH, or some path at least, somewhere, you cannot really escape using the index.php file (under whatever name).

Thinks like YAML I would consider perhaps using in the frontend of my application to help endusers configure a very complex site with a lot of options, but using it with a framework like CI to set changes there seems overkill. Those who need to set these options are either developers or admins. Either way they will have to know how their system is set up to some extent, and tweak settings.

An expose, wich might help show my point of view:
The way I (try) to use CI, is to get the/a (git) repositoy for CI, and for any thing else that I pull in as components of an application; then for tweaks to those components, I use branches in the local repository; I have a (git) repository "apprepo" that pulls them in where I work on an application, so I can easily check differences between different versions, and easily know with what version I am working.

For local configuration (the test database, etc). on my development machine I have a separate "work-confg" repo that also gets pulled in so I can separate those before testing/deployment. The configuration changes that I need for the app (routes, etc.) go into the apprepo/config branch, because I need them wherever I use the app, but they don't change (shouldn't!) upon deployment. Note that an update of any component, be it CI, my own code, or any component, means a new version - usually with minor and/r clearly demarked changes, but a new version still, with possibly new config changes needed.

Before deploying a new version, I now have to remove the changes in the work-config branch. But this is fine, as at he end of my development a rebase to a known working version that end up being "released" is not a bad idea anyway - this version then is what becomes apprepo master, the basis for further work on the app.

I then test this release with an environment that matches production as best as I can. I have a "deploy-config" which changes to the intended setting for deployment (+version of the production db, but name comes from app-config). At the end of testing, that is the code that I drop onto a production machine. Here I don't need to change anything on that machine, unless my testing went wrong/was incomplete.

I do admit that initially index.php gave me a bit of a dillemma, as I wondered where most changes to it should be made (in what repositry), but in the end, the name of the application folder is app dependant for me (ie. goes in apprepo), with it's location usually fixed in the root of the site, and system location depends on the deployment (both possibly changing between work-config and deploy-config), and the environment likewise stored in those config branches. The database is a slight misfit: I have a name that comes from apprepo/config, but at least the authentication depends on the actual deployment, so that information needs to be checked for every machine (maybe it shouldn't be in application/config/?). That seems unavoidable however.

Unsubscribe.

+1 for

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

+2 :-)

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

+3

  • 4

Inviato da iPhone

Il giorno 02/giu/2012, alle ore 11:54, Toby [email protected] ha scritto:

+3


Reply to this email directly or view it on GitHub:
https://github.com/EllisLab/CodeIgniter/issues/1112#issuecomment-6076267

Ok, adding that then. Thanks guys.

For those that come via google to this thread i wanted to explain my personal solution for this issue. it is in my opinion the only way to deploy CI to various environments without touching the core files (index.php) and our edited configs are not overridden by an update, so updates are no problem anymore.

the only thing you should know is that i don't make use of the "official" ENVIRONMENT constant, because you cannot override constants in standard installations.

we leave the "development" environment as it is in index.php

in the "/application/config/" folder create a folder "development" (= the name of the ENVIRONMENT from index.php). CI first looks at this folder for present config files, if not found it uses the "normal" config files in "/application/config".

i decided to create a "constants.php" in that new folder, and added the following line on top:
require(dirname($_SERVER['SCRIPT_FILENAME']).'/application/config/'.basename(__FILE__));
and put only the changed lines after that. what happens is, that CI finds the custom config file, includes the original config file and after that it overriddes the original values with our changed lines. perfect so far. this can be done with each config file you want to make changes. so eventually new config lines are after the upgrade available but our changes aren't touched/resetted anymore.

in the constants.php i added my environment condition and added a MY_ENVIRONMENT constant, that can be called from everywhere of the MVCs.

then you could add to your database.php the db-entries for your environments and change the line
$active_group = 'default';
to
$active_group = MY_ENVIRONMENT;

hope that helps somebody, that way works for me on 2 installations without problems.

Hi All,
I am new to PHP I am facing an issue. I have a constant file where I have kept my constant file.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Tjoosten picture Tjoosten  Â·  6Comments

sasbass picture sasbass  Â·  7Comments

huehnerhose picture huehnerhose  Â·  6Comments

Struki84 picture Struki84  Â·  7Comments

it-can picture it-can  Â·  5Comments