Перенос приложения php для обработки UTF-8

Я работаю над многоязычным приложением в php.

Все было хорошо до недавнего времени, меня попросили поддержать китайских иероглифов. Действия, которые я предпринял для поддержки символов UTF-8, следующие:

  • Все таблицы DB теперь UTF-8

  • HTML-шаблоны содержат тег <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

  • Контроллеры отправляют заголовок, определяющий кодировку (utf-8) для использования для ответа HTTP

Все было хорошо, пока я не начал делать строчные манипуляции (substr и подобные)

С китайским это не сработает, потому что китайский представлен как многобайт, и, следовательно, если вы делаете обычную подстроку (substr), она будет прорезать «букву» посреди одного из выделенных байт и f * ck до результата экран.

Я исправил ВСЕ свои проблемы, добавив это в бутстрап

mb_internal_encoding("UTF-8");

и заменяя все strlen , substr , strstr своими аналогами mb_ .

Что еще мне нужно сделать, чтобы полностью поддерживать UTF-8 в php?

Это немного больше, чем просто замена этих функций.

Обычные выражения

Вы должны добавить флаг utf8 ко всем регулярным выражениям PCRE, которые могут содержать строки, которые содержат символы не-Ascii, так что шаблоны интерпретируются как фактические символы, а не байты.

 $subject = "Helló"; $pattern = '/(l|ó){2,3}/u'; //The u flag indicates the pattern is UTF8 preg_match($pattern, substr($subject,3), $matches, PREG_OFFSET_CAPTURE); 

Также вы должны использовать классы символов Unicode, а не стандартные Perl, если вы хотите, чтобы ваши регулярные выражения были правильными для нелатинских алфавитов?

  • \ p {L} вместо \ w для любого символа 'letter'.
  • \ p {Z} вместо \ s для любого символа 'space'.
  • \ p {N} вместо \ d для любого символа 'digit', например арабские цифры

Существует множество различных классов символов Unicode, некоторые из которых довольно необычны для тех, кто привык читать и писать латинским алфавитом. Например, некоторые символы объединяются с предыдущим символом, чтобы создать новый символ. Более подробное объяснение их можно прочитать здесь .

Хотя в расширении mbstring есть функции регулярного выражения, они не рекомендуются для использования. Стандартные функции PCRE отлично работают с флагом UTF8.

Функциональные замены

Хотя ваш список – это начало, список функций, которые я нашел до сих пор, которые нужно заменить многобайтовыми версиями, длиннее. Это список функций с их функциями замены, некоторые из которых не определены в PHP, но доступны здесь на Github как mb_extra .

 $unsafeFunctions = array( 'mail' => 'mb_send_mail', 'split' => null, //'mb_split', deprecated function - just don't use it 'stripos' => 'mb_stripos', 'stristr' => 'mb_stristr', 'strlen' => 'mb_strlen', 'strpos' => 'mb_strpos', 'strrpos' => 'mb_strrpos', 'strrchr' => 'mb_strrchr', 'strripos' => 'mb_strripos', 'strstr' => 'mb_strstr', 'strtolower' => 'mb_strtolower', 'strtoupper' => 'mb_strtoupper', 'substr_count' => 'mb_substr_count', 'substr' => 'mb_substr', 'str_ireplace' => null, 'str_split' => 'mb_str_split', //TODO - check this works 'strcasecmp' => 'mb_strcasecmp', //TODO - check this works 'strcspn' => null, //TODO - implement alternative 'strrev' => 'mb_strrev', //TODO - check this works 'strspn' => null, //TODO - implement alternative 'substr_replace'=> 'mb_substr_replace', 'lcfirst' => null, 'ucfirst' => 'mb_ucfirst', 'ucwords' => 'mb_ucwords', 'wordwrap' => null, ); 

MySQL

Хотя вы бы подумали, что установка типа символа в utf8 даст вам поддержку UTF-8 в MySQL, это не так.

Это дает вам поддержку UTF-8, которые закодированы до 3 байт, а также Basic Multi-Language Plane . Однако люди активно используют символы, которым требуется кодирование 4 байта, включая большинство символов Эмоджи , также известные как дополнительный многоязычный самолет

Чтобы поддержать их, вы должны в основном использовать:

  • utf8mb4 – для кодировки вашего персонажа.
  • utf8mb4_unicode_ci – для сортировки символов.

Для конкретных сценариев существуют альтернативные варианты сортировки, которые могут вам пригодиться, но в целом придерживаться набора сопоставлений, который является наиболее правильным.

Список мест, где вы должны установить набор символов и сортировку в конфигурационном файле MySQL, это:

 [mysql] default-character-set=utf8mb4 [client] default-character-set=utf8mb4 [mysqld] init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci по [mysql] default-character-set=utf8mb4 [client] default-character-set=utf8mb4 [mysqld] init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci по [mysql] default-character-set=utf8mb4 [client] default-character-set=utf8mb4 [mysqld] init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci 

SET NAMES может не потребоваться при любых обстоятельствах – но это безопаснее только при небольшом штрафе за скорость.

Файл PHP INI

Хотя вы сказали, что вы установили mb_internal_encoding в свой сценарий начальной загрузки, гораздо лучше сделать это в файле PHP ini, а также установить все рекомендуемые параметры:

 mbstring.language = Neutral ; Set default language to Neutral(UTF-8) (default) mbstring.internal_encoding = UTF-8 ; Set default internal encoding to UTF-8 mbstring.encoding_translation = On ; HTTP input encoding translation is enabled mbstring.http_input = auto ; Set HTTP input character set dectection to auto mbstring.http_output = UTF-8 ; Set HTTP output encoding to UTF-8 mbstring.detect_order = auto ; Set default character encoding detection order to auto mbstring.substitute_character = none ; Do not print invalid characters default_charset = UTF-8 ; Default character set for auto content type header 

Помочь браузеру выбрать UTF8 для форм

  • Вам необходимо установить accept-charset в своих формах как UTF-8, чтобы сообщить браузеру, чтобы они представляли их как UTF8.

  • Добавьте символ UTF8 в форму в скрытом поле , чтобы остановить Internet Explorer (5, 6, 7 и 8) от представления формы как чего-то иного, кроме UTF8.

Разное

  • Если вы используете Apache, установите «AddDefaultCharset utf-8»,

  • Как вы сказали, вы делаете, но просто чтобы напомнить всем, кто читает ответ, установите мета-тип контента также в заголовке.

Это должно быть об этом. Хотя стоит прочитать статью « Что каждый программист, безусловно, нужно знать о кодировках и наборах символов для работы с текстом », я считаю, что лучше использовать UTF-8 всюду и поэтому не нужно тратить какие-либо умственные усилия на обработку разных наборы символов.