diff --git a/core/default.settings.php b/core/default.settings.php index 0de6589..ab603d0 100644 --- a/core/default.settings.php +++ b/core/default.settings.php @@ -45,8 +45,6 @@ * hostname with that number. For example, * http://www.drupal.org:8080/mysite/test/ could be loaded from * sites/8080.www.drupal.org.mysite.test/. - * - * @see \Drupal\Core\Utility\Site::getPath() */ /** @@ -66,16 +64,16 @@ * the database (files, system table, etc.) this will ensure the paths are * correct when the site is deployed to a live server. * - * Aliases are defined in an associative array in the format: + * Aliases are defined in an associative array named $sites. The array is + * written in the format: '..' => 'directory'. As an + * example, to map http://www.drupal.org:8080/mysite/test to the configuration + * directory sites/example.com, the array should be defined as: * @code - * '..' => 'directory', - * @endcode - * For example, to map http://www.drupal.org:8080/mysite/test to the directory - * sites/example.com, the array should be defined as: - * @code - * $sites['8080.www.drupal.org.mysite.test'] = 'example.com'; + * $sites = array( + * '8080.www.drupal.org.mysite.test' => 'example.com', + * ); * @endcode - * The URL http://www.drupal.org:8080/mysite/test/ could be a symbolic link or + * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or * an Apache Alias directive that points to the Drupal root containing * index.php. An alias could also be created for a subdomain. See the * @link http://drupal.org/documentation/install online Drupal installation guide @endlink @@ -83,16 +81,21 @@ * * The following examples look for a site configuration in sites/example.com: * @code - * # URL: http://dev.drupal.org + * URL: http://dev.drupal.org * $sites['dev.drupal.org'] = 'example.com'; - * # URL: http://localhost/example + * + * URL: http://localhost/example * $sites['localhost.example'] = 'example.com'; - * # URL: http://localhost:8080/example + * + * URL: http://localhost:8080/example * $sites['8080.localhost.example'] = 'example.com'; - * # URL: http://www.drupal.org:8080/mysite/test/ + * + * URL: http://www.drupal.org:8080/mysite/test/ * $sites['8080.www.drupal.org.mysite.test'] = 'example.com'; * @endcode * + * @see default.settings.php + * @see \Drupal\Core\Utility\Site::getPath() * @see http://drupal.org/documentation/install/multi-site */ # $sites = array(); diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 2d227c8..58187d3 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -248,36 +248,6 @@ function timer_stop($name) { } /** - * Returns the appropriate configuration directory. - * - * @param string $custom_path - * (optional) A custom $conf_path to set and statically cache. - * @param bool $reset - * Force a full search for matching directories even if one had been - * found previously. Defaults to FALSE. - * - * @deprecated Use \Drupal\Core\Utility\Site::getPath() instead. - */ -function conf_path($custom_path = NULL, $reset = FALSE) { - if (!empty($custom_path) && is_string($custom_path)) { - Site::setPath($custom_path); - } - if ($reset) { - Site::reset(); - } - return Site::getPath(); -} - -/** - * Finds the appropriate configuration directory for a given host and path. - * - * @deprecated Use \Drupal\Core\Utility\Site::getMultisitePath() instead. - */ -function find_conf_path($http_host, $script_name, $require_settings = TRUE, array $sites = array()) { - return $site->getMultisitePath($http_host, $script_name, $require_settings, $sites); -} - -/** * Returns the path of a configuration directory. * * @param string $type @@ -333,6 +303,8 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { * @see \Symfony\Component\HttpFoundation\Request::getClientIP() */ function drupal_override_server_variables($variables = array()) { + // @todo Neither \Drupal nor the class loader are 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. @@ -361,8 +333,6 @@ function drupal_override_server_variables($variables = array()) { // Replace elements of the $_SERVER array, as appropriate. $request->server->replace($variables + $server_vars + $defaults); - // @todo remove once \Drupal\Core\Utility\Site::getMultisitePath() no longer - // uses $_SERVER. $_SERVER = $request->server->all(); } @@ -451,27 +421,26 @@ function drupal_settings_initialize($require_settings = TRUE) { // Export these settings.php variables to the global namespace. global $sites, $databases, $cookie_domain, $conf, $db_prefix, $drupal_hash_salt, $base_secure_url, $base_insecure_url, $config_directories; $conf = array(); - // Include the global settings.php to determine whether the multi-site - // functionality is enabled. If settings.php is not required, then the caller - // is likely the installer, in which case the global settings.php may be used - // to enable the multi-site functionality to install Drupal into a - // site-specific directory. + + // Include settings.php to determine whether multi-site functionality is + // enabled. In the installer, $require_settings is FALSE, in which case the + // global settings.php may be used to enable the multi-site functionality + // to install Drupal into a site-specific directory. if ($require_settings || is_readable(DRUPAL_ROOT . '/settings.php')) { require_once DRUPAL_ROOT . '/settings.php'; } - // Discover the site directory, priming the static cache in - // Site::determinePath(). Make $conf_path available as a local variable in - // settings.php. - if (isset($conf_path)) { - Site::setPath($conf_path); - } + // Discover the site directory. + require_once __DIR__ . '/../lib/Drupal/Core/Utility/Site.php'; + Site::init(DRUPAL_ROOT, isset($sites) ? $sites : NULL, isset($conf_path) ? $conf_path : NULL, $require_settings); + + // Make conf_path() available as local variable in settings.php. $conf_path = Site::getPath(); - if (isset($sites) && Site::getPath() !== '.' && is_readable(Site::getAbsolutePath('settings.php'))) { + if (isset($sites) && Site::getPath() !== '' && is_readable(Site::getAbsolutePath('settings.php'))) { include_once Site::getAbsolutePath('settings.php'); } - require_once __DIR__ . '../../lib/Drupal/Component/Utility/Settings.php'; + require_once __DIR__ . '/../lib/Drupal/Component/Utility/Settings.php'; new Settings(isset($settings) ? $settings : array()); $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on'; @@ -1867,11 +1836,7 @@ function _drupal_bootstrap_configuration() { // Load the procedural configuration system helper functions. require_once __DIR__ . '/config.inc'; - // Set the Drupal custom error handler. - // Circular dependency: The error/exception handler requires config, which - // requires the service container, which requires the class loader, which - // requires $conf/settings.php (to be swappable). Therefore, errors in early - // bootstrap and settings.php cannot be handled by Drupal. + // Set the Drupal custom error handler. (requires \Drupal::config()) set_error_handler('_drupal_error_handler'); set_exception_handler('_drupal_exception_handler'); @@ -2171,12 +2136,13 @@ function _drupal_load_test_overrides($test_prefix) { } // Check for and load a settings.php file in the simpletest files directory. - $filename = Site::getPath('/files/' . $path_prefix . '/settings.php'); + $filename = Site::getAbsolutePath('files/' . $path_prefix . '/settings.php'); if (file_exists($filename)) { $settings = settings()->getAll(); - $conf_path = &drupal_static('conf_path'); + $conf_path = Site::getPath(); // This can override $conf, $conf_path, $settings, and $config_directories. include $filename; + Site::setPath($conf_path); // Keep the overriden $conf_path alive across drupal_static_reset() calls. // @see \Drupal\Core\Utility\Site::getSimpletestPath() $settings['simpletest_conf_path'] = $conf_path; diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 43085da..7e6cb05 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -285,11 +285,8 @@ function install_begin_request(&$install_state) { } // Perform a minimal bootstrap. - // This essentially calls _drupal_bootstrap_configuration(), which in turn - // calls drupal_settings_initialize() using the return value of - // drupal_installation_attempted() as argument. During installation, this - // causes drupal_settings_initialize() to not attempt to load any settings.php - // files, which allows to prime the site path to be used during installation. + // During installation, drupal_settings_initialize() will not attempt to load + // settings.php, so as to prime the site path to be used during installation. // By not requiring settings.php, a bare site folder can be prepared in the // /sites directory, which will be used for installing Drupal. drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); @@ -1083,8 +1080,7 @@ function install_verify_database_settings() { global $databases; if (!empty($databases)) { $database = $databases['default']['default']; - $settings_file = Site::getPath('settings.php'); - $errors = install_database_errors($database, $settings_file); + $errors = install_database_errors($database); if (empty($errors)) { return TRUE; } @@ -1105,7 +1101,6 @@ function install_verify_database_settings() { function install_settings_form($form, &$form_state, &$install_state) { global $databases; - $settings_file = Site::getPath('settings.php'); $database = isset($databases['default']['default']) ? $databases['default']['default'] : array(); drupal_set_title(t('Database configuration')); @@ -1152,7 +1147,6 @@ function install_settings_form($form, &$form_state, &$install_state) { ); $form['errors'] = array(); - $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file); return $form; } @@ -1186,7 +1180,7 @@ function install_settings_form_validate($form, &$form_state) { unset($database['db_prefix']); $form_state['storage']['database'] = $database; - $errors = install_database_errors($database, $form_state['values']['settings_file']); + $errors = install_database_errors($database); foreach ($errors as $name => $message) { form_set_error($name, $form_state, $message); } @@ -1195,7 +1189,7 @@ function install_settings_form_validate($form, &$form_state) { /** * Checks a database connection and returns any errors. */ -function install_database_errors($database, $settings_file) { +function install_database_errors($database) { global $databases; $errors = array(); @@ -1203,7 +1197,11 @@ function install_database_errors($database, $settings_file) { $database_types = drupal_get_database_types(); $driver = $database['driver']; if (!isset($database_types[$driver])) { - $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array('%settings_file' => $settings_file, '@drupal' => drupal_install_profile_distribution_name(), '%driver' => $driver)); + $errors['driver'] = t("In your %settings_file file you have configured @drupal to use a %driver server, however your PHP installation currently does not support this database type.", array( + '%settings_file' => Site::getPath('settings.php'), + '@drupal' => drupal_install_profile_distribution_name(), + '%driver' => $driver, + )); } else { // Run driver specific validation @@ -2393,9 +2391,9 @@ function install_check_requirements($install_state) { if (!$install_state['settings_verified']) { $readable = FALSE; $writable = FALSE; + $conf_path = Site::getPath(); $settings_file = Site::getPath('settings.php'); $default_settings_file = './core/default.settings.php'; - $conf_path = Site::getPath(); $file = $conf_path; $exists = FALSE; // Verify that the directory exists. diff --git a/core/lib/Drupal/Component/Utility/Path.php b/core/lib/Drupal/Component/Utility/Path.php deleted file mode 100644 index 709d4a3..0000000 --- a/core/lib/Drupal/Component/Utility/Path.php +++ /dev/null @@ -1,57 +0,0 @@ -root = $root_directory; + $this->sites = $sites; + + // An explicitly defined $conf_path in /settings.php takes precedence. + if (isset($custom_path)) { + $this->path = $custom_path; + } + // Check for a Simpletest override. + elseif ($simpletest_path = $this->getSimpletestPath()) { + $this->path = $simpletest_path; } - static::$root; + // If the multi-site functionality was enabled in /settings.php, discover + // the path for the current site. + // $sites just needs to be defined; an explicit mapping is not required. + elseif (isset($sites)) { + $this->path = $this->determinePath($sites, $require_settings); + } + // If the multi-site functionality is not enabled, the Drupal root + // directory is the site directory. + else { + $this->path = ''; + } + self::$instance = $this; } /** - * Determines the path to the site configuration. + * Finds the appropriate configuration directory for a given host and path. + * + * Finds a matching configuration directory file by stripping the website's + * hostname from left to right and pathname from right to left. By default, + * the directory must contain a 'settings.php' file for it to match. If the + * parameter $require_settings is set to FALSE, then a directory without a + * 'settings.php' file will match as well. The first configuration + * file found will be used and the remaining ones will be ignored. If no + * configuration file is found, returns a default value '$confdir/default'. See + * default.settings.php for examples on how the URL is converted to a directory. + * + * The settings.php file can define aliases in an associative array named + * $sites. The array is written in the format + * '..' => 'directory' + * + * As an example, to create a directory alias for + * http://www.drupal.org:8080/mysite/test whose configuration file is in + * sites/example.com, the array should be defined as: + * @code + * $sites = array( + * '8080.www.drupal.org.mysite.test' => 'example.com', + * ); + * @endcode + * + * @param array $sites + * A multi-site mapping, as defined in settings.php. + * @param bool $require_settings + * Only configuration directories with an existing settings.php file + * will be recognized. Defaults to TRUE. During initial installation, + * this is set to FALSE so that Drupal can detect a matching directory, + * then create a new settings.php file in it. * * @return string - * The relative path to the site path. May be an empty string, in case the - * site configuration directory is the Drupal root directory. + * The path of the matching configuration directory. May be an empty string, + * in case the site configuration directory is the root directory. + * + * @todo Inject a Request object in instead of relying on globals? */ - protected static function determinePath() { - // @todo Instead of setting a global change drupal_settings_initialize() to - // call a setSites() method on this object. - global $sites; + private function determinePath(array $sites, $require_settings) { + // The hostname and optional port number, e.g. "www.example.com" or + // "www.example.com:8080". + $http_host = $_SERVER['HTTP_HOST']; + // The part of the URL following the hostname, including the leading slash. + $script_name = $_SERVER['SCRIPT_NAME']; + if (!$script_name) { + $script_name = $_SERVER['SCRIPT_FILENAME']; + } - if (!isset(static::$path)) { - // Check for a simpletest override. - if ($simpletest_path = static::getSimpletestPath()) { - static::$path = $simpletest_path; - } - elseif (!empty($sites)) { - // @todo Require a request object to be passed in instead of relying on - // globals. - $http_host = $_SERVER['HTTP_HOST']; - // @todo Why does other code rely only on $_SERVER['SCRIPT_NAME'] and - // assume that to be non-empty? - $script_name = $_SERVER['SCRIPT_NAME']; - if (!$script_name) { - $script_name = $_SERVER['SCRIPT_FILENAME']; + $uri = explode('/', $script_name); + $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.'))))); + for ($i = count($uri) - 1; $i > 0; $i--) { + for ($j = count($server); $j > 0; $j--) { + $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); + // Check for an alias in $sites. + if (isset($sites[$dir])) { + $dir = $sites[$dir]; + if (!$require_settings) { + return $dir; + } + } + if ($require_settings) { + if (file_exists($this->root . '/sites/' . $dir . '/settings.php')) { + return "sites/$dir"; + } + } + elseif (file_exists($this->root . '/sites/' . $dir)) { + return "sites/$dir"; } - static::$path = static::getMultisitePath($http_host, $script_name, static::$custom, $sites); - } - // If the multi-site functionality is not enabled, the Drupal root - // directory is the site directory. - else { - static::$path = ''; } } - return static::$path; + return ''; } /** @@ -154,16 +176,21 @@ protected static function determinePath() { * @see \Drupal\Core\Utility\Site::determinePath() * @see _drupal_load_test_overrides() */ - protected static function getSimpletestPath() { + private function getSimpletestPath() { // Ensure that the settings object is available. Site::getPath() is called // once before the Settings class is included, and at that point it should // still load the primary $conf_path. See drupal_settings_initialize(). - // @todo Remove this, when possible. if (!class_exists('Drupal\Component\Utility\Settings', FALSE)) { return FALSE; } // If no $simpletest_conf_path is set, use the normal $conf_path. + + // @todo Critical race condition: This class discovers settings.php, and + // settings.php declares the $settings for instantiating Settings. + // The Settings singleton is not and cannot be instantiated at this point + // in time. + if (!($simpletest_conf_path = Settings::getSingleton()->get('simpletest_conf_path'))) { return FALSE; } @@ -179,65 +206,51 @@ protected static function getSimpletestPath() { return $simpletest_conf_path; } + private function resolvePath($filepath) { + if ($filepath !== '' && $filepath[0] === '/') { + $filepath = substr($filepath, 1); + } + if ($this->path !== '') { + if ($filepath !== '') { + $filepath = $this->path . '/' . $filepath; + } + else { + $filepath = $this->path; + } + } + return $filepath; + } + /** - * Finds the appropriate configuration directory for a given host and path. + * Returns the relative path to the site directory with an optional suffix. * - * Finds a matching configuration directory file by stripping the website's - * hostname from left to right and pathname from right to left. By default, - * the directory must contain a 'settings.php' file for it to match. If the - * parameter $require_settings is set to FALSE, then a directory without a - * 'settings.php' file will match as well. The first configuration - * file found will be used and the remaining ones will be ignored. If no - * configuration file is found, returns a default value '$confdir/default'. See - * default.settings.php for examples on how the URL is converted to a directory. + * Use this function instead of appending strings to the site path manually, + * because the site directory may be the root directory and thus the resulting + * path would be an absolute filesystem path. * - * If a file named sites.php is present in the $confdir, it will be loaded - * prior to scanning for directories. That file can define aliases in an - * associative array named $sites. The array is written in the format - * '..' => 'directory'. As an example, to create a - * directory alias for http://www.drupal.org:8080/mysite/test whose configuration - * file is in sites/example.com, the array should be defined as: - * @code - * $sites = array( - * '8080.www.drupal.org.mysite.test' => 'example.com', - * ); - * @endcode - * - * @param $http_host - * The hostname and optional port number, e.g. "www.example.com" or - * "www.example.com:8080". - * @param $script_name - * The part of the URL following the hostname, including the leading slash. - * @param $require_settings - * Defaults to TRUE. If TRUE, then only match directories with a - * 'settings.php' file. Otherwise match any directory. - * @param array $sites - * A multi-site mapping, as defined in settings.php. + * @param string $filepath + * (optional) A relative filepath to append to the site path. * * @return string - * The path of the matching configuration directory. - * - * @see default.settings.php - * @see \Drupal\Core\Utility\Site::determinePath() + * The given $filepath, potentially prefixed with the site path. */ - public static function getMultisitePath($http_host, $script_name, $require_settings, array $sites) { - $uri = explode('/', $script_name); - $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.'))))); - for ($i = count($uri) - 1; $i > 0; $i--) { - for ($j = count($server); $j > 0; $j--) { - $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); - // Check for an alias in $sites. - if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) { - $dir = $sites[$dir]; - } - if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) { - return "sites/$dir"; - } - } - } - return 'sites/default'; + public static function getPath($filepath = '') { + return self::$instance->resolvePath($filepath); } + /** + * Returns the absolute path to the site directory with an optional suffix. + * + * @param string $filepath + * (optional) A relative filepath to append to the site path. + * + * @return string + * The given $filepath, potentially prefixed with the site path, as an + * absolute filesystem path. + */ + public static function getAbsolutePath($filepath = '') { + return self::$instance->root . '/' . self::$instance->resolvePath($filepath); + } /** * Sets the site path to a given path. @@ -246,18 +259,16 @@ public static function getMultisitePath($http_host, $script_name, $require_setti * The relative path to the site configuration directory that will be set. */ public static function setPath($path) { - static::$custom = TRUE; - static::$path = $path; + self::$instance->path = $path; } /** * Resets the statically cached site path. + * + * @todo To be removed prior to commit. */ public static function reset() { - static::$path = NULL; - static::$custom = FALSE; - // static::$root is not reset because it only depends on the location of - // this file on the file system which cannot change during a single request. + self::$instance = NULL; } }