【问题标题】:Serializing / Unserializing a PHP Array序列化/反序列化 PHP 数组
【发布时间】:2011-08-11 16:35:45
【问题描述】:

我在尝试反序列化 PHP 中的数组时遇到了一些问题。

我在一个类中有两种方法,一种用于在 mysql 表中存储序列化数组,另一种用于检索它。

执行第二种方法时(检索/反序列化时)出现以下错误:

注意:unserialize():第 39 行 /Users/benwaine/NetBeansProjects/SentimentEngineMk2/lib/TSE/Mapper/Filter.php 中 50647 字节的偏移 50623 处出错

字符串存储在 MySQL 的 blob 字段中。该数组是多维的,由带有浮点数组的标记组成。问题是间歇性的,可能表明问题出在令牌上?

// 结构 关键字A - 0.234 - 0.234 关键字B - 0.23 - 0.47 // 方法 公共函数 insertFilterForKeyword($id, 数组 $filterProbs) { $sql = "插入过滤器 (keyword_id, filter_probs, sample_size_pos, sample_size_neg) 值(:id,:filterProbs,:pos,:neg)“; $stmt = $this->pdo->prepare($sql); $meta = array_shift($filterProbs); $stmt->bindParam(':id', $id); $stmt->bindParam(':filterProbs',serialize($filterProbs)); $stmt->bindParam(':pos', $meta['sample_size_pos']); $stmt->bindParam(':neg', $meta['sample_size_neg']); $result = $stmt->execute(); 返回$结果; } 公共函数 getFilterByKeyword($keyword) { $sql = 'SELECT f.id, f.keyword_id, f.filter_probs, f.sample_size_pos, f.sample_size_neg FROM 过滤器 f 加入关键字 k ON k.id = f.keyword_id WHERE k.keyword = :keyword'; $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':keyword', $keyword); $result = $stmt->execute(); $data = $stmt->fetch(PDO::FETCH_ASSOC); $probArray = unserialize($data['filter_probs']); $filter = new TSE_Filter($probArray); 返回$过滤器; }

我猜这个错误与数据中导致反序列化问题的字符有关。

在谷歌搜索后,我尝试了以下方法的反序列化行,但都没有奏效:

1) base64_encode / 解码序列化字符串。

//安全序列化 $safe_string_to_store = base64_encode(序列化($multidimensional_array)); //反序列化... $array_restored_from_db = unserialize(base64_decode($encoded_serialized_string));

2) 使用预匹配来改变潜在的困难字符:

反序列化(preg_replace('/;n;/', ';N;', strtolower($data['filter_probs'])));

任何帮助将不胜感激!

谢谢。

【问题讨论】:

  • 您能否发布一个示例,说明当您从数据库中查询而不尝试反序列化时序列化数据的样子?

标签: php mysql serialization


【解决方案1】:

我猜想数据库中字符串的长度是问题所在。如果在将序列化字符串从数据库中取出后回显它,会发生什么情况?它看起来像一根完成的弦还是断了?我认为 blob 大约有 65k 个字符,您可以尝试将其更改为 longblob 然后重新保存数据?

另外,如果您知道有一个不起作用,请跳过数据库保存并尝试立即反序列化字符串。那么至少你知道问题是反序列化还是你的数据库中的数据?

【讨论】:

  • 谢谢道格拉斯。你哪里对。更改为长 blob 后,反序列化效果很好。我最终在数据库保存之前和之后将字符串写入文件,然后我对它们进行了比较,很容易看到你提到的截断。干杯!
【解决方案2】:

在您的示例代码中,您在序列化字符串上使用了urlencode。反序列化时没有解码urlencoding,这会导致反序列化失败。

也许这就是问题所在?

(你应该可以不使用urlencoding存储序列化数据)

【讨论】:

  • 感谢您回复 Jani。我在发布之前尝试的解决方案之一意外地将其留在了其中。我已经对其进行了编辑并将其从问题中删除。
【解决方案3】:

我的猜测是它与列、连接或客户端字符集有关。

来自http://dev.mysql.com/doc/refman/5.1/en/charset-conversion.html

如果列具有二进制数据类型(BINARY、VARBINARY、BLOB),则它包含的所有值都必须使用单个字符集(要将列转换为的字符集)进行编码。如果使用二进制列存储多个字符集的信息,MySQL 无法知道哪些值使用哪个字符集,无法正确转换数据。

所以我会先尝试将列显式设置为 CHARACTER SET BINARY。请记住,如果您序列化对象,序列化的字符串包含空字节和其他奇怪的东西(我知道您没有这样做,但谁知道您的数组包含什么作为键和值)。

此外,在准备序列化参数时,您没有将其标记为 blob,因此 PDO 可能也在应用一些字符转换。对于插入,请尝试使用:

$stmt->bindParam(':filterProbs', serialize($filterProbs), PDO::PARAM_LOB);

在获取时也可能使用相同的方法,只是使用PDOStatement::bindColumn()(然后记住使用PDOStatement::fetch(PDO::FETCH_BOUND) 获取)。

【讨论】:

    【解决方案4】:

    检查字段filter.filter_probs 的数据库方案定义是否足够长以保存序列化字符串。

    您还可以在序列化之前和反序列化之后验证包含相同值的数组。

    【讨论】:

    • 嗨,安迪,我检查了它的定义,它是“blob”,没有长度值。够了吗?
    【解决方案5】:

    getmequick http://php.net/manual/en/function.unserialize.php 的评论有帮助吗?搜索“偏移错误”...

    【讨论】:

      猜你喜欢
      • 2014-07-14
      • 1970-01-01
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      相关资源
      最近更新 更多