UTF-8 полностью - PullRequest
       90

UTF-8 полностью

1105 голосов
/ 11 ноября 2008

Я настраиваю новый сервер и хочу полностью поддерживать UTF-8 в моем веб-приложении. Я пытался сделать это в прошлом на существующих серверах, и мне всегда приходилось прибегать к ISO-8859-1.

Где именно мне нужно установить кодировку / кодировки? Я знаю, что для этого мне нужно настроить Apache, MySQL и PHP - есть ли какой-нибудь стандартный контрольный список, которому я могу следовать, или, возможно, устранить неполадки в случае несоответствия?

Это для нового сервера Linux, работающего под управлением MySQL 5, PHP, 5 и Apache 2.

Ответы [ 14 ]

952 голосов
/ 11 ноября 2008

Хранение данных :

  • Укажите набор символов utf8mb4 для всех таблиц и текстовых столбцов в вашей базе данных. Это заставляет MySQL физически хранить и извлекать значения, изначально закодированные в UTF-8. Обратите внимание, что MySQL будет неявно использовать кодировку utf8mb4, если указано сопоставление utf8mb4_* (без какого-либо явного набора символов).

  • В более старых версиях MySQL (<5.5.3), к сожалению, вам придется использовать просто <code>utf8, который поддерживает только подмножество символов Unicode. Я бы хотел пошутить.

Доступ к данным :

  • В коде вашего приложения (например, PHP) в любом используемом вами методе доступа к БД вам нужно установить кодировку соединения на utf8mb4. Таким образом, MySQL не выполняет преобразование из собственного UTF-8, когда передает данные в ваше приложение, и наоборот.

  • Некоторые драйверы предоставляют собственный механизм для настройки набора символов соединения, который обновляет свое собственное внутреннее состояние и информирует MySQL о кодировке, которая будет использоваться в соединении - это обычно предпочтительный подход. В PHP:

    • Если вы используете слой абстракции PDO с PHP & ge; 5.3.6, вы можете указать charset в DSN :

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Если вы используете mysqli , вы можете позвонить set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Если вы застряли на обычном mysql , но у вас работает PHP & ge; 5.2.3, вы можете позвонить mysql_set_charset.

  • Если драйвер не предоставляет свой собственный механизм для установки набора символов соединения, вам, возможно, придется выполнить запрос, чтобы сообщить MySQL, как ваше приложение ожидает данные по соединению, которые будут закодированы: SET NAMES 'utf8mb4' .

  • То же самое относится к utf8mb4 / utf8, как и выше.

выход

  • Если ваше приложение передает текст в другие системы, они также должны быть проинформированы о кодировке символов. В веб-приложениях браузер должен быть информирован о кодировке, в которой отправляются данные (через заголовки ответа HTTP или метаданные HTML ).

  • В PHP вы можете использовать опцию default_charset php.ini или вручную выполнить заголовок Content-Type MIME самостоятельно, что просто больше работы, но имеет тот же эффект.

  • При кодировании вывода с использованием json_encode() добавьте JSON_UNESCAPED_UNICODE в качестве второго параметра.

Input

  • К сожалению, вы должны проверить каждую полученную строку как действительную UTF-8, прежде чем пытаться сохранить ее или использовать где-либо. PHP mb_check_encoding() делает свое дело, но вы должны использовать его неукоснительно. Это действительно невозможно, поскольку злонамеренные клиенты могут отправлять данные в любой нужной им кодировке, и я не нашел способа заставить PHP сделать это для вас надежно.

  • Из моего прочтения текущей спецификации HTML следующие подпункты больше не нужны и даже не действительны для современного HTML. Насколько я понимаю, браузеры будут работать и отправлять данные в наборе символов, указанном для документа. Однако, если вы ориентируетесь на более старые версии HTML (XHTML, HTML4 и т. Д.), Эти пункты могут быть полезны:

    • Для HTML до HTML5 только : вы хотите, чтобы все данные, отправляемые вам браузерами, были в UTF-8. К сожалению, если вы используете единственный надежный способ сделать это, добавьте атрибут accept-charset ко всем вашим тегам <form>: <form ... accept-charset="UTF-8">.
    • Для HTML до HTML5 только : обратите внимание, что спецификация HTML W3C говорит, что клиенты "должны" по умолчанию отправлять формы обратно на сервер в любой кодировке, которую обслуживал сервер, но это, очевидно, только рекомендация, отсюда необходимость явного указания на каждый тег <form>.

