Хранение сериализованного объекта в базе данных MySql - PullRequest
9 голосов
/ 02 февраля 2012

У меня есть большой объект php, который я хочу сериализовать и сохранить в базе данных MySql. Кодировка таблицы - UTF-8, а столбец для хранения кодировки сериализованного объекта - также UTF-8.

Проблема в том, что объект содержит текстовую строку, содержащую французские символы.

Например:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

Когда я сериализирую объект, затем снова сериализую его непосредственно, строка сохраняется и находится в правильном формате.

Однако, когда я сохраняю сериализованный объект в базе данных MySql, затем извлекаю его снова, затем десериализую, строка становится такой:

Merci d'avoir passé commande avec Lovre. Voici le récapitulatif de votre commande 

Что-то идет не так, когда я сохраняю объект в базе данных.

Примечания:

  • Объект хранится с помощью propel ORM.
  • Тип столбца text.
  • Строка сохраняется и читается из файла html.

Ответы [ 4 ]

12 голосов
/ 02 февраля 2012

Строки, создаваемые serialize, являются двоичными строками, они не имеют определенной кодировки кодировки, а представляют собой просто «массив» байтов (где один байт равен 8 битам, октет).

Если вы сейчас возьмете такую ​​строку и скажете своей базе данных, что она закодирована в LATIN-1, и ваша база данных сохранит ее в текстовое поле с кодировкой UTF-8, база данных будет прозрачно менять кодировку с LATIN-1 на UTF. -8. UTF-8 - это кодировка кодировки, которая использует более одного байта на символ для некоторых символов, например, тех, которые вы задаете в своем вопросе, например é.

Символ é затем сохраняется как é внутри базы данных, которая является байтовой последовательностью UTF-8 для é.

Если вы теперь извлекаете данные из базы данных, не указывая, в какой кодировке они вам нужны, база данных вернет их как UTF-8.

Теперь unserialize имеет проблему, потому что двоичная строка была модифицирована таким образом, что делает ее недействительной.

Вместо этого вам нужно либо указать вашей базе данных, что она не должна изменять кодировку при хранении сериализованной строки, например, выбрав правильный тип столбца и кодировку (двоичное поле, BLOB - Большой двоичный объект & shy; Документы MySQL , см. также Двоичные типы & shy; Propel Docs ) или при извлечении данных из базы данных вы возвращаете кодировку кодировки обратно в исходный формат. Первый подход (двоичное поле) лучше, потому что это именно то, что вы ищете.

Для данных, которые уже были сохранены в базе данных в неправильном формате, вам необходимо исправить данные. Для этого сначала нужно выяснить, какое перекодирование было применено, например, из какой кодировки в какую кодировку. Я предполагаю, что это LATIN-1, но нет никакой гарантии. Вам необходимо проверить кодировку данных вашего текущего приложения и процессов, чтобы выяснить это.

После того, как вы узнали, закодируйте значения обратно из UTF-8 в исходную кодировку.

4 голосов
/ 02 февраля 2012

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

в вашем случае, я думаю, что вы забыли установить правильный набор символов для вашего соединения с базой данных (используя оператор SET NAMES или mysql_set_charset () ) - но это трудно сказать, не видя вашего код (и я не знаю, пропел).

ниже приводится цитата chazomaticus , который дал идеальный ответ в UTF-8 вплоть до , в котором перечислены все ваши точки позаботиться о:

Хранение:

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

индексирование:

  • В PHP, в любой оболочке БД вы использовать, вам нужно установить соединение кодировка к utf8. Таким образом, MySQL делает нет конвертации из родного UTF-8 когда он передает данные в PHP. * Обратите внимание, что если вы не используете БД обертка, вам, вероятно, придется выдать запрос, чтобы сказать MySQL, чтобы дать вам результаты в UTF-8: SET NAMES 'utf8' (как только вы подключитесь).

Доставка:

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

Представление:

  • Вы хотите, чтобы все данные отправлялись вам браузеры должны быть в UTF-8. К сожалению, единственный способ надежно сделать это добавить accept-charset атрибут для всех ваших <form> теги: <form ... accept-charset="UTF-8">.
  • Примечание что спецификация HTML W3C говорит, что клиенты «должны» по умолчанию отправлять формируется обратно на сервер в любом charset сервер обслуживал, но это видимо только рекомендация, отсюда необходимость явного каждый тег <form>.
  • Хотя на этом фронте вы все равно хотите проверить каждую отправленную строку как действительный UTF-8, прежде чем пытаться храните его или используйте где угодно. РНР mb_check_encoding() делает трюк, но вы должны использовать это религиозно.

Обработка:

  • Это, к сожалению, тяжелая часть. Вы должны убедиться, что каждый раз, когда вы обрабатываете строку UTF-8, вы делаете это безопасно. Самый простой способ сделать это путем широкого использования Расширение PHP mbstring.
  • РНР строковые операции НЕ по умолчанию UTF-8 сейф. Есть некоторые вещи, которые вы можно смело делать с обычной строкой PHP операции (например, объединение), но для большинства вещей вы должны использовать Эквивалентная mbstring функция.
  • Для знаю, что ты делаешь (читай: не путай это), вам действительно нужно знать UTF-8 и как это работает на самом низком возможный уровень. Проверьте любой из ссылки с utf8.com для хорошего ресурсы, чтобы узнать все, что вам нужно знать.
  • Кроме того, я чувствую себя так следует сказать где-то, даже если это может показаться очевидным: каждый PHP или HTML файл, который вы будете обслуживать, должен быть закодировано в действующем UTF-8.

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

2 голосов
/ 02 февраля 2012

Я всегда храню проверенные данные с помощью base64_encode(). Сериализованные данные иногда вызывают проблемы, но после использования их значения base64 остаются только простые символы.

1 голос
/ 21 августа 2015

Я настоятельно рекомендую вам использовать json_encode вместо сериализации. Однажды вы обнаружите, что пытаетесь использовать эти данные из другого места, не являющегося PHP, и хранение их в JSON делает их читаемыми везде; практически каждый язык поддерживает декодирование JSON и является общепризнанным стандартом.

Ответ об использовании utf8 повсюду : -D

...