Checking for modifications to default.settings.php

Sat, 30/01/2021 - 16:45 -- James Oakley
Drupal

When you install a Drupal site, a settings.php file is created (either by you, or by the installer) to contain various settings specific to your site (such as database configuration, trusted hostnames, etc.). This is done by taking a copy of a file provided by Drupal core, default.settings.php, and adding or modifying the required lines.

As Drupal develops, additional features mean new things going into default.settings.php.

For example, after a long discussion, a new entry was added to default.settings.php with effect from Drupal 9.2

# $settings['update_fetch_with_http_fallback'] = TRUE;

This mitigates a potential man-in-the-middle attack with checking for updates to core and contributed modules. The point here is not to discuss that issue. This merely serves to illustrate something: Any Drupal site created before 9.2 will have its settings.php file based off the earlier default.settings.php file, and so won't have this entry with associated documentation comments.

This is going to become increasingly important. Before Drupal 8, major new Drupal releases would often involve creating a new settings.php file. Now, this file could persist as Drupal moves through 8.x, 9.x, 10.x, etc.

There needs to be some way to keep track of changes to default.settings.php between releases of Drupal core, so that any individual site's settings.php file can keep pace. Expecting site maintainers to comb the extensive release notes for every minor core release is not going to work; apart from the chance something might be missed, there is also the fact that sometimes smaller changes in a major release are documented in the release notes of a beta or release candidate.

To work, we need a solution that

  • Keeps track of the default.settings.php file off which the current settings.php file is based
  • Allows a (semi-)automated way to update settings.php files to incorporate changes
  • Alerts the site maintainer when the settings.php file has become stale.

This post will offer a solution, running through those 3 requirements

Keeping track of the defaults for the current settings.php

When you install your Drupal site, take a copy of default.settings.php. I'll call it last.default.settings.php.

Put it in web/sites/default, the same place as default.settings.php.

If your site is tracked with some kind of version control, make sure that file is included.

You now have a file that matches exactly the default.settings.php file used to create your site's settings.php file for the first time.

Checking when something has changed

We'll get to automating this in a bit.

But, for now, after any core update, you can run the following to check to see if default.settings.php has changed since you created settings.php.

diff -u web/sites/default/last.default.settings.php web/sites/default/default.settings.php

That command will return nothing if nothing has changed, or a diff of the changes if something has.

Incorporating changes (semi-)automatically

We can use that diff to change settings.php to incorporate any changes

cd web/sites/default
diff -u web/sites/default/last.default.settings.php web/sites/default/default.settings.php > settings-merge.patch
patch --dry-run settings.php < settings-merge.patch

As long as you're happy with what the dry-run says will happen, follow this with:

patch settings.php < settings-merge.patch
rm settings-merge.patch

Lastly, we need to copy the (changed) default.settings.php file. Your settings.php file is now based off the updated version, so we need to update the copy we're keeping to track this

cp -a default.settings.php last.default.settings.php

Take care, if patch creates a file called settings.php.orig containing the unaltered file, remove that before checking the changed version back into version control. If you're using version control, you don't need a separate copy of the old file anyway.

This is all only semi-automated, because it's possible that the patch won't apply cleanly (for example, if the changed portion of default.settings.php is too close to site-specific modifications you had made), in which case you'd have to make the changes manually.

Alerting the site maintainer

You could run that diff command manually after each core update. But it would be nice to automate that.

Fortunately, this is easily done.

I have a directory inside my composer root folder named hook-scripts. Your mileage may vary as to where you choose to put files like this, but working with my directory structure, create a file in hook-scripts named check-default-settings.

#!/bin/bash
DIFF=$(diff -q web/sites/default/last.default.settings.php web/sites/default/default.settings.php)
if [ ! -z "$DIFF" ]; then
  echo -e "\e[31mdefault.settings.php file has changed\e[0m"
fi

(Make sure you set the file to be executable, chmod +x)

If you execute that script, it will return nothing if default.settings.php is unchanged. But if your last.default.settings.php file no longer matches default.settings.php, it will print a message to that effect in red letters.

Now all we need to do is tell composer to call this script after each installation or update. I'll assume here that you know how to put pre / post update / install scripts into composer.json. But you want something like this:

    "scripts": {
        "post-update-cmd" : [
            "~/composer/hook-scripts/check-default-settings"
        ],
        "post-install-cmd" : [
            "~/composer/hook-scripts/check-default-settings"
        ]
    }

Now, every time Drupal core is updated (indeed, anything is updated) your script will run. If default.settings.php has changed, you'll be prompted in red lettering. You can then go and run the diff / patch commands above to make sure those changes are included for your site.

Blog Category: 

Comments

Andy Baker's picture
Submitted by Andy Baker on

My approach is to have a small custom settings.php, load the lastest defaults and tweak, eg:

include $app_root . '/' . $site_path . '/default.settings.php' ;

$databases['default']['default'] = array (
...
...

James Oakley's picture
Submitted by James Oakley on

Yes, that works. Simply include the default.settings.php file, and then add what you need to customise.

I don't actually put my database credentials in settings.php. They go in settings.local.php, so if that was all I used settings.php for, the file would be very small - just the include statement.

Thanks for this alternative. I'm sure it will help some, as it's certainly cleaner and simpler to set up. I think the reason I prefer the approach I use is that the comments documenting each entry in settings.php are very helpful, and there's something accessible about having all the configurable options and their docs in place. But advantages both ways, and I like yours too.

Andy Baker's picture
Submitted by Andy Baker on

Oh agreed. One still needs to check for changes (and their impact) to the default settings. Just another thought to add into the mix :-)

Add new comment

Additional Terms