views:

156

answers:

5

I'm trying to find a good way to maintain PHP configuration differences between a dev and live environment. I know how to handle differences when scripts are run by Apache (see below), but not when they are run on the command line, e.g. via cron.

Background info:

What do I mean by "configuration differences"? Like most code shops, we run a non-public 'staging' version of our website where we test code before it goes to the live website. We use Subversion and have the live website as 'Trunk' and 'Staging' as a branch. It makes life easier when code goes from staging to live if the repository version of the files have minimal differences. But obviously, some details need to be different, e.g. the DB connection details.

How configuration differences are solved with Apache

In PHP, we set branch specific variables as follows:

switch ($_SERVER['HTTP_HOST']) {
    case 'ourstagingurl.com':
        $dbPassword = "blahblah";
        break;
    default:
        $dbPassword = "blahblah";
}

or we put the following in the .htaccess file relevant to the specific site:

php_value dbPassword "blahblah"

Why I can't resolve configuration differences using the CLI?

When a script is run on the CLI, there's no super globals such as $_SERVER. I could include a config file using a absolute path but how can I know whether the script is from live or staging? I could pass in a command line argument that specifies the environment but I was hoping there was a better way?

+2  A: 

Hey, I work for a company with a similar setup. What I generally do is set up a scenerio where the staging and live servers both modify a common and generic config file. When the site is deployed on both the staging and live the information will be incorrect and will need to be modified once in each location. However, this will ONLY need to happen once because the parts you modify will be noted as modified by subversion and will not be overwritten by subversion in subsequent svn updates.

Jurassic_C
Thanks - but how do you include the config file in your scripts without introducing a difference between the live and staging code?
Tom
It could be im not understanding the question well enough, but it seems like the idea is to not contaminate your repository code with server specific configuration. You'll notice a lot of apps solve this problem by having a config.php.dist that has sample or blank configuration stuff. Then the installer copies config.php.dist to config.php and puts the real data in there. This will happen only once, obviously. Its kindof a slightly different paradigm than what I think you were shooting for, but I think its one that works.
Jurassic_C
@Jurassic_C - Thanks, the `config.php.dist -> config.php` tip is useful for deployment. But my problem is how to reference the `config.php` file in a PHP script which is run both by Apache and without Apache. Using `dirname(__FILE__)` in conjunction with `$_SERVER['DOCUMENT_ROOT']` has enabled me to solve my problem.
Tom
+2  A: 
$host = isset( $_SERVER['HTTP_HOST'] ) ? $SERVER_['HTTP_HOST'] : php_uname('n');

switch ( $host ) 
{
    case 'ourstagingurl.com':
        $dbPassword = "blahblah";
        break;
    default:
        $dbPassword = "blahblah";
}

If php version is => 5.3 then gethostname() could be used instead.

David
Thanks - the `php_uname()` is a good tip that I didn't know about. I did a quick test (`php -r 'echo gethostname()."\n";'`) and found that because our live and staging run on the same machine, it won't solve the problem :-(
Tom
+1  A: 

You can do as Jurassic suggested, or you can set an environment variable and read it in through $_ENV.

troelskn
$_ENV not $_SERVER
johannes
Thanks - But unfortunately this won't work because at the moment live and staging code are on the same server so they will share the same environment variables.
Tom
@Johannes: You're right (Though `$_SERVER` would work too).
troelskn
@tom you can set the env before running the command, or you can run it as two different users?
troelskn
+1  A: 

If live and staging are the same server (why don' t you use virtualisation?) then you'll probably have to resort to passing arguments to your scripts ie. call php script.php staging for staging and php script.php live for live site. BTW In case you wouldn' t know, the arguments are accessible using $argv in your PHP script -> http://www.php.net/manual/en/reserved.variables.argv.php.

Though maybe you could get part of the path of the file and use that as your "environment". ie. when file layout is /project/staging/script.php for staging and /project/live/script.php for live it should be easy to get the environment from the script itself using dirname(__FILE __) - extra space after FILE needs to be removed - and stripping the /project folder from it. Pretty stupid but it will work :p.

wimvds
Thanks - using `dirname(__FILE__)` in conjunction with `$_SERVER['DOCUMENT_ROOT']` has enabled me to solve my problem.
Tom
+1  A: 

In some of my applications, I attempt to include a file that only exists to override values on the development server. I use the dreaded @ operator, but you could do an is_file() as well.

@include 'includes/debug.php';

debug.php would attempt to set some variables:

define('DEBUG', true);
define('DB_PASSWORD', 'foobar');

I tell svn to ignore this file. It sticks around in my development checkout, and has a minimal impact on production.

More generally I use hostname checking as it works in both CLI and web apps, but you've stated you have both branches on the same box, so that's out.

Adam Backstrom