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

& Лт;!-- ВАЖНАЯ ИНФОРМАЦИЯ О НАЗВАНИИ ВОПРОСА Об этом заголовке было проведено длительное обсуждение по URL ниже. Не делайте никаких правоустановок без предварительного прочтения https://meta.stackoverflow.com/questions/335327/ -- > Я настраиваю новый сервер и хочу полностью поддерживать UTF-8 в своем веб-приложении. Я пробовал это в прошлом на существующих серверах и, кажется, всегда вынужден возвращаться к ISO-8859-1.

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

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

Комментарии к вопросу (4)
Решение

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

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

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

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

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

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

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

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

        $ mysqli- > set_charset ('utf8mb4'); // объектно-ориентированный стиль
        mysqli_set_charset ($ link, 'utf8mb4'); // процедурный стиль
    • Если вы застряли с простым 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 в качестве второго параметра.

Ввод :

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

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

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

Другие кодовые соображения :

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

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

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

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

Комментарии (15)

Я хотел бы добавить одну вещь к [отличному ответу chazomaticus](https://stackoverflow.com/questions/279170/utf-8-all-the-way-through # 279279):

Не забывайте также тег META (например, или его версия HTML4 или XHTML): ,

<meta charset="utf-8">

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

Я все делал правильно; база данных, подключение к базе данных и HTTP-заголовок Content-Type были установлены на UTF-8, и он работал нормально во всех других браузерах, но Internet Explorer все еще настаивал на использовании кодировки «Западная Европа».

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

< strong > Edit: < / strong >

Название < abbr = "World Wide Web Consortium" > W3C < / abbr > на самом деле имеет довольно большой < a href = "http://www.w3.org/International/"> section, посвященный < abbr title = "Internationalization" > I18N / abbr; > >. У них есть ряд статей, связанных с этой проблемой & ndash; описание HTTP, (X) HTML и CSS сторон:

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

Комментарии (5)

В дополнение к настройке 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 за кулисами, в любом случае, для повышения производительности.

Комментарии (1)

Я обнаружил проблему с кем-то, использующим 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.

Комментарии (2)

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

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

Комментарии (0)

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

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

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

INTL

Хорошо:

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

Плохой:

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

mb_string

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

ICONV

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

DATABASES

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

Некоторые другие Готча

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

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

Комментарии (1)

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

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

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

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

Комментарии (0)

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

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

Комментарии (0)

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

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

Комментарии (3)

Я только что прошел через ту же проблему и нашел хорошее решение в руководствах 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());
}

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

Комментарии (2)

Поддержка Unicode в PHP все еще в большом беспорядке. Хотя он способен преобразовывать строку ISO8859 (которую он использует внутри) в utf8, ему не хватает возможности работать со строками Unicode изначально, что означает, что все функции обработки строк будут искажать и повреждать ваши строки. Таким образом, вы должны либо использовать отдельную библиотеку для правильной поддержки utf8, либо переписать все функции обработки строк самостоятельно.

Простая часть - просто указание кодировки в заголовках HTTP и в базе данных и т. Д., Но ничего из этого не имеет значения, если ваш код PHP не выводит действительный UTF8. Это сложная часть, и PHP практически не помогает вам там. (Я думаю, что PHP6 должен исправить худшее из этого, но это еще немного)

Комментарии (0)

Если вы хотите, чтобы сервер MySQL определял набор символов, а не PHP как клиент (старое поведение; предпочтительнее, на мой взгляд), попробуйте добавить `skip-character-set-client-handshake к вашему my.cnf, в [ mysqld]и перезапуститеmysql.

Это может вызвать проблемы в случае, если вы используете что-либо, кроме UTF8.

Комментарии (0)

Главный ответ отличный. Вот что я должен был сделать при обычной настройке debian / php / mysql:

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

это было все !

Комментарии (0)

если вы хотите решение mysql, у меня были похожие проблемы с двумя моими проектами после миграции сервера. После поиска и опробования множества решений я столкнулся с этим / ничего, прежде чем этот работал):

mysqli_set_charset($con,"utf8");

После добавления этой строки в мой файл конфигурации все работает нормально!

Я нашел это решение https://www.w3schools.com/PHP/func_mysqli_set_charset.asp, когда я искал решение вставки из html-запроса

удачи!

Комментарии (0)

Просто примечание:

Вы сталкиваетесь с проблемой того, что ваши нелатинские символы отображаются как ?????????, вы задали вопрос, и он был закрыт со ссылкой на этот канонический вопрос, вы перепробовали все, и независимо от того, что вы делаете, вы все равно получаете??????????из MySQL.

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

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

Комментарии (0)