Fix settings.php written to wrong directory when core/ is a symlink, fixes #38#47
Open
rfay wants to merge 6 commits into
Open
Fix settings.php written to wrong directory when core/ is a symlink, fixes #38#47rfay wants to merge 6 commits into
rfay wants to merge 6 commits into
Conversation
When web/core is a symlinked directory (as in this dev project layout), PHP resolves __DIR__ and realpath() to the real filesystem path, so core/install.php and DrupalKernel::guessApplicationRoot() both compute repos/drupal/ as the app root instead of web/. This causes the installer to write settings.php to repos/drupal/sites/default/ rather than web/sites/default/. Add two patches applied during post-drupal-scaffold-cmd: - scaffold-patch-install-php.patch: use $_SERVER['SCRIPT_FILENAME'] to derive the web root without resolving symlinks. - scaffold-patch-drupal-kernel-php.patch: use $_SERVER['DOCUMENT_ROOT'] in guessApplicationRoot() so InstallerKernel (constructed without an explicit app root) also resolves to the correct web root. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…aping Two bugs in the initial DrupalKernel patch: - PHP_SAPI !== 'cli' guard meant the fix was skipped for drush site:install - Shell escaping produced '/\\\\' (two backslashes) instead of '/\\' (one) The new guessApplicationRoot() fix: 1. Checks $_SERVER['DOCUMENT_ROOT'] unconditionally (it is only set by web servers, so it is naturally absent in CLI context). 2. For CLI (e.g. drush), falls back to the __DIR__-based computation, then verifies the result has autoload.php. If not, walks ancestor directories looking for a web root whose core/ symlink resolves to the same real path. Verified with drush site:install: settings.php now lands in web/sites/default/ rather than repos/drupal/sites/default/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GNU patch 2.7+ refuses to traverse symlinks in file paths. Applying the core patches from web/ via the web/core symlink therefore silently failed on Linux (DDEV containers), leaving DrupalKernel.php and install.php unpatched. Fix by applying the two core patches from repos/drupal/ directly, where the files exist at their real paths with no symlink traversal needed. The --follow-symlinks flag is also added in case any paths inside core/ are themselves symlinks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
install.php does chdir('..') which, when core/ is a symlink, resolves to
repos/drupal/. Our previous patch correctly set $root_path using
SCRIPT_FILENAME, but left CWD as repos/drupal/. The installer in
install.core.inc constructs settings file paths with './' . $site_path,
which is relative to CWD, so settings.php was still written to
repos/drupal/sites/default/ during a web install.
Fix by also calling chdir($root_path) after computing the correct web
root, so CWD and $root_path are consistent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
install_begin_request() uses dirname(__DIR__, 2) to pass the app root to Settings::initialize(), but __DIR__ resolves via the real filesystem path when core/ is a symlinked directory, giving repos/drupal/ instead of web/. Use DOCUMENT_ROOT (set by the web server, symlink-unaware) as the app root in web context, falling back to dirname(__DIR__, 2) for CLI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
repos/drupal/ has its own autoload.php, so the previous condition !is_file(autoload.php) never triggered and the ancestor search was skipped. The correct discriminator is whether core/ is a real directory (repos/drupal/) vs a symlink (web/): use !is_link(core/) so drush finds web/sites/default/settings.php and reads settings.ddev.php, preventing unnecessary rewrite of database credentials into settings.php. Applies same condition fix to both install.core.inc and DrupalKernel.php. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
|
i can confirm, the PR in combination with ddev/ddev#8366 fixes #38 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
This project places the Drupal git clone at
repos/drupal/and symlinksweb/core -> ../repos/drupal/core/. PHP resolves symlinks when computing__DIR__,realpath(), andchdir('..'), so several places in Drupal's installer computerepos/drupal/as the application root instead ofweb/. The result:settings.phpis written torepos/drupal/sites/default/instead ofweb/sites/default/, DDEV'ssettings.ddev.phpis never loaded, the web installer prompts for database credentials it should already know, and drush appends database credentials tosettings.phpunnecessarily.Root causes and fixes
Three files in Drupal core needed patching, each applied from
repos/drupal/(not throughweb/core) because GNU patch 2.7+ refuses to traverse symlinks.The key discriminator throughout is
is_link($path . '/core'): inrepos/drupal/,core/is a real directory; inweb/,core/is a symlink. Whencore/is a real directory, we search ancestor directories for a sibling whosecore/symlink resolves to the same real path.core/install.phpchdir('..')from inside the symlinkedcore/directory sets CWD torepos/drupal/. All relative paths (including'./' . $site_path . '/settings.php'ininstall.core.inc) then resolve underrepos/drupal/. Fix: use$_SERVER['SCRIPT_FILENAME'](set by nginx to the unresolved docroot path) to compute$root_path, then callchdir($root_path)to correct CWD.core/includes/install.core.incinstall_begin_request()callsSettings::initialize(dirname(__DIR__, 2), ...).__DIR__resolves via the real filesystem path torepos/drupal/core/includes, soSettings::initialize()looks forsettings.phpinrepos/drupal/sites/default/and finds nothing — causing the web installer to prompt for database config and drush to write credentials intosettings.php. In web context, use$_SERVER['DOCUMENT_ROOT']. In CLI context (drush), detect thatcore/is a real directory and search ancestor directories for the web root.core/lib/Drupal/Core/DrupalKernel.phpguessApplicationRoot()uses__DIR__for the same reason. Same fix:DOCUMENT_ROOTfor web context, ancestor directory search for CLI.Testing with DDEV
Requirements: DDEV installed.
Test 1 — drush install:
Expected:
settings.phpexists only atweb/sites/default/settings.phprepos/drupal/sites/default/settings.phpweb/sites/default/settings.phpTest 2 — web installer:
Drop the database and remove
settings.phpto start fresh:Visit
https://drupal-test.ddev.site/core/install.phpin a browser.Expected: the installer proceeds language → profile → "Installing Drupal" without prompting for database credentials (DDEV's
settings.ddev.phpis loaded automatically). After installation completes,settings.phpshould exist only atweb/sites/default/settings.php.Verify the wrong location is empty: