Skip to content

Изменение кодировки таблиц. Решение для кодеров

После установки Drupal 7 на странице статуса можно увидеть:

Database 4 byte UTF-8 support
Enabled, but database tables need conversion
Please convert all database tables to utf8mb4 prior to enabling it in settings.php. See the documentation on adding 4 byte UTF-8 support for more information.

Речь о том, что база данных и таблицы ещё не переведены на utf8mb4 и не умеют нормально хранить эмодзи, некоторые иероглифы и спецсимволы.

Подготовка MySQL

Перед началом нужно:

  1. В my.cnf / mysqld.cnf убедиться, что заданы:

    ini
    [mysqld]
    innodb_large_prefix=true
    innodb_file_format=barracuda
    innodb_file_per_table=true
  2. Убедиться, что драйвер поддерживает utf8mb4 (libmysqlclient >= 5.5.3 или mysqlnd >= 5.0.9).

  3. Убедиться, что сервер MySQL не старее 5.5.3.

Настройка подключения Drupal

В settings.php в массиве $databases нужно проставить charset и collation:

php
<?php
$databases['default']['default'] = [
  'driver' => 'mysql',
  'database' => 'databasename',
  'username' => 'username',
  'password' => 'password',
  'host' => 'localhost',
  'charset' => 'utf8mb4',
  'collation' => 'utf8mb4_general_ci',
];

После этого Drupal начнёт ругаться уже на несоответствие таблиц.

Минимальное решение в лоб

Суть в двух запросах:

php
db_query("ALTER DATABASE my_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci");
foreach (db_query('SHOW TABLES')->fetchCol() as $table) {
  db_query("ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
}

Но лучше обернуть это в hook_update_N(), добавить проверки и корректно обновить статус Drupal.

Полный пример hook_update_N

php
<?php
/**
 * Implements hook_update_N().
 */
function MYMODULE_update_N() {
  $connection = Database::getConnection();
  $database_info = $connection->getConnectionOptions();
  $database = !empty($database_info['database']) ? $database_info['database'] : NULL;
  $collation = !empty($database_info['collation']) ? $database_info['collation'] : NULL;
  $charset = !empty($database_info['charset']) ? $database_info['charset'] : NULL;

  if (!$collation) {
    throw new Exception('Collation is not configured');
  }
  if (!$charset) {
    throw new Exception('Charset is not configured');
  }

  if ($database && $collation && $charset) {
    db_query("ALTER DATABASE $database CHARACTER SET = $charset COLLATE = $collation");
    foreach (db_query('SHOW TABLES')->fetchCol() as $table) {
      db_query("ALTER TABLE $table CONVERT TO CHARACTER SET $charset COLLATE $collation");
    }

    // Убираем предупреждение на странице статуса.
    if ($connection->utf8mb4IsConfigurable() && $connection->utf8mb4IsActive()) {
      variable_set('drupal_all_databases_are_utf8mb4', TRUE);
    }
  }
}

Перед запуском убедитесь, что:

  • в конфиге MySQL включены нужные опции;
  • в settings.php заданы charset и collation.