Не удалось сохранить японские символы в Maria DB [дубликат]

Оператор == всегда предназначен для сравнения ссылок на объекты, тогда как метод сравнения строк .equals () переопределяется для сравнения содержимого:

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
1029
задан Machavity 9 January 2018 в 16:49
поделиться

14 ответов

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

Не забудьте также тег META (например, или HTML4 или XHTML-версия этого файла ):

<meta charset="utf-8">

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

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

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

Правка:

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

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

867
ответ дан Community 15 August 2018 в 17:33
поделиться
  • 1
    Я понимаю, что если вы укажете сортировку как utf8_ *, она также автоматически кодируется как utf8. Это неправильно? – chazomaticus 10 November 2008 в 22:49
  • 2
    Я не ошибаюсь: COLLATE означает CHARACTER SET. См. dev.mysql.com/doc/refman/5.0/en/charset-database.html . – chazomaticus 11 November 2008 в 00:01
  • 3
    Нельзя ли также указать кодировку в заголовках HTTP? Вероятно, вам нужен вариант конфигурации для веб-сервера ... – oliver 20 November 2008 в 18:47
  • 4
    @oliver: Да, вы можете отправить его в HTTP-заголовке, но лучше отправить его в контент, потому что, если клиент сохраняет файл, он всегда сохраняет метатег. HTTP-заголовок, скорее всего, просто исчезнет, ​​если браузер не станет достаточно умным, чтобы скопировать его в метатег в сохраненном файле. – user 2 December 2008 в 02:49
  • 5
    Кроме того, убедитесь, что строка является первым дочерним элементом элемента head (перед любым материалом Unicode). Браузер может переинтерпретировать страницу после попадания этого мета-элемента, описанного выше. – alex 20 April 2010 в 09:55
  • 6
    Подумайте о добавлении примеров PDO для установки набора символов. – Ja͢ck 22 October 2012 в 04:35
  • 7
    Обратите внимание: MySQL не говорит на том же языке, что и все остальные. Когда MySQL говорит «utf8», это действительно означает «какой-то странно отсталый вариант UTF-8, который ограничен тремя байтами, потому что бог знает, какая нелепая причина». Если вы действительно хотите UTF-8, вы должны сказать MySQL, что хотите эту странную вещь, которую MySQL любит называть utf8mb4 . Не беспокойтесь об экономии на «WTF!». – R. Martinho Fernandes 9 April 2013 в 10:21
  • 8
    Этот ответ мне очень помог, но я также обнаружил, что в моем случае мне нужно было добавить JSON_UNESCAPED_UNICODE в свой PHP json_encode при передаче результатов запроса базы данных обратно через ajax. – Petay87 14 December 2017 в 10:49
  • 9
  • 10

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

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

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

  • В вашем коде приложения (например, PHP) в любом используемом вами способе доступа к базе данных вы будете необходимо установить кодировку соединения на utf8mb4. Таким образом, MySQL не выполняет преобразование из собственного UTF-8, когда он передает данные в ваше приложение и наоборот.
  • Некоторые драйверы предоставляют свой собственный механизм для настройки набора символов соединения, который как обновляет свои собственные внутреннее состояние и информирует MySQL о кодировании, которое будет использоваться в соединении - это, как правило, предпочтительный подход. В PHP: если вы используете уровень абстракции PDO с помощью PHP & ge; 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 & ge; 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 только : обратите внимание, что спецификация HTML W3C говорит, что клиенты «должны» по умолчанию отправлять формы обратно на сервер в любой кодировке, обслуживаемой сервером, но это, по-видимому, только рекомендация, следовательно, необходимо явно указывать на каждый тэг <form>.

Другие кодовые соображения:

  • Очевидно, что все файлы, которые вы будете обслуживать (PHP, HTML, JavaScript и т. д.), должны быть закодированы в действительном UTF-8.
  • Вы должны убедиться, что каждый раз, когда вы обрабатываете строку UTF-8, вы делаете это безопасно. Это, к сожалению, тяжелая часть. Вероятно, вы захотите широко использовать расширение PHP mbstring .
  • Встроенные строковые операции PHP - это not по умолчанию UTF-8 безопасно. Есть некоторые вещи, которые можно смело выполнять с обычными строковыми операциями PHP (например, конкатенация), но для большинства вещей вы должны использовать эквивалентную функцию mbstring.
  • Чтобы узнать, что вы делаете (читайте: not испортите это), вам действительно нужно знать UTF-8 и как он работает на минимально возможном уровне. Проверьте какие-либо ссылки из utf8.com на некоторые полезные ресурсы, чтобы узнать все, что вам нужно знать.
