diff --git a/core/default.settings.php b/core/default.settings.php index 9160653..ae4391d 100644 --- a/core/default.settings.php +++ b/core/default.settings.php @@ -2,7 +2,7 @@ /** * @file - * Drupal global configuration file. + * Drupal configuration file. * * IMPORTANT NOTE: * This file may have been set to read-only by the Drupal installation program. diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index a3f4d1e..6e41e61 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -274,7 +274,6 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { * @see \Symfony\Component\HttpFoundation\Request::getClientIP() */ function drupal_override_server_variables($variables = array()) { - // @todo \Drupal::request() is not available when this function is called. $request = \Drupal::request(); $server_vars = $request->server->all(); // Allow the provided URL to override any existing values in $_SERVER. @@ -303,10 +302,7 @@ function drupal_override_server_variables($variables = array()) { // Replace elements of the $_SERVER array, as appropriate. $request->server->replace($variables + $server_vars + $defaults); - // @todo Inject a global Request object for all CLI executions + use the - // manipulated $request->server as basis for any subsequently instantiated - // Request objects. Alternatively, sub-class Request or fix it upstream to - // account for CLI environments. + // @todo remove once conf_path() no longer uses $_SERVER. $_SERVER = $request->server->all(); } @@ -345,7 +341,7 @@ function drupal_environment_initialize() { error_reporting(E_STRICT | E_ALL | error_reporting()); // Override PHP settings required for Drupal to work properly. - // default.settings.php contains more runtime settings. + // settings.php contains more runtime settings. // The .htaccess file contains settings that cannot be changed at runtime. // Deny execution with enabled "magic quotes" (both GPC and runtime). @@ -391,11 +387,10 @@ function drupal_settings_initialize() { $config = array(); // Read the global /settings.php file. - // Exclude it for test requests to prevent settings of the parent site/ - // test-runner to leak into the test environment. + // Exclude it for test requests to prevent settings of the test runner from + // leaking into the test environment. if (!drupal_valid_test_ua() && is_readable(DRUPAL_ROOT . '/settings.php')) { require DRUPAL_ROOT . '/settings.php'; - } // Discover the site directory. @@ -407,7 +402,6 @@ function drupal_settings_initialize() { if ($conf_path !== '' && is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) { require DRUPAL_ROOT . '/' . $conf_path . '/settings.php'; } - // Initialize Settings. new Settings($settings); } @@ -425,7 +419,6 @@ function _drupal_request_initialize() { global $base_path, $base_root, $script_path; global $base_secure_url, $base_insecure_url; - $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on'; if (isset($base_url)) { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index cbf42d6..85df072 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -271,13 +271,6 @@ function install_begin_request(&$install_state) { drupal_override_server_variables($install_state['server']); } - // Initialize the Site directory. - // This primes the site path to be used during installation, to allow a bare - // site folder to be prepared in the /sites directory, which will be used for - // installing Drupal. - require_once DRUPAL_ROOT . '/core/lib/Drupal/Core/Utility/Site.php'; - Site::initInstaller(DRUPAL_ROOT); - // If the hash salt leaks, it becomes possible to forge a valid testing user // agent, install a new copy of Drupal, and take over the original site. // The user agent header is used to pass a database prefix in the request when @@ -288,6 +281,12 @@ function install_begin_request(&$install_state) { exit; } + // Initialize the Site directory. + // This primes the site path to be used during installation, to allow a bare + // site folder to be prepared in the /sites directory, which will be used for + // installing Drupal. + Site::initInstaller(DRUPAL_ROOT); + drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); // Ensure that procedural dependencies are loaded as early as possible, diff --git a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php index cbb596c..2ea5d8c 100644 --- a/core/lib/Drupal/Core/StreamWrapper/PublicStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/PublicStream.php @@ -6,6 +6,7 @@ */ namespace Drupal\Core\StreamWrapper; + use Drupal\Core\Utility\Site; /** diff --git a/core/lib/Drupal/Core/SystemListing.php b/core/lib/Drupal/Core/SystemListing.php index 6d895a2..b4509a3 100644 --- a/core/lib/Drupal/Core/SystemListing.php +++ b/core/lib/Drupal/Core/SystemListing.php @@ -6,6 +6,7 @@ */ namespace Drupal\Core; + use Drupal\Core\Utility\Site; /** diff --git a/core/lib/Drupal/Core/SystemListingInfo.php b/core/lib/Drupal/Core/SystemListingInfo.php index 3575adc..d302699 100644 --- a/core/lib/Drupal/Core/SystemListingInfo.php +++ b/core/lib/Drupal/Core/SystemListingInfo.php @@ -28,7 +28,6 @@ protected function profiles($directory) { // For SimpleTest to be able to test modules packaged together with a // distribution we need to include the profile of the parent site (in // which test runs are triggered). - // @todo !drupal_installation_attempted() defeats the whole purpose? if (drupal_valid_test_ua() && !drupal_installation_attempted()) { $testing_profile = \Drupal::config('simpletest.settings')->get('parent_profile'); if ($testing_profile && $testing_profile != $profile) { diff --git a/core/lib/Drupal/Core/Utility/Site.php b/core/lib/Drupal/Core/Utility/Site.php index 6711562..6c59f82 100644 --- a/core/lib/Drupal/Core/Utility/Site.php +++ b/core/lib/Drupal/Core/Utility/Site.php @@ -45,7 +45,7 @@ class Site { * * @var \Drupal\Core\Utility\Site */ - private $original; + private static $original; /** * The Site singleton instance. @@ -68,18 +68,21 @@ class Site { * @see drupal_settings_initialize() */ public static function init($root_directory, array $sites = NULL, $custom_path = NULL) { - if (!isset(self::$instance)) { - new self($root_directory); - } // Only the installer environment is allowed instantiate the Site singleton // prior to drupal_settings_initialize(). // @see initInstaller() - elseif (!self::$instance->isInstaller()) { - throw new \BadMethodCallException('Site path is initialized already.'); + if (isset(self::$instance)) { + if (!self::$instance->isInstaller()) { + throw new \BadMethodCallException('Site path is initialized already.'); + } + else { + // Disable the $isInstaller flag to prevent init() from being invoked + // more than once. + self::$instance->isInstaller = FALSE; + } } - // Force-override the site directory in tests. - if ($test_prefix = drupal_valid_test_ua()) { - $custom_path = 'sites/simpletest/' . substr($test_prefix, 10); + else { + new self($root_directory); } self::$instance->initializePath($sites, $custom_path); } @@ -98,68 +101,54 @@ public static function init($root_directory, array $sites = NULL, $custom_path = * @see install_begin_request() */ public static function initInstaller($root_directory) { - // WebTestBase::setUp() invokes Site::setUpTest() prior to invoking the - // non-interactive installer, in order to override the singleton and prime - // a custom site directory. - if (drupal_valid_test_ua()) { - return; - } if (isset(self::$instance)) { throw new \BadMethodCallException('Site path is initialized already.'); } // Set a global state flag to denote that we are operating in the special - // installer environment. initializePath() is unnecessary, as init() will be - // called by drupal_settings_initialize(), possibly passing new values from - // the newly created settings.php file. + // installer environment. new self($root_directory, TRUE); + self::$instance->initializePath(); } /** - * Re-initializes the Site singleton for a test run. - * - * Called by WebTestBase::setUp() prior to invoking the non-interactive - * installer for a test. + * Constructs the Site singleton. + */ + private function __construct($root_directory, $is_installer = FALSE) { + if (isset(self::$instance)/* && !self::$instance->isInstaller()*/) { + throw new \BadMethodCallException('Site path is initialized already.'); + } + $this->root = $root_directory; + $this->isInstaller = $is_installer; + self::$instance = $this; + } + + /** + * Re-initializes (resets) the Site singleton for a test run. * - * @param string $root_directory - * The root directory to use for absolute paths; i.e., DRUPAL_ROOT. - * @param string $custom_path - * The relative site directory path to use during the test run; e.g., - * 'sites/simpletest/123456'. + * @see \Drupal\simpletest\TestBase::prepareEnvironment() */ - public static function setUpTest($root_directory, $custom_path) { + public static function setUpTest() { + if (!isset(self::$instance)) { + throw new \RuntimeException('No original Site to backup. Missing invocation of Site::init()?'); + } if (!drupal_valid_test_ua()) { throw new \BadMethodCallException('Site is not executing a test.'); } - if (!file_exists($root_directory . '/' . $custom_path)) { - throw new \InvalidArgumentException("Test site directory '$custom_path' does not exist."); - } - new self($root_directory, TRUE, $custom_path); + self::$original = clone self::$instance; + self::$instance = NULL; } /** * Reverts the Site singleton to the original after a test run. + * + * @see \Drupal\simpletest\TestBase::restoreEnvironment() */ public static function tearDownTest() { - if (!isset(self::$instance->original)) { + if (!isset(self::$original)) { throw new \RuntimeException('No original Site to revert to. Missing invocation of Site::setUpTest()?'); } - self::$instance = self::$instance->original; - } - - /** - * Constructs the Site singleton. - */ - private function __construct($root_directory, $is_installer = FALSE, $custom_path = NULL) { - if (isset(self::$instance->original)) { - throw new \RuntimeException('Site is overridden for a test already. Duplicate invocation of Site::setUpTest()?'); - } - if (isset(self::$instance)) { - $this->original = clone self::$instance; - } - $this->root = $root_directory; - $this->isInstaller = $is_installer; - $this->path = $custom_path; - self::$instance = $this; + self::$instance = clone self::$original; + self::$original = NULL; } /** @@ -180,12 +169,9 @@ private function isInstaller() { * (optional) An explicit site path to set; skipping site negotiation. */ private function initializePath(array $sites = NULL, $custom_path = NULL) { - // When executing the non-interactive installer in the parent site/ - // test-runner, WebTestBase::setUp() primes the site directory path via - // Site::setUpTest() already. - // @todo Remove this case by adding a 'site' parameter to drupal_install(). - if (isset($this->path)) { - return; + // Force-override the site directory in tests. + if ($test_prefix = drupal_valid_test_ua()) { + $custom_path = 'sites/simpletest/' . substr($test_prefix, 10); } // An explicitly defined $conf_path in /settings.php takes precedence. @@ -278,6 +264,14 @@ private function determinePath(array $sites, $require_settings) { /** * Prefixes a given filepath with the site directory, if any. * + * Ensures that a given filepath does not result in an absolute filesystem + * path in case of a string concatenation like the following: + * @code + * // If $site_path is empty (Drupal's root directory), then the resulting + * // filesystem path would become absolute; e.g.: "/some/file" + * unlink($site_path . '/' . $some_file); + * @endcode + * * @param string $filepath * The filepath to prefix. * @@ -285,6 +279,7 @@ private function determinePath(array $sites, $require_settings) { * The prefixed filepath. */ private function resolvePath($filepath) { + // @todo Remove this convenience/sanity check? if ($filepath !== '' && $filepath[0] === '/') { $filepath = substr($filepath, 1); } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index c703d8d..26692bc 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -1072,8 +1072,11 @@ private function prepareEnvironment() { // After preparing the environment and changing the database prefix, we are // in a valid test environment. + if (!is_dir(DRUPAL_ROOT . '/' . $this->siteDirectory)) { + throw new \RuntimeException("Test site directory '$this->siteDirectory' does not exist."); + } drupal_valid_test_ua($this->databasePrefix); - Site::setUpTest(DRUPAL_ROOT, $this->siteDirectory); + Site::setUpTest(); drupal_set_time_limit($this->timeLimit); } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index aeea83d..afa9d12 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; +use Drupal\Component\Utility\Settings; use Drupal\Component\Utility\String; use Drupal\Core\DrupalKernel; use Drupal\Core\Database\Database; @@ -17,7 +18,6 @@ use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\UserSession; use Drupal\Core\StreamWrapper\PublicStream; -use Drupal\Core\Utility\Site; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\block\Entity\Block; use Symfony\Component\HttpFoundation\Request; @@ -775,7 +775,7 @@ protected function setUp() { // Copy and prepare an actual settings.php, so as to resemble a regular // installation. // Not using File API; a potential error must trigger a PHP warning. - copy(DRUPAL_ROOT . '/sites/default/default.settings.php', DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php'); + copy(DRUPAL_ROOT . '/core/default.settings.php', DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php'); // All file system paths are created by System module during installation. // @see system_requirements() @@ -786,7 +786,7 @@ protected function setUp() { ); // Add the parent profile's search path to the child site's search paths. // @see drupal_system_listing() - $settings['conf']['simpletest.settings']['parent_profile'] = (object) array( + $settings['config']['simpletest.settings']['parent_profile'] = (object) array( 'value' => $this->originalProfile, 'required' => TRUE, ); @@ -795,13 +795,16 @@ protected function setUp() { // Since Drupal is bootstrapped already, install_begin_request() will not // bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to // reload the newly written custom settings.php manually. - drupal_settings_initialize(); + require DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php'; + new Settings($settings); + $GLOBALS['config'] = $config; // Execute the non-interactive installer. require_once DRUPAL_ROOT . '/core/includes/install.core.inc'; install_drupal($parameters); // Import new settings.php written by the installer. + // @todo Fix non-interactive installer; this should happen automatically. drupal_settings_initialize(); foreach ($GLOBALS['config_directories'] as $type => $path) { $this->configDirectories[$type] = $path; @@ -883,7 +886,6 @@ protected function setUp() { * @see install_state_defaults() */ protected function installParameters() { - // The prefix is prepared in TestBase::changeDatabasePrefix() already. $connection_info = Database::getConnectionInfo(); $driver = $connection_info['default']['driver']; unset($connection_info['default']['driver']); @@ -1065,7 +1067,6 @@ protected function tearDown() { $this->kernel->shutdown(); } parent::tearDown(); - Site::tearDownTest(); // Ensure that internal logged in variable and cURL options are reset. $this->loggedInUser = FALSE; diff --git a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php index 76ce11f..224d8f5 100644 --- a/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/File/DirectoryTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\system\Tests\File; + use Drupal\Core\Utility\Site; /** diff --git a/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php index 656e47d..9a2bfa7 100644 --- a/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/File/ReadOnlyStreamWrapperTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\system\Tests\File; + use Drupal\Core\Utility\Site; /** diff --git a/core/modules/system/system.install b/core/modules/system/system.install index a2ecfe2..6d0ab12 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -230,7 +230,7 @@ function system_requirements($phase) { // Test configuration files and directory for writability. if ($phase == 'runtime') { $conf_errors = array(); - $conf_path = Site::getPath(); + $conf_path = Site::getPath(); # @todo if (!drupal_verify_install_file($conf_path, FILE_NOT_WRITABLE, 'dir')) { $conf_errors[] = t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array('%file' => $conf_path)); }