80

Basically, one of the greatest questions of all time: What are some ways you're using settings.php in your development/staging workflow?

Right now, I have my settings.php file set up like the following, and I base my development on the server's $HOST directive—meaning I can work on dev.example.com for the development (shared) server, local.example.com for my local computer (and other dev's local code checkouts), and www.example.com (or just example.com) for the live site.

(This code is in the 'Database settings' section of settings.php):

$host = $_SERVER['HTTP_HOST'];
$base_url = 'http://'.$host;
$cookie_domain = $host;

switch($host) {
  case 'example.com': # Production server
    $db_url = 'mysqli://prod_sql_user:[email protected]/prod_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
    );
    break;

  case 'dev.example.com': # Development server
    $db_url = 'mysqli://dev_sql_user:[email protected]/dev_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
    );
    break;

  case 'local.example.com': # Local server
    $db_url = 'mysqli://local_sql_user:[email protected]/local_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
      // Turn off most core caching.
      'cache_inc' => 'includes/cache.inc',
      'cache' => CACHE_DISABLED,
    );
    break;

}
?>

This works pretty well for most purposes, but it means we have a lot of extraneous code sitting around in our shared settings.php file... is there a better way?

1

7 Answers 7

66

What I do is separating that file into a settings.php and a local.settings.php.

At the end of settings.php is the following code:

if (file_exists(dirname(__FILE__) . '/local.settings.php')) {
  include dirname(__FILE__) . '/local.settings.php';
}

The local file is then excluded from whatever VCS you are using. The advantage is that you can put settings which are common over all instances in settings.php and have that versioned/distributed automatically and keep the local stuff in local.settings.php.

9
  • 2
    This is actually the strategy used on drupal.org itself and we use consistently at Palantir.net. For a bikeshed, I recommend using 'settings.local.php' as the filename as it matches the pattern set by 'settings.default.php'.
    – Dave Reid
    Commented Mar 2, 2011 at 21:26
  • 1
    I've created a gist for this: gist.github.com/1235389 since i've been using this more and more frequently
    – chrisjlee
    Commented Sep 22, 2011 at 17:22
  • 4
    Note: Drupal 8 has now added a similar snippet to the settings file by default, you just need to uncomment it: drupal.org/node/1118520
    – Berdir
    Commented Jun 1, 2012 at 17:45
  • 1
    @DaveReid: the pattern is set by 'default.settings.php' not by 'settings.default.php'.
    – iconoclast
    Commented Jul 31, 2012 at 19:29
  • 1
    For funsies you could use (__DIR__) instead of dirname(__FILE__). They are equivalent.
    – cdmo
    Commented Jul 26, 2013 at 13:33
25

This seems like you're reinventing Drupal's built in multisite functionality.

Personally, I keep all standard themes and modules for the site in sites/all, and then have sites/dev.example.com and sites/example.com.

As an added bonus you can then have different files folders for each site, and you can add any development modules to sites/dev.example.com/modules as well.

7
  • That makes some sense, but I have a few sites where there are 5-10 multisite folders already, and having all the themes for those sites in sites/all/themes can be quite annoying. Not to mention my typical use of custom.module for each site. I guess I could use sitename_custom.module instead :-/ Commented Mar 2, 2011 at 21:02
  • 2
    You could always try using symbolic links from the sites/dev.example.com/modules to sites/example.com/modules
    – Paul Jones
    Commented Mar 2, 2011 at 21:04
  • Accepting this answer - I'm going to try this on the site I'm currently working on. Looks like a good fit for my workflow. Commented Mar 2, 2011 at 21:16
  • 10
    I think this is actually a poor way to handle dev and staging environments because they aren't actually different/separate sites, just different versions of the same site. In this case you would very much want to avoid having separate files for each site. I'd very much recommend using the method mentioned below where settings.php is versioned and settings specific to each site (DB settings) are put in a local.settings.php that is not versioned.
    – Mikey P
    Commented Mar 3, 2011 at 3:46
  • 1
    @Mikey P - both solutions are valid—I think it's mostly up to personal/team preference here... there are tradeoffs with either approach, in my opinion. Commented Mar 3, 2011 at 18:01
11

I prefer to ignore the file locally (using a .gitignore file in git) and then keep separate versions if the file on each host.

4
  • 1
    This is an interesting solution, though I do like tracking settings.php in git (some bugs I've had crop up are due to setting.php changes...). Is there a way I could have my local git checkout replace that file with my own (besides having me copy in my own file)? Commented Mar 2, 2011 at 21:00
  • 1
    That's what I do too. Files with configuration data, especially with database credentials have no place in the VCS.
    – mmartinov
    Commented Mar 3, 2011 at 0:37
  • @geerlingguy yes you can. Please read my update (if it'll be published ;)
    – sobi3ch
    Commented Apr 3, 2015 at 10:32
  • @martin I agree, but let's don't forget we can have SPECIAL separate repo only for THIS file! You can read it in my update.
    – sobi3ch
    Commented Apr 3, 2015 at 10:34
6

I tend to always set up DNS or host file entries and use

dev.example.com
staging.example.com

and

example.com

Then I have completely separate settings file directories with differing files directories. For instance ./sites/dev.example.com/files

3
  • The problem I see with that approach is that I often have a /themes/ and /modules/ directory that I use for each site (often in a multisite setup), and since I need to use those site-specific modules and themes for local, dev and production, I can't just do hosts/multisite like that :-/ Commented Mar 2, 2011 at 20:58
  • Good point. I guess I left out that I symlink that stuff in. Commented Mar 2, 2011 at 21:09
  • You can create a symlink and share themes and modules folders that way. So basically you main folder will be a production folder and then from it you can create a symlinks to stage and dev and local.
    – gansbrest
    Commented Mar 2, 2011 at 21:10
5

Why not have a few folders based on the development host name?

Example

  • sites/dev1.domain.com
  • sites/dev2.domain.com
  • sites/dev3.domain.com
  • sites/www.domain.com

Each with their own settings file and db_url.

3
  • Potential problem: Files saved/uploaded in one site folder will not be accessible to another.
    – Greg
    Commented Mar 2, 2011 at 20:58
  • See my reply to @Stewart :) Commented Mar 2, 2011 at 20:59
  • Create symlinks to the central files folder
    – Kevin
    Commented Mar 2, 2011 at 21:09
2

If the only things changing are the database credentials, then you can set environment variables in your local (and staging/production) virtual host config or in a .htaccess a folder above your web root. Here's a simple example:

/var/www/example.com/drupal-resides-here

I can then create a .htaccess file here:

/var/www/example.com/.htaccess

which has the following code:

SetEnv DB1_USER my_local_user
SetEnv DB1_PASS my_local_pass
SetEnv DB1_HOST my_local_host
SetEnv DB1_NAME my_local_dbname

Then in /var/www/example.com/drupal-resides-here/sites/default/settings.php (or whatever) you can grab the db credentials like:

$db_url = "mysql://{$_SERVER['DB1_USER']}:{$_SERVER['DB1_PASS']}@{$_SERVER['DB1_HOST']}:{$_SERVER['DB1_PORT']}/{$_SERVER['DB1_NAME']}";

This lets multiple developers run things locally and you can push to staging / production while still tracking settings.php (there are more things in there than just the database credentials...). You also wouldn't have to keep track of multiple settings.php files.

3
  • I personally think this is the best way to go. However, our set up we add the SetEnv statements to the apache config. Makes it a bit more secure. Commented Dec 4, 2013 at 21:32
  • That's an interesting use for .htaccess and variable storage. But what about when you run drush up --y? That will overwrite your base .htaccess file.
    – Screenack
    Commented Jan 8, 2014 at 1:46
  • This is done in an .htaccess file a level above webroot. For example, /var/www/.htaccess stores these directives, and /var/www/drupal/.htaccess would be Drupal's .htaccess. You could also just put it in the Apache virtual host configuration, which is even nicer. Regardless of any of that, we almost always have custom stuff in the webroot's .htaccess and therefore if we update Drupal we need to compare the .htaccess changes with Git. Commented Jan 8, 2014 at 16:43
0

Simplest and most efficient solution that is just one line is the following. Just include it in the last line of your settings.php file:

@include('settings.local.php');

The @ symbol in the front just means don't display any error even if it doesnt find that file. Typical setup's like this involve a conditional to check if the file is there. This accomplishes it in one line without it.

http://php.net/manual/en/language.operators.errorcontrol.php

Also known as the STFU PHP operator.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.