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_* (без какого-либо явного набора символов).

  • В более старых версиях 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 и т. Д.), Эти пункты могут по-прежнему быть полезными:

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

  • 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 , который использует 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

INTL

Хорошо:

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

Плохо:

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

mb_string

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

Iconv

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

БАЗ

  • mysql: Charset и сортировка по таблицам и по соединению (а не сортировка). Также не используйте 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 в строке подключения) и изменить строковые функции для использования 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.