UTF-8 полностью через
Я настраиваю новый сервер и хочу полностью поддерживать UTF-8 в моем веб-приложении. Я пытался сделать это в прошлом на существующих серверах, и мне всегда приходилось прибегать к ISO-8859-1.
Где именно мне нужно установить кодировку/кодировки? Я знаю, что мне нужно настроить Apache, MySQL и PHP для этого - есть ли какой-то стандартный контрольный список, которому я могу следовать, или, возможно, устранить неполадки в случае несоответствия?
Это для нового сервера Linux, работающего под управлением MySQL 5, PHP, 5 и Apache 2.
Хранение данных:
-
Укажите
utf8mb4
символовutf8mb4
для всех таблиц и текстовых столбцов в вашей базе данных. Это заставляет MySQL физически хранить и извлекать значения, изначально закодированные в UTF-8. Обратите внимание, что MySQL будет неявно использовать кодировкуutf8mb4
еслиutf8mb4_*
сопоставлениеutf8mb4_*
(без явного набора символов). -
В более старых версиях MySQL (<5.5.3) вам, к сожалению, придется использовать просто
utf8
, который поддерживает только подмножество символов Unicode. Я хотел бы шутить.
Доступ к данным:
-
В коде вашего приложения (например, PHP), в каком бы методе доступа к БД вы ни использовали, вам нужно установить для charset соединения значение
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
относится кutf8mb4
/utf8
как и выше.
Выход:
-
Если ваше приложение передает текст в другие системы, они также должны быть проинформированы о кодировке символов. В веб-приложениях браузер должен быть проинформирован о кодировке, в которой отправляются данные (через заголовки ответа HTTP или метаданные HTML).
-
В PHP вы можете использовать опцию
default_charset
php.ini или вручную выполнить MIME-заголовокContent-Type
, который просто требует больше работы, но имеет тот же эффект. -
При кодировании вывода с использованием
json_encode()
добавьтеJSON_UNESCAPED_UNICODE
в качестве второго параметра.
Вход:
-
К сожалению, вы должны проверить каждую полученную строку как действительную UTF-8, прежде чем пытаться сохранить ее или использовать где-либо. PHP
mb_check_encoding()
делает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>
.
- Только для HTML до HTML5: вы хотите, чтобы все данные, отправляемые вам браузерами, были в формате UTF-8. К сожалению, если вы выбрали единственный надежный способ сделать это, добавьте атрибут
Другие соображения по коду:
-
Очевидно, что все файлы, которые вы будете обслуживать (PHP, HTML, JavaScript и т.д.), Должны быть закодированы в допустимом UTF-8.
-
Вы должны быть уверены, что каждый раз, когда вы обрабатываете строку UTF-8, вы делаете это безопасно. Это, к сожалению, самая сложная часть. Возможно, вы захотите широко использовать
mbstring
PHPmbstring
. -
Встроенные строковые операции 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 по-прежнему настаивал на использовании "западноевропейской" кодировки.
Оказалось, что на странице отсутствует тег META. Добавление этого решения проблемы.
Edit:
У W3C фактически есть довольно большой раздел посвященный I18N. У них есть ряд статей, связанных с этой проблемой – описывая HTTP, (X) HTML и CSS сторону вещей:
- FAQ: Изменение (X) кодировки HTML-страницы в UTF-8
- Объявление символьных кодировок в HTML
- Учебное пособие: наборы символов и кодировки в XHTML, HTML и CSS
- Настройка параметра charset 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, которая имеет хорошую поддержку unicode, graphemes, операции с строкой, локализация и многие другие, см. ниже.
Я приведу некоторую информацию о поддержке unicode в PHP с помощью slides Элизабет Смит в PHPBenelux'14
INTL
Хорошо:
- Обертка вокруг библиотеки ICU
- Стандартизованные локали, задайте локаль за script
- Форматирование чисел
- Форматирование валюты
- Форматирование сообщений (заменяет gettext)
- Календари, даты, часовой пояс и время
- Транслитератор
- Spoofchecker
- Ресурсные пакеты
- конвертеры
- Поддержка IDN
- графемы
- Сверка
- итераторы
Плохо:
- Не поддерживает zend_multibite
- Не поддерживает преобразование вывода ввода HTTP
- Не поддерживает перегрузку функций
mb_string
- Включает поддержку zend_multibyte
- Поддерживает прозрачную кодировку HTTP in/out
- Предоставляет некоторые оболочки для funtionallity, такие как 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
Некоторые другие Gotchas
- Вы не можете использовать имена файлов Unicode с PHP и Windows, если вы не используете расширение третьей части.
- Отправить все в ASCII, если вы используете exec, proc_open и другие вызовы командной строки
- Обычный текст не является обычным текстом, файлы имеют кодировки
- Вы можете конвертировать файлы "на лету" с фильтром iconv.
Я обновлю этот ответ, если что-то изменит добавленные функции и так далее.
Недавно я обнаружил, что использование strtolower()
может вызвать проблемы, когда данные усекаются после специального символа.
Решение заключалось в использовании
mb_strtolower($string, 'UTF-8');
mb_ использует MultiByte. Он поддерживает больше символов, но в целом немного медленнее.
Единственное, что я хотел бы добавить к этим замечательным ответам, - это подчеркнуть сохранение ваших файлов в кодировке utf8, я заметил, что браузеры принимают это свойство за установку utf8 в качестве кодировки кода. Любой достойный текстовый редактор покажет вам это, например Notepad ++ имеет пункт меню для подделки файлов, он показывает текущую кодировку и позволяет вам ее изменить. Для всех моих php файлов я использую utf8 без спецификации.
Некоторое время назад у меня кто-то попросил меня добавить поддержку utf8 для приложения php/mysql, разработанного кем-то еще, я заметил, что все файлы были закодированы в ANSI, поэтому мне пришлось использовать ICONV для преобразования всех файлов, изменения таблиц базы данных для использования команды utf8 charset и utf8_general_ci, добавьте "SET NAMES utf8" на уровень абстракции базы данных после подключения (если используете 5.3.6 или более раннее, иначе вам нужно использовать charset = utf8 в строке подключения) и изменить строковые функции для использования функциональные функции многобайтовой строки php эквивалентны.
В PHP вам нужно либо использовать функции multibyte, либо включить mbstring.func_overload. Таким образом, такие вещи, как strlen, будут работать, если у вас есть символы, которые принимают более одного байта.
Вам также потребуется определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать PHP-код, который возвращает заголовок. (Или вы можете добавить метку META в свои HTML-документы.)
Я только что прошел ту же проблему и нашел хорошее решение в руководствах 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());
}
Хорошая цель - с самого начала - основываясь на характере вашего сайта, я нашел много ресурсов по этому поводу в Googling - вы, конечно, не первый в этом разбираетесь.
Предполагается, что мистический PHP6 должен все это выпрямиться, верно?
Вы можете в значительной степени настроить utf-8 как глобальную кодировку по умолчанию для mysql на уровне сервера, и она по умолчанию будет правильно соответствовать более гранулированным уровням.
Поддержка 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, у меня были аналогичные проблемы с 2 из моих проектов, после миграции сервера. После поиска и опробования множества решений я наткнулся на это/ничего до того, как это сработало):
mysqli_set_charset($con,"utf8");
После добавления этой строки в мой конфигурационный файл все работает отлично!
Я нашел это решение https://www.w3schools.com/PHP/func_mysqli_set_charset.asp, когда искал решение для вставки из HTML-запроса
удачи!
Просто примечание:
Вы сталкиваетесь с проблемой того, что ваши нелатинские символы отображаются как ?????????
, вы задали вопрос, и он был закрыт со ссылкой на этот канонический вопрос, вы пробовали все, и независимо от того, что вы делаете, вы все равно получаете ??????????
из MySQL
.
Это происходит главным образом потому, что вы тестируете свои старые данные, которые были вставлены в базу данных с использованием неправильной кодировки, а также преобразованы и сохранены в символы знака вопроса ?
. Это означает, что вы потеряли свой оригинальный текст навсегда, и что бы вы ни пытались, вы получите ???????
.
Применение того, что вы узнали из ответов на этот вопрос на свежие данные, может решить вашу проблему.
Размещено как сообщество wiki:
Для пользователей WordPress:
- Выталкивается из этого вопроса ', показанный как? только на сервере Wordpress
Sidenote: вопрос был отменен. Сообщение было взято из:
-
и другое редактирование https://stackoverflow.com/revisions/35671546/6
Частичное сообщение:
У меня есть сайт wordpress, который я установил на своем локальном хосте. Я только что загрузил его на мой хостинг и импортировал базу данных, но все они отображаются как.
Решение из OP:
Для всех, у кого есть эта проблема, ниже это исправлено для меня. Он не был связан с базой данных.
Требуется обновление wp-config.php. Я изменил define('DB_CHARSET', 'utf8mb4');
на define('DB_CHARSET', 'utf8');