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

Nov 11 2008

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

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

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

Ответы

1044 chazomaticus Nov 11 2008 at 04:43

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

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

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

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

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

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

    • Если вы используете уровень абстракции PDO с PHP ≥ 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 ≥ 5.2.3, вы можете позвонить mysql_set_charset.

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

  • В отношении utf8mb4/ utf8применяется то же соображение, что и выше.

Выход :

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

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

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

Вход :

  • К сожалению, вы должны проверять каждую полученную строку как действительную 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 : обратите внимание, что в спецификации W3C HTML говорится, что клиенты «должны» по умолчанию отправлять формы обратно на сервер в любой кодировке, которую обслуживает сервер, но это, по-видимому, всего лишь рекомендация, следовательно, необходимость явного указания для каждого отдельного <form>тег.

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

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

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

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

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

157 mercator Nov 13 2008 at 02:27

К отличному ответу chazomaticus я хотел бы добавить одну вещь :

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

<meta charset="utf-8">

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

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

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

Редактировать:

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

  • Часто задаваемые вопросы: изменение кодировки (X) HTML-страницы на UTF-8
  • Объявление кодировок символов в HTML
  • Учебник: наборы символов и кодировки в XHTML, HTML и CSS
  • Установка параметра кодировки HTTP

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

66 chroder Nov 11 2008 at 04:30

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

37 JimW. Sep 11 2012 at 22:40

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

25 JDelage Feb 24 2012 at 05:20

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

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

23 JimmyKane Jan 27 2014 at 16:16

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

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

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

INTL

Хороший:

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

Плохо:

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

mb_string

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

ICONV

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

БАЗЫ ДАННЫХ

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

Некоторые другие проблемы

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

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

15 PuertoAGP Sep 10 2014 at 10:39

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

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

14 MiguelStevens Jan 13 2014 at 16:37

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

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

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

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

10 AbdulSadikYalcin May 06 2015 at 04:36

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

Просмотреть источник

9 JW. Nov 11 2008 at 04:29

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

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

7 jalf Nov 11 2008 at 04:48

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

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

7 BudimirGrom Feb 12 2015 at 06:52

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

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

6 commonpike Jan 14 2011 at 23:13

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

это все !

2 castro_pereira Mar 25 2019 at 02:27

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

mysqli_set_charset($con,"utf8");

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

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

удачи!

Accountantم Aug 24 2019 at 02:10

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

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

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

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

IjazAhmedBhatti Sep 27 2020 at 13:24

в connection.php: mysqli_set_charset ($ con, «utf8»); и в sql collation utf = 8