UTF-8 полностью
Я настраиваю новый сервер и хочу полностью поддерживать UTF-8 в своем веб-приложении. Я пробовал это в прошлом на существующих серверах, и мне всегда приходилось возвращаться к ISO-8859-1.
Где именно мне нужно установить кодировку / кодировку? Я знаю, что для этого мне нужно настроить Apache, MySQL и PHP - есть ли какой-нибудь стандартный контрольный список, которому я могу следовать, или, возможно, устранить неполадки, где возникают несоответствия?
Это для нового сервера Linux, работающего под управлением MySQL 5, PHP, 5 и Apache 2.
Ответы
Хранение данных :
Укажите
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>
тег.
- Только для HTML до HTML5 : вы хотите, чтобы все данные, отправляемые вам браузерами, были в UTF-8. К сожалению, если вы идете единственным способом надежно сделать это добавить
Другие соображения по коду :
Очевидно, что все файлы, которые вы будете обслуживать (PHP, HTML, JavaScript и т. Д.), Должны быть закодированы в допустимом UTF-8.
Вы должны быть уверены, что каждый раз, когда вы обрабатываете строку UTF-8, вы делаете это безопасно. Это, к сожалению, самая сложная часть. Вероятно, вы захотите широко использовать mbstringрасширение PHP .
PHP встроенных в строковых операциях не по умолчанию UTF-8 сейф. Есть некоторые вещи, которые вы можете безопасно делать с обычными строковыми операциями PHP (например, конкатенация), но для большинства вещей вам следует использовать эквивалентную
mbstring
функцию.Чтобы знать, что вы делаете (читай: не испортить), вам действительно нужно знать UTF-8 и то, как он работает на самом низком уровне. Ознакомьтесь с любыми ссылками на utf8.com, чтобы найти полезные ресурсы, чтобы узнать все, что вам нужно знать.
К отличному ответу 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).
В дополнение к настройке 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 за кулисами для повышения производительности.
Я обнаружил проблему с кем-то, использующим 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.
В моем случае я использовал mb_split
, который использует регулярное выражение. Поэтому мне также пришлось вручную убедиться, что кодировка регулярного выражения была utf-8, выполнивmb_regex_encoding('UTF-8');
В качестве примечания я также обнаружил, запустив, mb_internal_encoding()
что внутренняя кодировка не является utf-8, и я изменил это, запустив mb_internal_encoding("UTF-8");
.
Прежде всего, если у вас <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
Я обновлю этот ответ, если что-то изменится, добавлены функции и так далее.
Единственное, что я бы добавил к этим удивительным ответам, - это подчеркнуть сохранение ваших файлов в кодировке utf8. Я заметил, что браузеры принимают это свойство, а не устанавливают utf8 в качестве кодировки кода. Любой приличный текстовый редактор покажет вам это, например, в Notepad ++ есть пункт меню для включения файла, он показывает текущую кодировку и позволяет изменить ее. Для всех моих файлов php я использую utf8 без спецификации.
Некоторое время назад меня попросили добавить поддержку utf8 для приложения php / mysql, разработанного кем-то другим, я заметил, что все файлы были закодированы в ANSI, поэтому мне пришлось использовать ICONV для преобразования всех файлов, изменить таблицы базы данных, чтобы использовать Кодировка utf8 и сопоставление utf8_general_ci, добавьте 'SET NAMES utf8' на уровень абстракции базы данных после подключения (при использовании версии 5.3.6 или более ранней версии, в противном случае вы должны использовать charset = utf8 в строке подключения) и измените строковые функции, чтобы использовать многобайтовый php эквивалент строковых функций.
Недавно я обнаружил, что использование strtolower()
может вызвать проблемы, когда данные обрезаются после специального символа.
Решением было использовать
mb_strtolower($string, 'UTF-8');
mb_ использует MultiByte. Он поддерживает больше символов, но в целом работает немного медленнее.
Я только что столкнулся с той же проблемой и нашел хорошее решение в руководствах по 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());
}
Просмотреть источник
В PHP вам нужно либо использовать многобайтовые функции , либо включить mbstring.func_overload . Таким образом, такие вещи, как strlen, будут работать, если у вас есть символы, занимающие более одного байта.
Вам также необходимо определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать PHP-код, который возвращает заголовок. (Или вы можете добавить в свои HTML-документы тег META.)
Поддержка Unicode в PHP по-прежнему представляет собой огромный беспорядок. Хотя он способен преобразовывать строку ISO8859 (которую он использует внутри) в utf8, ему не хватает возможности работать со строками Unicode изначально, что означает, что все функции обработки строк будут искажать и повреждать ваши строки. Поэтому вам придется либо использовать отдельную библиотеку для правильной поддержки utf8, либо самостоятельно переписать все функции обработки строк.
Легкая часть - просто указать кодировку в заголовках HTTP, в базе данных и т. Д., Но все это не имеет значения, если ваш PHP-код не выводит действительный UTF8. Это сложная часть, и PHP здесь практически не поможет. (Я думаю, что PHP6 должен исправить худшее из этого, но до этого еще немного)
Если вы хотите, чтобы набор символов определял сервер MySQL, а не PHP в качестве клиента (старое поведение; на мой взгляд, предпочтительнее), попробуйте добавить skip-character-set-client-handshake
в ваш my.cnf
, под [mysqld]
и перезапустить mysql
.
Это может вызвать проблемы, если вы используете что-либо, кроме UTF8.
Главный ответ - отлично. Вот что мне пришлось сделать при обычной настройке 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
это все !
Если вам нужно решение mysql, у меня были аналогичные проблемы с двумя моими проектами после миграции сервера. После поиска и опробования множества решений я столкнулся с этим / ничего до того, как это сработало):
mysqli_set_charset($con,"utf8");
После добавления этой строки в мой файл конфигурации все работает нормально!
Я нашел это решение https://www.w3schools.com/PHP/func_mysqli_set_charset.asp когда я хотел решить вставку из запроса html
удачи!
Просто примечание:
Вы столкнулись с проблемой ваших не латинских символов , показывая , как ?????????
вы задали вопрос, и он получил закрыт со ссылкой на этот канонический вопрос, вы перепробовали все , и независимо от того , что вы делаете , вы все еще получаете ??????????
от MySQL
.
В основном это связано с тем, что вы тестируете свои старые данные, которые были вставлены в базу данных с использованием неправильной кодировки и были преобразованы и сохранены в фактически символы вопросительного знака ?
. Это означает, что вы навсегда потеряли исходный текст, и что бы вы ни пытались, вы его получите ???????
.
Повторное применение того, что вы узнали из ответов на этот вопрос, на свежих данных может решить вашу проблему.
в connection.php: mysqli_set_charset ($ con, «utf8»); и в sql collation utf = 8