Settings.php 5.95 KB
Newer Older
1 2
<?php

3
namespace Drupal\Core\Site;
4

5
use Drupal\Component\Utility\Crypt;
6 7
use Drupal\Core\Database\Database;

8 9
/**
 * Read only settings that are initialized with the class.
10 11
 *
 * @ingroup utility
12 13
 */
final class Settings {
14 15

  /**
16 17
   * Array with the settings.
   *
18 19
   * @var array
   */
20
  private $storage = [];
21 22

  /**
23 24
   * Singleton instance.
   *
25
   * @var \Drupal\Core\Site\Settings
26
   */
27
  private static $instance = NULL;
28

29 30 31 32 33 34 35 36 37 38 39
  /**
   * Constructor.
   *
   * @param array $settings
   *   Array with the settings.
   */
  public function __construct(array $settings) {
    $this->storage = $settings;
    self::$instance = $this;
  }

40
  /**
41 42 43 44 45
   * Returns the settings instance.
   *
   * A singleton is used because this class is used before the container is
   * available.
   *
46
   * @return \Drupal\Core\Site\Settings
47 48 49
   *
   * @throws \BadMethodCallException
   *   Thrown when the settings instance has not been initialized yet.
50
   */
51
  public static function getInstance() {
52 53 54
    if (self::$instance === NULL) {
      throw new \BadMethodCallException('Settings::$instance is not initialized yet. Whatever you are trying to do, it might be too early for that. You could call Settings::initialize(), but it is probably better to wait until it is called in the regular way. Also check for recursions.');
    }
55 56 57
    return self::$instance;
  }

58 59 60 61 62 63 64 65 66 67
  /**
   * Protects creating with clone.
   */
  private function __clone() {
  }

  /**
   * Prevents settings from being serialized.
   */
  public function __sleep() {
68
    throw new \LogicException('Settings can not be serialized. This probably means you are serializing an object that has an indirect reference to the Settings object. Adjust your code so that is not necessary.');
69 70
  }

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
  /**
   * Returns a setting.
   *
   * Settings can be set in settings.php in the $settings array and requested
   * by this function. Settings should be used over configuration for read-only,
   * possibly low bootstrap configuration that is environment specific.
   *
   * @param string $name
   *   The name of the setting to return.
   * @param mixed $default
   *   (optional) The default value to use if this setting is not set.
   *
   * @return mixed
   *   The value of the setting, the provided default if not set.
   */
  public static function get($name, $default = NULL) {
87 88 89
    if ($name === 'install_profile' && isset(self::$instance->storage[$name])) {
      @trigger_error('To access the install profile in Drupal 8 use \Drupal::installProfile() or inject the install_profile container parameter into your service. See https://www.drupal.org/node/2538996', E_USER_DEPRECATED);
    }
90
    return isset(self::$instance->storage[$name]) ? self::$instance->storage[$name] : $default;
91 92 93 94 95 96 97 98 99
  }

  /**
   * Returns all the settings. This is only used for testing purposes.
   *
   * @return array
   *   All the settings.
   */
  public static function getAll() {
100
    return self::$instance->storage;
101 102
  }

103 104 105
  /**
   * Bootstraps settings.php and the Settings singleton.
   *
106 107
   * @param string $app_root
   *   The app root.
108 109
   * @param string $site_path
   *   The current site path.
110 111 112 113 114 115
   * @param \Composer\Autoload\ClassLoader $class_loader
   *   The class loader that is used for this request. Passed by reference and
   *   exposed to the local scope of settings.php, so as to allow it to be
   *   decorated with Symfony's ApcClassLoader, for example.
   *
   * @see default.settings.php
116
   */
117
  public static function initialize($app_root, $site_path, &$class_loader) {
118
    // Export these settings.php variables to the global namespace.
119
    global $config_directories, $config;
120 121 122
    $settings = [];
    $config = [];
    $databases = [];
123

124 125
    if (is_readable($app_root . '/' . $site_path . '/settings.php')) {
      require $app_root . '/' . $site_path . '/settings.php';
126 127 128 129 130 131 132 133 134
    }

    // Initialize Database.
    Database::setMultipleConnectionInfo($databases);

    // Initialize Settings.
    new Settings($settings);
  }

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  /**
   * Gets a salt useful for hardening against SQL injection.
   *
   * @return string
   *   A salt based on information in settings.php, not in the database.
   *
   * @throws \RuntimeException
   */
  public static function getHashSalt() {
    $hash_salt = self::$instance->get('hash_salt');
    // This should never happen, as it breaks user logins and many other
    // services. Therefore, explicitly notify the user (developer) by throwing
    // an exception.
    if (empty($hash_salt)) {
      throw new \RuntimeException('Missing $settings[\'hash_salt\'] in settings.php.');
    }

    return $hash_salt;
  }

155
  /**
156
   * Generates a prefix for APCu user cache keys.
157
   *
158
   * A standardized prefix is useful to allow visual inspection of an APCu user
159 160 161
   * cache. By default, this method will produce a unique prefix per site using
   * the hash salt. If the setting 'apcu_ensure_unique_prefix' is set to FALSE
   * then if the caller does not provide a $site_path only the Drupal root will
162 163
   * be used. This allows tests to use the same prefix ensuring that the number
   * of APCu items created during a full test run is kept to a minimum.
164 165
   * Additionally, if a multi site implementation does not use site specific
   * module directories setting apcu_ensure_unique_prefix would allow the sites
166
   * to share APCu cache items.
167 168 169 170 171 172
   *
   * @param $identifier
   *   An identifier for the prefix. For example, 'class_loader' or
   *   'cache_backend'.
   *
   * @return string
173
   *   The prefix for APCu user cache keys.
174 175
   *
   * @see https://www.drupal.org/project/drupal/issues/2926309
176 177 178
   */
  public static function getApcuPrefix($identifier, $root, $site_path = '') {
    if (static::get('apcu_ensure_unique_prefix', TRUE)) {
179
      return 'drupal.' . $identifier . '.' . \Drupal::VERSION . '.' . static::get('deployment_identifier') . '.' . hash_hmac('sha256', $identifier, static::get('hash_salt') . '.' . $root . '/' . $site_path);
180
    }
181
    return 'drupal.' . $identifier . '.' . \Drupal::VERSION . '.' . static::get('deployment_identifier') . '.' . Crypt::hashBase64($root . '/' . $site_path);
182 183
  }

184
}