序列化/反序列化PHP数组

时间:2011-04-24 00:30:01

标签: php mysql serialization

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

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

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

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

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


// Structure

keywordA - 0.234
         - 0.234
KeywordB - 0.23
         - 0.47



// Methods

    public function insertFilterForKeyword($id, array $filterProbs)
    {

        $sql = "INSERT INTO filter (keyword_id, filter_probs, sample_size_pos, sample_size_neg)
                VALUE (: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();

        return $result;
    }


    public function getFilterByKeyword($keyword)
    {
        $sql = 'SELECT f.id, f.keyword_id, f.filter_probs, f.sample_size_pos, f.sample_size_neg
                FROM filter f
                JOIN keyword 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);

        return $filter;
    }

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

谷歌搜索后,我尝试了以下方式的反序列化方法,其中没有一个工作:

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


    //to safely serialize 
    $safe_string_to_store = base64_encode(serialize($multidimensional_array)); 

    //to unserialize... 
    $array_restored_from_db = unserialize(base64_decode($encoded_serialized_string)); 

2)使用preg匹配来改变可能有困难的角色:

   
   unserialize(preg_replace('/;n;/', ';N;', strtolower($data['filter_probs'])));
   

非常感谢任何帮助!

感谢。

5 个答案:

答案 0 :(得分:1)

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

也许这就是问题?

(您应该能够存储没有urlencoding的序列化数据)

答案 1 :(得分:1)

我已经猜到db中的strin长度是个问题。如果在将序列化字符串拉出数据库后回显出序列化字符串会发生什么?它看起来像一个完成的字符串还是它打破了?我认为blob大约是65k个字符,您可以尝试将其更改为longblob然后重新保存数据吗?

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

答案 2 :(得分:1)

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

来自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)提取)。

答案 3 :(得分:0)

检查字段filter的数据库方案定义。如果filter_probs足够长,可以保存序列化字符串。

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

答案 4 :(得分:0)

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