【问题标题】:Storing a serialized object in MySql database在 MySql 数据库中存储序列化对象
【发布时间】:2012-02-02 08:21:34
【问题描述】:

我有一个大的 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 文件中读取。

【问题讨论】:

  • 你文件的编码是什么?
  • 您可以尝试对其进行 base_64 编码,但您不必这样做。数据库列是什么类型?你检查过php中的数据库连接设置吗?
  • @TheSilencer 数据库列类型是文本。数据库连接是使用 PROPEL 完成的。
  • @alexn 字符串存储在 html 文件中。

标签: php mysql encoding propel object-serialization


【解决方案1】:

serialize 创建的字符串是二进制字符串,它们没有特定的字符集编码,只是一个字节“数组”(其中一个字节是 8 位,一个八位字节)。

如果您现在获取这样一个字符串并告诉您的数据库它是 LATIN-1 编码的,并且您的数据库将其存储到使用 UTF-8 编码的文本字段中,那么数据库将透明地将编码从 LATIN-1 更改为 UTF -8。 UTF-8 是一种字符集编码,对于某些字符,每个字符使用一个以上字节,例如您在问题中给出的那些字符,例如 é。

字符é 然后在数据库中存储为é,这是é 的UTF-8 字节序列。

如果您现在从数据库中获取数据而没有指定您需要的编码,那么数据库会将其返回为 UTF-8。

现在unserialize 有一个问题,因为二进制字符串已被修改为使其无效。

相反,您需要告诉您的数据库在存储序列化字符串时不应修改编码,例如通过选择正确的列类型和编码(二进制字段,BLOB - Binary Large Object­MySQL Docs,另见Binary Types­Propel Docs) - 或者 - 当您从数据库中获取数据时,您将字符集编码恢复为原始格式。第一种方法(二进制字段)更好,因为它正是您要寻找的。​​p>

对于已经以错误格式存入数据库的数据,需要更正数据。为此,您首先需要找出应用了哪种重新编码,例如从哪个字符集到哪个字符集。我认为它是 LATIN-1,但不能保证。您需要查看当前应用程序数据和流程的编码以找出答案。

找到后,将值从 UTF-8 编码回原始编码。

【讨论】:

  • 我试了你说的,将列类型转换为BLOB,但问题依旧。但是,在从数据库中检索对象后,我决定utf_decode 消息本身并解决了问题。
  • 它对现有数据和/或新数据是否持续存在?我也不是推进专家,但我很确定数据库层必须有一个直截了当的解决方案,因此您无需关心应用程序逻辑代码中的编码。如果你不能在数据库层解决它,PHP 中还有Serializable 接口可能有助于保持你的代码干净。
  • 我没有现有数据,因为我本身仍处于开发阶段。我检查了 PROPEL 配置,它在连接中使用 UTF-8。也许我错过了一些东西,但我会研究你提到的 Serializable 接口。感谢您的帮助。
【解决方案2】:

确保在任何地方都使用 utf-8 - 听起来你错过了什么。

在您的情况下,我认为您忘记为您的数据库连接设置正确的字符集(使用 SET NAMES 语句或 mysql_set_charset()) - 但如果没有看到您的代码就很难说(我不知道)不知道推进)。

以下是chazomaticus的引用,他在UTF-8 all the way through中给出了完美的答案,列出了你需要注意的所有点:

存储:

  • 指定utf8_unicode_ci(或 等效)所有表的排序规则 和数据库中的文本列。 这使得 MySQL 物理存储和 以 UTF-8 本地检索值。

检索:

  • 在 PHP 中,在任何 DB 包装器中 使用,你需要设置连接 字符集为 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 属于你所有的 &lt;form&gt; 标签:<form ... accept-charset="UTF-8">.
  • 注意 W3C HTML 规范说 客户“应该”默认发送 以任何形式返回服务器 字符集服务器服务,但这是 显然只是一个建议, 因此需要明确 每个&lt;form&gt; 标签。
  • 尽管在这方面,你仍然会 想要验证每个提交的字符串 在您尝试之前作为有效的 UTF-8 存放或在任何地方使用。 PHP的 mb_check_encoding() 成功了, 但你必须虔诚地使用它。

处理:

  • 不幸的是,这很难 部分。你需要确保 每次处理 UTF-8 字符串时, 你这样做是安全的。最简单的方法 这是通过广泛使用 PHP 的 mbstring 扩展。
  • PHP 的 默认情况下不是字符串操作 UTF-8 安全。有些事情你 可以安全地使用普通的 PHP 字符串 操作(如连接),但是 对于大多数事情,您应该使用 等效mbstring 函数。
  • 到 知道你在做什么(阅读:不乱 起来),你真的需要知道 UTF-8 以及它如何在最低处工作 可能的水平。查看任何 来自utf8.com 的链接 资源来学习你需要的一切 知道。
  • 还有,我也有这种感觉 应该在某处说,即使 这似乎很明显:每个 PHP 或 HTML 您将要提供的文件应该是 以有效的 UTF-8 编码。

请注意,您不需要使用 utf-8 - 重要的是在任何地方都使用相同的字符集,而与可能的字符集无关。但是,如果您无论如何都需要更改内容,请使用 utf-8。

【讨论】:

    【解决方案3】:

    我总是通过使用 base64_encode() 来存储 esrialized 数据。 序列化数据有时会导致问题,但使用它的 base64 值后,只剩下简单的字符。

    【讨论】:

      【解决方案4】:

      我强烈建议您使用json_encode 而不是序列化。总有一天,您会发现自己尝试使用来自 PHP 以外的其他地方的数据,并将其存储在 JSON 中使其在任何地方都可读;几乎所有语言都支持解码 JSON,并且是一个成熟的标准。

      关于在任何地方使用 utf8 的答案都成立! :-D

      【讨论】:

      • 不是一个好主意:1。它将数组转换为对象,2. 类类型和方法丢失
      • 无论如何方法都会丢失....你不会用serialize调用保存它们相信我,存储序列化的东西是一个更糟糕的主意..你最终需要阅读那些东西从别的地方。如果您需要反序列化回一个类,只需将类型存储为字符串,然后切换以使用 json 数据作为字段实例化正确的类,而不是返回纯 json,就像任何 ORM 基本上对 DB 记录所做的那样。
      • JSON 在某些情况下可能确实更好。但是,这里的问题是如何序列化 PHP 对象,所以 1. 无论如何你都可以坚持使用 PHP 2. 你不能将 PHP 对象转换为 JSON,因为那样你就不能 unserialize/json_decode 它所以你仍然可以重新创建原始 PHP 对象。
      猜你喜欢
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 2019-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      相关资源
      最近更新 更多