Avatar ·

Какую кодировку (collation) лучше всего использовать в MySQL для PHP-проекта? Проблемы с русскими символами

Всем привет! Я новичок в PHP и MySQL, и у меня возникла серьёзная проблема с отображением русских символов. У меня есть простая форма регистрации на PHP. Когда пользователь вводит имя на русском (например, "Иван"), в базе данных оно сохраняется как "?????" или "Р�ван". Я уже перепробовал кучу настроек, но ничего не помогает. Вот мой код подключения к БД: ```php $db = new mysqli('localhost', 'root', '', 'mydb'); $db->query("SET NAMES 'utf8'"); ``` И структура таблицы: ```sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100) ) DEFAULT CHARSET=utf8; ``` Данные вставляю так: ```php $name = $_POST['name']; $stmt = $db->prepare("INSERT INTO users (name, email) VALUES (?, ?)"); $stmt->bind_param("ss", $name, $email); $stmt->execute(); ``` При выводе на экран через echo тоже кракозябры. Я читал, что нужно выбрать правильную collation для MySQL, но их там десятки: utf8_general_ci, utf8_unicode_ci, utf8mb4_unicode_ci... В чём разница? Какую выбрать, чтобы и русский, и английский работали, и сортировка была нормальной? И нужно ли что-то менять в самом PHP, кроме SET NAMES? Заранее спасибо за помощь! Очень надеюсь на развёрнутый ответ для новичков. <<>>

Краткий ответ: используйте 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.