Я настраиваю новый сервер и хочу полностью поддерживать UTF-8 в своем веб-приложении. Я пытался в прошлом на существующих серверах и всегда, кажется, должен вернуться к ISO-8859-1.
Где именно мне нужно установить кодировку / кодировки? Я знаю, что мне нужно настроить Apache, MySQL и PHP, чтобы сделать это – есть ли какой-то стандартный контрольный список, который я могу отслеживать, или, возможно, устранять неполадки, где возникают несоответствия?
Это для нового Linux-сервера, работающего под MySQL 5, PHP 5 и Apache 2.
Хранение данных :
Укажите utf8mb4
символов 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_charset
php.ini или вручную самостоятельно выпускать заголовок Content-Type
MIME, который просто больше работает, но имеет тот же эффект.
Вход :
К сожалению, вы должны проверить каждую полученную строку как действительную UTF-8, прежде чем пытаться ее сохранить или использовать в любом месте. PHP mb_check_encoding()
делает трюк, но вы должны использовать его религиозно. На самом деле этого не происходит, так как вредоносные клиенты могут отправлять данные в любую кодировку, которую они хотят, и я не нашел трюка, чтобы заставить PHP сделать это для вас надежно.
Из моего чтения текущей спецификации HTML следующие субпалеты не нужны или даже не действительны для современного HTML. Я понимаю, что браузеры будут работать и отправлять данные в набор символов, указанный для документа. Однако, если вы ориентируетесь на более старые версии HTML (XHTML, HTML4 и т. Д.), Эти пункты могут по-прежнему быть полезными:
accept-charset
ко всем тэгам <form>
: <form ... accept-charset="UTF-8">
. <form>
. Другие кодовые соображения :
Очевидно, что все файлы, которые вы будете обслуживать (PHP, HTML, JavaScript и т. Д.), Должны быть закодированы в действительном UTF-8.
Вы должны убедиться, что каждый раз, когда вы обрабатываете строку UTF-8, вы делаете это безопасно. Это, к сожалению, тяжелая часть. Вероятно, вы захотите широко использовать mbstring
PHP mbstring
.
Встроенные строковые операции 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. Добавление этого решения проблемы.
Редактировать:
W3C фактически имеет довольно большой раздел, посвященный I18N . У них есть ряд статей, связанных с этой проблемой – описание HTTP, (X) HTML и CSS сторон:
Они рекомендуют использовать как 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
, который использует regex. Поэтому мне также пришлось вручную убедиться, что кодировка регулярных выражений была utf-8, выполнив mb_regex_encoding('UTF-8');
В качестве дополнительной заметки я также обнаружил, запустив mb_internal_encoding()
что внутренняя кодировка не была utf-8, и я изменил ее, запустив mb_internal_encoding("UTF-8");
,
Прежде всего, если вы находитесь в <5.3PHP, то нет. У тебя много проблем, чтобы справиться.
Я удивлен, что никто не упомянул библиотеку intl , которая имеет хорошую поддержку для unicode , графемы , строковые операции , локализацию и многие другие, см. Ниже.
Я приведу некоторую информацию о поддержке Unicode в PHP с помощью слайдов Элизабет Смит на PHPBenelux'14
Хорошо:
Плохо:
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
Я обновлю этот ответ, если что-то изменит добавленные функции и так далее.
Недавно я обнаружил, что использование 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 в строке подключения) и изменить строковые функции для использования multibyte php строковые функции эквивалентны.
В PHP вам нужно либо использовать многобайтовые функции , либо включить mbstring.func_overload . Таким образом, такие вещи, как strlen, будут работать, если у вас есть символы, которые принимают более одного байта.
Вам также потребуется определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать PHP-код, который возвращает заголовок. (Или вы можете добавить метку META в свои HTML-документы.)
Хорошая цель – с самого начала – основываясь на характере вашего сайта, я нашел много ресурсов по этому поводу в Google, но вы, конечно, не первый в этом разбираетесь.
Предполагается, что мистический PHP6 должен все это выпрямиться, не так ли?
Вы можете в значительной степени настроить utf-8 как глобальную кодировку по умолчанию для mysql на уровне сервера, и она по умолчанию будет правильно соответствовать более гранулированным уровням.
Я только что прошел ту же проблему и нашел хорошее решение в руководствах 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()); }
Посмотреть источник
Поддержка Unicode в PHP по-прежнему огромна. Хотя он способен преобразовывать строку ISO8859 (которая используется внутри нее) в utf8, ей не хватает возможности работать с строками unicode изначально, что означает, что все функции обработки строк будут искажать и повреждать ваши строки. Поэтому вам нужно либо использовать отдельную библиотеку для правильной поддержки utf8, либо самостоятельно переписать все функции обработки строк.
Легкая часть – это просто указать кодировку в заголовках HTTP и в базе данных и т. Д., Но ничто из этого не имеет значения, если ваш PHP-код не выводит действительный UTF8. Это сложная часть, и PHP практически не помогает. (Я думаю, что PHP6 должен исправить худшее из этого, но это все еще далеко)
Верхний ответ превосходный. Вот что я должен был сделать на обычной настройке 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 решал набор символов, а не PHP как клиент (старое поведение, предпочтительнее, на мой взгляд), попробуйте добавить в свой файл my.cnf
на my.cnf
skip-character-set-client-handshake
, под [mysqld]
и перезапустить mysql
.
Это может вызвать проблемы, если вы используете что-то другое, кроме UTF8.