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

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

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

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

13 ответов


Хранилище Данных:

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

  • в более старых версиях MySQL (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
      
    • если вы застряли с plain в 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 spec, следующие под-пули больше не нужны или даже не действительны для современного HTML. Я понимаю, что браузеры будут работать и отправлять данные в наборе символов, указанном для документ. Однако, если вы ориентируетесь на более старые версии HTML (XHTML, HTML4 и т. д.), эти пункты все еще могут быть полезны:

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

Другие Соображения, Код:

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

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


Я хотел бы добавить одну вещь к chazomaticus' отличный ответ:

Не забывайте метатег либо (например, или версия HTML4 или XHTML):

<meta charset="utf-8">

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

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

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

Edit:

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");.


прежде всего, если вы находитесь в

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

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

INTL

хорошо:

  • обертка вокруг библиотеки ICU
  • стандартизированные локали, установить языковой стандарт на скрипт
  • форматирование
  • валюты
  • форматирование сообщений (заменяет 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, Если вы не используете расширение 3-й части.
  • отправить все в ASCII, если вы используете exec, proc_open и другие вызовы командной строки
  • обычный текст не является обычным текстом, файлы имеют кодировки
  • вы можете конвертировать файлы на лету с помощью фильтра с iconv

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


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

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

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

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


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

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


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

Вам также необходимо определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать PHP-код, который возвращает заголовок. (Или вы можете добавить метатег в свои 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());
}

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


поддержка 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 server решал набор символов, а не PHP в качестве клиента (старое поведение; предпочтительно, на мой взгляд), попробуйте добавить skip-character-set-client-handshake на my.cnf, под [mysqld] и перезапустите mysql.

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