You are here

public static function Connection::open in Drupal 10

Same name in this branch
  1. 10 core/modules/sqlite/src/Driver/Database/sqlite/Connection.php \Drupal\sqlite\Driver\Database\sqlite\Connection::open()
  2. 10 core/modules/pgsql/src/Driver/Database/pgsql/Connection.php \Drupal\pgsql\Driver\Database\pgsql\Connection::open()
  3. 10 core/modules/mysql/src/Driver/Database/mysql/Connection.php \Drupal\mysql\Driver\Database\mysql\Connection::open()

File

core/modules/mysql/src/Driver/Database/mysql/Connection.php, line 117

Class

Connection
MySQL implementation of \Drupal\Core\Database\Connection.

Namespace

Drupal\mysql\Driver\Database\mysql

Code

public static function open(array &$connection_options = []) {
  if (isset($connection_options['_dsn_utf8_fallback']) && $connection_options['_dsn_utf8_fallback'] === TRUE) {

    // Only used during the installer version check, as a fallback from utf8mb4.
    $charset = 'utf8';
  }
  else {
    $charset = 'utf8mb4';
  }

  // The DSN should use either a socket or a host/port.
  if (isset($connection_options['unix_socket'])) {
    $dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
  }
  else {

    // Default to TCP connection on port 3306.
    $dsn = 'mysql:host=' . $connection_options['host'] . ';port=' . (empty($connection_options['port']) ? 3306 : $connection_options['port']);
  }

  // Character set is added to dsn to ensure PDO uses the proper character
  // set when escaping. This has security implications. See
  // https://www.drupal.org/node/1201452 for further discussion.
  $dsn .= ';charset=' . $charset;
  if (!empty($connection_options['database'])) {
    $dsn .= ';dbname=' . $connection_options['database'];
  }

  // Allow PDO options to be overridden.
  $connection_options += [
    'pdo' => [],
  ];
  $connection_options['pdo'] += [
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    // So we don't have to mess around with cursors and unbuffered queries by default.
    \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
    // Make sure MySQL returns all matched rows on update queries including
    // rows that actually didn't have to be updated because the values didn't
    // change. This matches common behavior among other database systems.
    \PDO::MYSQL_ATTR_FOUND_ROWS => TRUE,
    // Because MySQL's prepared statements skip the query cache, because it's dumb.
    \PDO::ATTR_EMULATE_PREPARES => TRUE,
    // Limit SQL to a single statement like mysqli.
    \PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE,
    // Convert numeric values to strings when fetching. In PHP 8.1,
    // \PDO::ATTR_EMULATE_PREPARES now behaves the same way as non emulated
    // prepares and returns integers. See https://externals.io/message/113294
    // for further discussion.
    \PDO::ATTR_STRINGIFY_FETCHES => TRUE,
  ];
  try {
    $pdo = new \PDO($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
  } catch (\PDOException $e) {
    if ($e
      ->getCode() == static::DATABASE_NOT_FOUND) {
      throw new DatabaseNotFoundException($e
        ->getMessage(), $e
        ->getCode(), $e);
    }
    if ($e
      ->getCode() == static::ACCESS_DENIED) {
      throw new DatabaseAccessDeniedException($e
        ->getMessage(), $e
        ->getCode(), $e);
    }
    throw $e;
  }

  // Force MySQL to use the UTF-8 character set. Also set the collation, if a
  // certain one has been set; otherwise, MySQL defaults to
  // 'utf8mb4_general_ci' (MySQL 5) or 'utf8mb4_0900_ai_ci' (MySQL 8) for
  // utf8mb4.
  if (!empty($connection_options['collation'])) {
    $pdo
      ->exec('SET NAMES ' . $charset . ' COLLATE ' . $connection_options['collation']);
  }
  else {
    $pdo
      ->exec('SET NAMES ' . $charset);
  }

  // Set MySQL init_commands if not already defined.  Default Drupal's MySQL
  // behavior to conform more closely to SQL standards.  This allows Drupal
  // to run almost seamlessly on many different kinds of database systems.
  // These settings force MySQL to behave the same as postgresql, or sqlite
  // in regards to syntax interpretation and invalid data handling.  See
  // https://www.drupal.org/node/344575 for further discussion. Also, as MySQL
  // 5.5 changed the meaning of TRADITIONAL we need to spell out the modes one
  // by one.
  $connection_options += [
    'init_commands' => [],
  ];
  $connection_options['init_commands'] += [
    'sql_mode' => "SET sql_mode = 'ANSI,TRADITIONAL'",
  ];

  // Execute initial commands.
  foreach ($connection_options['init_commands'] as $sql) {
    $pdo
      ->exec($sql);
  }
  return $pdo;
}