Сегодня зачищал PDOException: SQLSTATE: General error: 1366. Происходила ошибка при записи в базу UTF строк, содержащих неизвестные базе данных UTF символы. По логам было ясно, что и куда пытается сохранить программа.
Путей решения маячило целых два:
- «научить» базу понимать эти символы,
- убирать символы, вызывающие проблему.
Но сначала хотелось разобраться, чем одни UTF символы отличаются от других. Я не вдавался в подробности того как кодируется UTF, какие они бывают.
Оказалось, что UTF содержит символы, кодируемые последовательностью от 1 до 4 байт. Вот как они шифруются в бинарном коде:
1 2 3 4 |
0xxxxxxx 110xxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
В моем случае проблемы с базой вызвали 4х байтные символы.
«Учим» базу
Можно поменять тип поля на BLOB, чтобы база не производила проверку валидности UTF. А можно проверить всю цепочку соединения с базой, чтобы переключиться на поддержку кодировки utf8mb4.
Лично мне, вся эта псевдографика, которая засунута в 4х-байтные таблицы utf, совершенна не нужна, потому я пойду вторым путем.
Убираем 4х-байтные символы UTF из текста
Для PHP получился вот такой шаблон для замены:
1 2 |
//удалить 4х-байтные символы UTF $text = preg_replace("/[\xf0-\xf7][\x80-\xbf]{3}/", " ", $text); |
Если вдруг понадобится «почикать» 3х байтные, вот пример регулярного выражения и для него:
1 2 |
//удалить 3х-байтные символы UTF $text = preg_replace("/[\xe0-\xef][\x80-\xbf]{2}/", " ", $text); |