867
ответ дан Community 15 August 2018 в 17:33
поделиться
  • 1
    Я понимаю, что если вы укажете сортировку как utf8_ *, она также автоматически кодируется как utf8. Это неправильно? – chazomaticus 10 November 2008 в 22:49
  • 2
    Я не ошибаюсь: COLLATE означает CHARACTER SET. См. dev.mysql.com/doc/refman/5.0/en/charset-database.html . – chazomaticus 11 November 2008 в 00:01
  • 3
    Подумайте о добавлении примеров PDO для установки набора символов. – Ja͢ck 22 October 2012 в 04:35
  • 4
    Обратите внимание: MySQL не говорит на том же языке, что и все остальные. Когда MySQL говорит «utf8», это действительно означает «какой-то странно отсталый вариант UTF-8, который ограничен тремя байтами, потому что бог знает, какая нелепая причина». Если вы действительно хотите UTF-8, вы должны сказать MySQL, что хотите эту странную вещь, которую MySQL любит называть utf8mb4 . Не беспокойтесь об экономии на «WTF!». – R. Martinho Fernandes 9 April 2013 в 10:21
  • 5
    Этот ответ мне очень помог, но я также обнаружил, что в моем случае мне нужно было добавить JSON_UNESCAPED_UNICODE в свой PHP json_encode при передаче результатов запроса базы данных обратно через ajax. – Petay87 14 December 2017 в 10:49

В дополнение к настройке 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 15 August 2018 в 17:33
поделиться
  • 1
    Задайте настройку перегрузки в php.ini. Это помогает при использовании многобайтовых строк. – Anthony Rutledge 21 December 2015 в 21:52

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

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

6
ответ дан Chuck Burgess 15 August 2018 в 17:33
поделиться

Главный ответ отличный. Вот что я должен был на обычной установке 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 15 August 2018 в 17:33
поделиться

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

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

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

7
ответ дан dkretz 15 August 2018 в 17:33
поделиться

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

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

11
ответ дан Funk Forty Niner 15 August 2018 в 17:33
поделиться
  • 1
    Я потратил час, пытаясь выяснить проблему кодирования на странице, над которой я работаю, и я обычно хорошо разбираюсь в вещах. Я всегда проконсультирую эту страницу, и ваш ответ мне очень помог. Получил мой взнос. В моем случае set_charset('utf8mb4') не работал, но >set_charset("utf8") сделал, и это не было показано в других ответах. – Funk Forty Niner 21 January 2017 в 15:16
  • 2
    @FunkFortyNiner Остерегайтесь: set_charset("utf8") может работать, но будет вести себя по-другому (см. Примечания о различии между utf8 и utf8mb4 и историей версий mysql). Используйте utf8 , если вам нужно И ТОЛЬКО , если вы знаете, что делаете ! – Martin Hennings 24 April 2018 в 10:09

Старая тема, я знаю. Нашел проблему с кем-то, использующим 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
ответ дан iankit 15 August 2018 в 17:33
поделиться
  • 1
    Ищете это немного дальше, это необходимо только для версий PHP до 5.3.6. См. Также: http://stackoverflow.com/a/4361485/2286722 (хотя они используют отдельный $dbh->exec("set names utf8");, я предпочитаю представленный здесь метод). Btw. есть также аналогичная заметка в этом комментарии в руководстве PHP: php.net/manual/en/pdo.construct.php#96325 . – Marten Koetsier 13 August 2015 в 13:55

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

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

20
ответ дан JDelage 15 August 2018 в 17:33
поделиться

Прежде всего, если вы находитесь в & lt; 5.3PHP, то нет. У тебя много проблем, чтобы справиться.

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

Я приведу некоторую информацию о поддержке Unicode в PHP с помощью слайдов Elizabeth Smith в PHPBenelux'14

INTL

Хорошо:

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

Плохо :

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

mb_string

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

ICONV

  • Первичный для преобразования кодировки
  • Обработчик выходных буферов
  • Функциональность кодирования mime
  • conversion
  • некоторые строковые помощники (len, substr, strpos, strppos)
  • Фильтр потока 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 15 August 2018 в 17:33
поделиться
  • 1
    Да, верно. Mysqli и PDO могут использовать свои собственные драйверы. Также они могут использовать драйвер mysqlnd, если вы скомпилируете php с параметрами --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd. – Alexander Yancharuk 16 February 2014 в 19:54

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

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

8
ответ дан JW. 15 August 2018 в 17:33
поделиться
  • 1
    Большой совет по настройке func_overload - позволяет минимально модифицировать существующий код. – Simon East 15 January 2014 в 06:56
  • 2
    Просто будьте осторожны - какой-то код действительно может полагаться на однобайтовый характер стандартных строковых функций. – JW. 15 January 2014 в 20:18
  • 3
    Важно отметить, что функция mbstring.func_overload устарела с PHP 7.2 из-за проблем, отмеченных в комментарии @ JW выше. Поэтому лучший совет: да, вы должны определенно использовать функции mbstring, но не используйте функцию перегрузки, чтобы стандартные функции работали как многобайтовые. – Simba 7 February 2017 в 14:08

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

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

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

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

13
ответ дан Martin 15 August 2018 в 17:33
поделиться

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

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

5
ответ дан Nikola Tulimirovic 15 August 2018 в 17:33
поделиться

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

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

11
ответ дан Funk Forty Niner 15 August 2018 в 17:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: