Какая кодировка и сортировка (collation) лучше всего подходят для MySQL в связке с PHP?
Правильный выбор: utf8mb4_unicode_ci
Коллега, вы столкнулись с классической проблемой, которая мучает новичков (и не только) уже много лет. Краткий ответ: используйте utf8mb4 как кодировку и utf8mb4_unicode_ci как collation. Это современный стандарт де-факто.
Давайте разберемся, почему старый utf8_general_ci не подходит, и как всё правильно настроить.
1. Почему utf8 — это ловушка?
В MySQL utf8 — это псевдоним для utf8mb3, который поддерживает символы только из базовой многоязычной плоскости (BMP). Это значит, что символы, занимающие 4 байта (например, эмодзи 😊, математические символы, редкие иероглифы), в него не помещаются. При попытке вставить такой символ MySQL либо обрежет его, либо заменит на ?.
Решение — utf8mb4 (UTF-8 Multibyte 4). Он поддерживает полный набор Unicode, включая эмодзи и редкие символы.
2. Сравнение collation: general vs unicode
utf8mb4_general_ci— старая, упрощенная сортировка. Она быстрее, но менее точная. Например, она не различает некоторые символы (вроде 'ß' и 'ss', 'æ' и 'ae'). Для русского языка разница минимальна, но для интернациональных проектов — критична.utf8mb4_unicode_ci— основана на стандарте Unicode Collation Algorithm (UCA). Она корректно обрабатывает все языки, правильно сортирует буквы с диакритикой и учитывает лигатуры. Это "золотой стандарт".utf8mb4_unicode_520_ci— более новая версия (на основе Unicode 5.20). Ещё точнее, но для 99% проектов разница незаметна.
Рекомендация: ставьте utf8mb4_unicode_ci. Если используете MySQL 8.0+, можно взять utf8mb4_0900_ai_ci (самый современный и точный вариант, но он несовместим со старыми версиями).
3. Полный пример настройки (исправляем ваш код)
Вам нужно изменить три вещи: саму таблицу, соединение с БД и, желательно, заголовки HTML.
<?php
// 1. Правильное соединение с PDO (указываем кодировку)
$pdo = new PDO(
'mysql:host=localhost;dbname=test;charset=utf8mb4', // <-- charset в DSN
'root',
'',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // отключаем эмуляцию для корректной работы с кодировками
]
);
// 2. Создаем таблицу с правильной кодировкой
$pdo->exec("
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
message TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
");
// 3. Вставка данных (остается без изменений, но работает корректно)
$stmt = $pdo->prepare("INSERT INTO comments (username, message) VALUES (?, ?)");
$stmt->execute([$_POST['username'], $_POST['message']]);
?>
Также не забудьте указать кодировку в HTML-шапке:
<meta charset="UTF-8">
И отправлять заголовок в PHP, если выводите данные:
header('Content-Type: text/html; charset=utf-8');
4. Проверка существующей БД
Если у вас уже есть таблицы в старой кодировке, их можно конвертировать:
ALTER TABLE comments CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Но будьте осторожны: если в данных уже есть битые символы, они не восстановятся — сначала нужно починить данные.
Итог
Для любого нового проекта на PHP + MySQL используйте utf8mb4_unicode_ci. Это решит проблему с кракозябрами, эмодзи и любыми редкими символами. Старый utf8_general_ci оставьте в прошлом — он годится только для легаси-проектов.
Альтернативный подход: utf8mb4_0900_ai_ci для MySQL 8.0+
Если вы используете MySQL версии 8.0 или выше, есть смысл обратить внимание на более современную collation — utf8mb4_0900_ai_ci.
Она основана на Unicode 9.0 (отсюда "0900") и использует алгоритм сортировки "accent insensitive" (ai — нечувствительность к диакритическим знакам) и "case insensitive" (ci — нечувствительность к регистру).
Преимущества перед utf8mb4_unicode_ci:
- Более точная и быстрая сортировка для современных языков.
- Лучшая поддержка редких символов и эмодзи.
- Оптимизирована под новые версии MySQL.
Недостаток: она несовместима с MySQL 5.7 и более старыми версиями. Если ваш хостинг использует старую версию (а таких ещё много), вы не сможете создать таблицу с такой collation — получите ошибку.
Пример использования:
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
message TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Резюме: если вы точно знаете, что у вас MySQL 8.0+, смело берите utf8mb4_0900_ai_ci. Если проект может переезжать на разные серверы — остановитесь на проверенном utf8mb4_unicode_ci, чтобы избежать проблем с совместимостью.