UTF-8 полностью через

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

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

Это для нового Linux-сервера, работающего под MySQL 5, PHP 5 и Apache 2.

989
задан mercutio 11 нояб. '08 в 0:04
источник поделиться

16 ответов

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

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

  • В более старых версиях MySQL (< 5.5.3) вам, к сожалению, придется просто использовать utf8, который поддерживает только подмножество символов Unicode. Хотелось бы, чтобы я шутил.

Доступ к данным:

  • В вашем коде приложения (например, PHP) в любом используемом вами методе доступа к БД вам нужно установить кодировку соединений utf8mb4. Таким образом, MySQL не выполняет преобразование из собственного UTF-8, когда он передает данные в ваше приложение и наоборот.

  • Некоторые драйверы предоставляют свой собственный механизм для настройки набора символов соединения, который обновляет собственное внутреннее состояние и сообщает MySQL о кодировке, которая будет использоваться в соединении. Это обычно предпочтительный подход. В PHP:

    • Если вы используете PDO уровень абстракции с помощью PHP & ge; 5.3.6 вы можете указать charset в mysqli, вы можете вызвать set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Если вы застряли с обычным mysql, но, похоже, работает PHP & ge; 5.2.3 вы можете вызвать mysql_set_charset.

  • Если драйвер не предоставляет свой собственный механизм для установки набора символов соединения, вам может потребоваться выдать запрос, чтобы сообщить MySQL, как ваше приложение ожидает, что данные в соединении будут закодированы: SET NAMES 'utf8mb4'.

  • То же самое относится к utf8mb4/utf8, как указано выше.

Выход

  • Если ваше приложение передает текст другим системам, они также должны быть проинформированы о кодировке символов. В веб-приложениях браузер должен быть проинформирован о кодировке, в которой данные отправляются (через заголовки ответа HTTP или метаданные HTML).

  • В PHP вы можете использовать параметр default_charset php.ini или вручную выпустить заголовок MIME Content-Type самостоятельно, который просто больше работает, но имеет тот же эффект.

Ввод

  • К сожалению, вы должны проверить каждую полученную строку как действительную 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, вы делаете это безопасно. Это, к сожалению, тяжелая часть. Вероятно, вы захотите широко использовать расширение PHP mbstring.

  • Встроенные строковые операции PHP по умолчанию не являются безопасными для UTF-8.Есть некоторые вещи, которые можно смело выполнять с обычными строковыми операциями PHP (например, конкатенация), но для большинства вещей вы должны использовать эквивалентную функцию mbstring.

  • Чтобы узнать, что вы делаете (читайте: не испортите его), вам действительно нужно знать UTF-8 и как он работает на самом низком возможном уровне. Просмотрите любые ссылки из utf8.com для получения некоторых хороших ресурсов, чтобы узнать все, что вам нужно знать.

864
ответ дан chazomaticus 11 нояб. '08 в 0:43
источник поделиться

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

Не забудьте также тег META (например, или версию HTML4 или XHTML):

<meta charset="utf-8">

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

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

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

Edit:

У W3C фактически есть довольно большой раздел посвященный I18N. У них есть ряд статей, связанных с этой проблемой – описывая HTTP, (X) HTML и CSS сторону вещей:

Они рекомендуют использовать как HTTP-заголовок, так и метатег HTML (или объявление XML в случае использования XHTML как XML).

135
ответ дан mercator 12 нояб. '08 в 22:27
источник поделиться

В дополнение к настройке 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 за кулисами, во всяком случае, для повышения производительности.

55
ответ дан Christopher Nadeau 11 нояб. '08 в 0:30
источник поделиться

Старая тема, я знаю. Обнаружена проблема с кем-то, использующим 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.

26
ответ дан Brad F Jacobs 11 сент. '12 в 18:40
источник поделиться

В моем случае я использовал mb_split, который использует регулярное выражение. Поэтому мне также пришлось вручную убедиться, что кодировка регулярного выражения была utf-8, выполнив mb_regex_encoding('UTF-8');