Другие вопросы кода :

  • Очевидно, что все файлы, которые вы будете обслуживать (PHP, HTML, JavaScript и т. Д.), Должны быть закодированы в допустимом UTF-8.

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

  • В PHP встроенные строковые операции не по умолчанию безопасны для UTF-8. Есть некоторые вещи, которые можно безопасно выполнять с помощью обычных строковых операций PHP (например, конкатенация) , но для большинства вещей вы должны использовать эквивалентную функцию mbstring.

  • Чтобы знать, что вы делаете (читай: не путайте), вам действительно нужно знать UTF-8 и как он работает на самом низком уровне. Проверьте любую из ссылок с utf8.com , чтобы найти полезные ресурсы, чтобы узнать все, что вам нужно знать.

141 голосов
/ 12 ноября 2008

Я бы хотел добавить одну вещь к превосходному ответу chazomaticus :

Не забудьте также метатег (например, или его HTML4 или XHTML ):

<meta charset="utf-8">

Это кажется тривиальным, но IE7 доставлял мне проблемы с этим раньше.

Я все делал правильно; база данных, соединение с базой данных и HTTP-заголовок Content-Type были настроены на UTF-8, и они прекрасно работали во всех других браузерах, но Internet Explorer все еще настаивал на использовании кодировки «Western European».

Оказалось, что на странице отсутствовал тег META. Добавление, которое решило проблему.

Edit:

W3C на самом деле имеет довольно большой раздел , посвященный I18N . У них есть ряд статей, связанных с этой проблемой & ndash; описание аспектов HTTP, (X) HTML и CSS:

Они рекомендуют использовать как заголовок HTTP, так и метатег HTML (или объявление XML, если XHTML служит XML).

59 голосов
/ 11 ноября 2008

В дополнение к настройке default_charset в php.ini, вы можете отправить правильный набор символов, используя header() из вашего кода, перед любым выводом:

header('Content-Type: text/html; charset=utf-8');

Работать с Unicode в PHP легко, если вы понимаете, что большинство строковых функций не работают с Unicode, а некоторые могут полностью искажать строки . PHP считает "символы" длиной 1 байт. Иногда это нормально (например, explode() только ищет последовательность байтов и использует ее в качестве разделителя - поэтому не имеет значения, какие именно символы вы ищете). Но в других случаях, когда функция фактически предназначена для работы с символами , PHP не знает, что ваш текст содержит многобайтовые символы, которые можно найти с помощью Unicode.

Хорошая библиотека для проверки: phputf8 . Это переписывает все «плохие» функции, чтобы вы могли безопасно работать со строками UTF8. Существуют такие расширения, как расширение mbstring, которые пытаются сделать это и для вас, но я предпочитаю использовать библиотеку, потому что она более переносима (но я пишу продукты для массового рынка, поэтому это важно для меня). Но phputf8 может в любом случае использовать mbstring для повышения производительности.

26 голосов
/ 11 сентября 2012

Старая тема, я знаю. Обнаружена проблема с кем-то, использующим PDO, и ответом было использование этого для строки подключения PDO:

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

Сайт, с которого я взял это, не работает, и, к счастью, смог получить его, используя кеш Google.

20 голосов
/ 24 февраля 2012

В моем случае я использовал mb_split, который использует регулярное выражение. Поэтому я также должен был вручную убедиться, что кодировка регулярного выражения была utf-8, выполнив mb_regex_encoding('UTF-8');

В качестве примечания я также обнаружил, запустив mb_internal_encoding(), что внутренняя кодировка не была utf-8, и изменил ее, запустив mb_internal_encoding("UTF-8");.

19 голосов
/ 27 января 2014

Прежде всего, если вы находитесь в <5.3PHP, то нет. У вас есть куча проблем для решения. </p>

Я удивлен, что никто не упомянул библиотеку intl , которая хорошо поддерживает юникод , графемы , строковые операции , локализация и многие другие, см. Ниже.

