Какую кодировку (collation) лучше всего использовать в MySQL для PHP-проекта? Проблемы с русскими символами
Краткий ответ: используйте utf8mb4_unicode_ci
Для 99% современных PHP-проектов лучший выбор — это utf8mb4_unicode_ci. Но давайте разберём по порядку, почему именно она и что нужно сделать, чтобы всё заработало.
Почему не utf8_general_ci?
Раньше часто использовали utf8_general_ci, но у неё есть недостатки:
- Нет поддержки эмодзи и спецсимволов (например, 👍, ©, ®)
- Некорректная сортировка для некоторых языков (например, немецкого, французского)
- Более простая, но менее точная логика сравнения строк
Тип utf8 в MySQL — это псевдоним для utf8mb3, который поддерживает только символы из Basic Multilingual Plane (3 байта). utf8mb4 — полноценный 4-байтовый UTF-8, который включает эмодзи и редкие символы.
Что нужно сделать в PHP и MySQL?
Шаг 1. Измените кодировку таблицы и базы данных
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Шаг 2. Правильное подключение к MySQL
$db = new mysqli('localhost', 'root', '', 'mydb');
$db->set_charset('utf8mb4'); // ВАЖНО: используйте set_charset, а не SET NAMES
// Или если хотите через запрос:
// $db->query("SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'");
Шаг 3. Убедитесь, что PHP-файл сохранён в UTF-8 без BOM
Откройте ваш PHP-файл в редакторе (VS Code, PHPStorm, Sublime) и убедитесь, что кодировка файла — UTF-8. BOM (Byte Order Mark) в начале файла может вызывать проблемы.
Шаг 4. Добавьте мета-тег в HTML
<meta charset="UTF-8">
Шаг 5. Для старых версий PHP (до 5.6) — дополнительная настройка
// В php.ini или в начале скрипта:
ini_set('default_charset', 'UTF-8');
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
Сравнение популярных collation
| Collation | Особенности | Когда использовать |
|---|---|---|
utf8mb4_unicode_ci | Точное сравнение по стандарту Unicode, поддержка эмодзи | Рекомендуется для большинства проектов |
utf8mb4_unicode_520_ci | Улучшенная версия для Unicode 5.2 | Если нужна более точная сортировка |
utf8mb4_general_ci | Быстрее, но менее точная | Только для английского или когда скорость критична |
utf8mb4_bin | Сравнение по байтам (регистрозависимое) | Для паролей, хэшей, точного поиска |
Проверка работоспособности
После всех настроек выполните тестовый запрос:
$db->query("INSERT INTO users (name) VALUES ('Иван 👍')");
$result = $db->query("SELECT name FROM users WHERE id = LAST_INSERT_ID()");
$row = $result->fetch_assoc();
echo $row['name']; // Должно вывести: Иван 👍
Если всё ещё проблемы — проверьте, что my.cnf (my.ini на Windows) содержит:
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
После изменения конфига MySQL нужно перезапустить.
<<Альтернативный подход: используйте utf8mb4_general_ci для простых проектов
Если ваш проект — простой блог или форма обратной связи, где не нужны эмодзи и сложная сортировка, можно использовать utf8mb4_general_ci. Она работает немного быстрее, но менее точна в сортировке для некоторых языков.
Однако я не рекомендую использовать старую utf8_general_ci (без mb4) — она не поддерживает эмодзи, и рано или поздно вы с этим столкнётесь.
Ещё один важный момент: PDO
Если вы используете PDO вместо mysqli, настройка выглядит так:
$pdo = new PDO(
'mysql:host=localhost;dbname=mydb;charset=utf8mb4',
'root',
'',
[
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'",
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
Также не забывайте про mb_ функции в PHP для работы со строками:
// Вместо strlen() используйте mb_strlen()
// Вместо substr() используйте mb_substr()
echo mb_strlen('Привет'); // 6, а не 12 (если считать байты)
И последнее: если вы работаете с JSON, убедитесь, что json_encode() не портит кириллицу — добавьте флаг JSON_UNESCAPED_UNICODE.