В качестве дополнительной заметки я также обнаружил, запустив mb_internal_encoding(), что внутренняя кодировка не была utf-8, и я изменил ее, запустив mb_internal_encoding("UTF-8");.

20
ответ дан JDelage 24 февр. '12 в 1:20
источник поделиться

Прежде всего, если вы находитесь в < 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.

Я обновлю этот ответ, если что-то изменит добавленные функции и так далее.

19
ответ дан Jimmy Kane 27 янв. '14 в 12:16
источник поделиться

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

Решение заключалось в использовании

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

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

13
ответ дан Notflip 13 янв. '14 в 12:37
источник поделиться

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

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

11
ответ дан Puerto AGP 10 сент. '14 в 6:39
источник поделиться

Я только что прошел ту же проблему и нашел хорошее решение в руководствах 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());
}

Просмотр источника

8
ответ дан Abdul Sadik Yalcin 06 мая '15 в 0:36
источник поделиться

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

Вам также потребуется определить набор символов ваших ответов. Вы можете использовать AddDefaultCharset, как указано выше, или написать PHP-код, который возвращает заголовок. (Или вы можете добавить метку META в свои HTML-документы.)

8
ответ дан JW. 11 нояб. '08 в 0:29
источник поделиться

Хорошая цель - с самого начала - основываясь на характере вашего сайта, я нашел много ресурсов по этому поводу в Googling - вы, конечно, не первый в этом разбираетесь.

Предполагается, что мистический PHP6 должен все это выпрямиться, верно?

Вы можете в значительной степени настроить utf-8 как глобальную кодировку по умолчанию для mysql на уровне сервера, и она по умолчанию будет правильно соответствовать более гранулированным уровням.

7
ответ дан dkretz 11 нояб. '08 в 0:41
источник поделиться

Поддержка Unicode в PHP по-прежнему огромна. Хотя он способен преобразовывать строку ISO8859 (которая используется внутри нее) в utf8, ей не хватает возможности работать с строками unicode изначально, что означает, что все функции обработки строк будут калечить и испортить ваши строки. Поэтому вам нужно либо использовать отдельную библиотеку для правильной поддержки utf8, либо самостоятельно переписать все функции обработки строк.

Легкая часть - это просто указание кодировки в заголовках HTTP и в базе данных и т.д., но ничто из этого не имеет значения, если ваш PHP-код не выводит допустимый UTF8. Это сложная часть, и PHP дает вам практически никакой помощи. (Я думаю, что PHP6 должен исправить худшее из этого, но это все еще вдалеке)

6
ответ дан jalf 11 нояб. '08 в 0:48
источник поделиться

Если вы хотите, чтобы сервер MySQL решал набор символов, а не PHP как клиент (старое поведение, предпочтительнее, на мой взгляд), попробуйте добавить skip-character-set-client-handshake к my.cnf под [mysqld] и перезапустить mysql.

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

5
ответ дан Nikola Tulimirovic 12 февр. '15 в 2:52
источник поделиться

Верхний ответ отличный. Вот что я должен был сделать на обычной настройке 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

Это все!

5
ответ дан commonpike 14 янв. '11 в 19:13
источник поделиться
<meta charset="utf-8">

Content-Type: text/html; кодировка = UTF-8

нажмите здесь описание ссылки

-1
ответ дан Jayanit Satani 03 дек. '17 в 6:33
поделиться

Размещено как сообщество wiki:

Для пользователей WordPress:

Sidenote: вопрос был отменен. Сообщение было взято из:

Частичное сообщение:

У меня есть сайт wordpress, который я установил на своем локальном хосте. Я только что загрузил его на мой хостинг и импортировал базу данных, но все они отображаются как.


Решение из OP:

Для всех, у кого есть эта проблема, ниже это исправлено для меня. Он не был связан с базой данных.

Требуется обновление wp-config.php. Я изменил define('DB_CHARSET', 'utf8mb4'); на define('DB_CHARSET', 'utf8');

-4
ответ дан Fred -ii- 03 дек. '17 в 6:33
поделиться

Другие вопросы по меткам