Я приведу некоторую информацию о поддержке юникода в PHP слайдов Элизабет Смит в PHPBenelux'14

INTL

Хорошо:

  • Обертка вокруг библиотеки ICU
  • Стандартизированные локали, настройка локали для скрипта
  • Форматирование чисел
  • Форматирование валюты
  • Форматирование сообщения (заменяет gettext)
  • Календари, даты, часовые пояса и время
  • Транслитератор
  • Spoofchecker
  • Ресурсные комплекты
  • Поддержка IDN
  • графема
  • Упорядочение
  • итераторы

Bad:

  • Не поддерживает zend_multibite
  • Не поддерживает преобразование ввода-вывода HTTP
  • Не поддерживает перегрузку функций

mb_string

  • Включает поддержку zend_multibyte
  • Поддерживает прозрачную кодировку HTTP in / out
  • Предоставляет некоторые обертки для функций, таких как strtoupper

Iconv

  • Основной для преобразования кодировки
  • Обработчик буфера вывода
  • Функциональность кодирования MIME
  • преобразование
  • некоторые строковые помощники (len, substr, strpos, strrpos)
  • Потоковый фильтр stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

БАЗ

  • mysql: Charset и сопоставление на таблицах и на соединении (не сопоставление). Также не используйте mysql - msqli или PDO
  • postgresql: pg_set_client_encoding
  • sqlite (3): убедитесь, что он был скомпилирован с поддержкой Unicode и Intl

Некоторые другие Gotchas

  • Вы не можете использовать имена файлов Unicode с PHP и Windows, если вы не используете расширение 3-й части.
  • Отправлять все в ASCII, если вы используете exec, proc_open и другие вызовы командной строки
  • Простой текст не является простым текстом, файлы имеют кодировки
  • Вы можете конвертировать файлы на лету с фильтром iconv

Я обновлю этот ответ, если что-то изменится, добавятся функции и так далее.

13 голосов
/ 13 января 2014

Я недавно обнаружил, что использование strtolower() может вызвать проблемы, когда данные усекаются после специального символа.

Решение было использовать

mb_strtolower($string, 'UTF-8');

mb_ использует MultiByte. Он поддерживает больше символов, но в целом немного медленнее.

12 голосов
/ 10 сентября 2014

Единственное, что я хотел бы добавить к этим удивительным ответам, - это сделать акцент на сохранении ваших файлов в кодировке utf8. Я заметил, что браузеры принимают это свойство вместо установки utf8 в качестве кодировки кода. Любой приличный текстовый редактор покажет вам это, например, Notepad ++ имеет пункт меню для добавления файла, показывает текущую кодировку и позволяет вам ее изменить. Для всех моих php-файлов я использую utf8 без спецификации.

Некоторое время назад у меня кто-то попросил меня добавить поддержку utf8 для приложения php / mysql, разработанного кем-то другим, я заметил, что все файлы были закодированы в ANSI, поэтому мне пришлось использовать ICONV для преобразования всех файлов, изменения таблиц базы данных. чтобы использовать кодировку utf8 и сборник utf8_general_ci, добавьте «SET NAMES utf8» к слою абстракции базы данных после подключения (если используется 5.3.6 или более ранняя версия, в противном случае необходимо использовать charset = utf8 в строке подключения) и изменить строковые функции, чтобы Эквивалент многобайтовых строковых функций php.

8 голосов
/ 06 мая 2015

Я только что прошел ту же проблему и нашел хорошее решение в руководствах по PHP.

Я изменил все свои кодировки файлов на UTF8, а затем кодировку по умолчанию для моего соединения. Это решило все проблемы.

if (!$mysqli->set_charset("utf8")) {
    printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

Просмотр источника

8 голосов
/ 11 ноября 2008

В PHP вам нужно либо использовать многобайтовые функции , либо включить mbstring.func_overload . Таким образом, такие вещи, как strlen, будут работать, если у вас есть символы, которые занимают более одного байта.

Вам также необходимо определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать код PHP, который возвращает заголовок. (Или вы можете добавить мета-тег в ваши HTML-документы.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...