开发者

Serializing / Unserializing a PHP Array

I'm having some problems when trying to unserialize an array in PHP.

I have two methods in a class, one to handle storing a serialized array in a mysql table and one to retrieve it.

I get the following error when executing the second method (when retrieving / unserializing):

Notice: unserialize(): Error at offset 50623 of 50647 bytes in /Users/benwaine/NetBeansProjects/SentimentEngineMk2/lib/TSE/Mapper/Filter.php on line 39

The string is stored ina blob field in MySQL. The array is multi-dimentional and composed of a token with an array of floats. The problem is intermittent perhaps suggesting the issue is with the tokens?


// Structure

keywor开发者_JAVA技巧dA - 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;
    }

I'm guessing the error has to do with characters in the data that are causing deserialization issues.

After googling I tried methods the deserialization line in the following ways, none of which worked:

1) base64_encode / decode the serialized string.


    //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) Use a preg match to alter potentially difficult characters:

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

Any help would be much appreciated!

Thanks.


I'd've guessed length of the strin in the db being the issue. What happens if you echo out the serialised string once you've pulled it out of the database? Does it look like a finished string or does it break? I think blob is around 65k characters, you could try changing it to a longblob and then resave the data?

Also, if you have one that you know doesn't work, skip the database save and try to unserialise the string straight away. Then atleast you know if the issue is with unserialising, or the data in your db?


In your sample code, you're using urlencode on the serialized string. You're not decoding the urlencoding when you unserialize, which would cause the unserialization to fail.

Perhaps that's the problem?

(You should be able to store the serialized data without urlencoding)


My guess is that it has something to do with column, connection or client charsets.

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

If the column has a binary data type (BINARY, VARBINARY, BLOB), all the values that it contains must be encoded using a single character set (the character set you're converting the column to). If you use a binary column to store information in multiple character sets, MySQL has no way to know which values use which character set and cannot convert the data properly.

So I'd try setting the column to CHARACTER SET BINARY explicitly first. Remember that serialized strings contain null bytes and other weird stuff if you serialize objects (I realize you aren't doing that, but who knows what your array contains as keys and values).

Also, you're not flagging the serialized argument as a blob when preparing it, so PDO is probably applying some character conversion as well. For the insert, try using this:

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

And maybe use the same approach when fetching as well, just with PDOStatement::bindColumn() (and remember fetching with PDOStatement::fetch(PDO::FETCH_BOUND) then).


Check database scheme definition for field filter.filter_probs if it is long enough to save serialized string.

Also you can validate the array before serialize and after unserialize containing same value.


Does the comment by getmequick http://php.net/manual/en/function.unserialize.php help? Search for 'error at offset'...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