За последние 24 часа нас посетили 9259 программистов и 461 робот. Сейчас ищут 102 программиста ...

Про кодировку и базу

Тема в разделе "MySQL", создана пользователем artoodetoo, 19 фев 2016.

Статус темы:
Закрыта.
  1. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.329
    Симпатии:
    1.034
    Адрес:
    там-сям
    Вопрос о неправильном отображении русского текста из MySQL возникает как Феникс из пепла: снова и снова. Поэтому сделаю закрепленную тему с набором очевидностей. Это не мнение, это истина. Внимайте бандерлоги! :D

    Кодировка данных в базе и на странице могут отличаться (хотя стремиться к этому не надо). Всё будет хорошо, если ты точно сообщил кодировку браузеру и серверу MySQL. Даже если в базе данные кодируются иначе, чем на странице!

    Надо сообщить кодировку страницы и браузеру, и серверу БД! Обоим. Обязательно.

    Сообщить кодировку своего текста браузеру можно через http заголовок:
    Код (PHP):
    1. header('Content-type: text/html; charset=UTF-8');
    То же самое может делаться неявно самим веб-сервером. Прописывается в настройках один раз для всех страниц. Для Apache это директива конфигурации AddDefaultCharset, в nginx она называется просто charset.
    Код (Text):
    1. charset utf-8;
    Сообщить кодировку своего текста базе можно через запрос SET NAMES: (обрати внимание, в mysql принято писать utf8 без черточки).
    Код (PHP):
    1. mysqli_query($link, "SET NAMES UTF8"); // регистр не важен. важно чтобы чёрточки не было            
    ИЛИ, еще лучше сделать это специальным методом (он сам сделает "set names…" и еще кое-что)
    Код (PHP):
    1. mysqli_set_charset($link, "utf8");
    Если ты используешь pdo_mysql, нужно указать кодировку прямо в строке соединения:
    Код (PHP):
    1. $link = new PDO("mysql:host=localhost;dbname=DB;charset=UTF8", $user, $password);
    Если ты в своих скриптах хочешь использовать кодировку 1251, то для браузера это выглядит как "windows-1251", а для базы как "CP1251".
    При этом данные в таблице могут по прежнему оставаться в UTF8. Текст на странице выводится не в той кодировке, в какой хранится в базе, а в той, какую ты укажешь при соединении. База и без напоминаний знает про свои данные, ты сообщаешь ей про кодировку страницы!

    Ты сообщаешь свою кодировку серверу для того, чтобы он мог правильно перекодировать данные при передаче и в ту и в другую сторону. Если этого не сделать, mysql может считать, что ты работаешь с 8-ми битной шведской кодировкой и поэтому будет сохранять данные неправильно. А при выдаче будет перекодировать в обратную сторону — ты можешь долго не догадываться, что в базе хранится мусор. Пока не заметишь, что пара букв в тексте регулярно портится.

    Вывод: всегда явно указывай свою кодировку. Какая бы она ни была!

    Читай также:
     
    TheHate и SpikePHP нравится это.
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    10.329
    Симпатии:
    1.034
    Адрес:
    там-сям
    Дополнение:
    Какой collate выбрать внутри одной кодировки? Для UTF8, например, есть UTF8_GENERAL_CI, UTF8_UNICODE_CI, UTF8_BIN и другие.

    Когда вы ничего не указываете, по умолчанию будет использован *_general_ci и обычно это всех устраивает )))

    COLLATE управляет сортировкой и сравнением. В большинстве случаев разные коллейты работают одинаково. Однако шведский вариант латиницы, например, будет сортироваться немного иначе, чем "уникодный". Или символ "ö" может считаться равным буквосочетанию "oe" или неравным и т.д. Особняком стоит коллейт BIN ! Он предполагает точное побайтное сравнение (регистрозависимое). В то время как по умолчанию в MySQL строки сравниваются без учета регистра!
    Если вы выбираете вариант *_BIN, вы должны быть уверены на 100%, что именно он вам нужен.

    Теория ничто без практики. Поэкспериментируйте в любой консоли MySQL:
    Код (PHP):
    1. SELECT 'Value' = 'value' 
    вернет 1, то есть "истина"

    Укажем явно коллейт UTF8_GENERAL_CI
    Код (PHP):
    1. SELECT CAST('Value' AS CHAR CHARACTER SET utf8) COLLATE utf8_general_ci = 'value'; 
    вернет 1, то есть "истина"

    Заменим на _BIN:
    Код (PHP):
    1. SELECT CAST('Value' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin = 'value'; 
    вернет 0, то есть "ложь"

    Можете еще поиграться с вариантами хитрых латинских букв и посравнивать с простым написанием: Weiß, Müller, valúe …
     
Статус темы:
Закрыта.