views:

543

answers:

6

I have some serverside PHP code that attempts persist a data object (essentially an multi-dimensional array) to a backend database. This data object originally comes in as AMF actionscript object sent from a flex application. I want persist the object in whole for later use so I have used the php serialize function and encode the object down a simple string that can go into a database field. The code looks like this:

$serializedDataObject = base64_encode(serialize($objectInstance->myDataObject));

When I want to revivify this object and bring it back I simply run the reverse

$unserializedDatanObject = unserialize(base64_decode($serializedDataObject));

So far this seems to work well. But sometimes my php script fails. I think it is failing at the serialization step. My question is theoretically speaking what could cause a php serialization and encoding process to fail? Are there certain characters or kinds of data in the data object array that could cause the serialization to bork?

Do I need to do some massaging of the data object before I try to serialize it?

Edit:

To clarify the process works like this

I have a Flex/Actionscript client app that sends AMF based actionscript objects to the server. On the PHP side I am using the Zend AMF library to read the AMF data. The object can be inspected in PHP and basically looks like an associative multi-dimensional array. It is at this point that I attempt to serialize and base 64 encode the object so that I can persist the object to the database as a encoded string.

Hopefully this makes sense. The problem is intermittent and not so easy to reproduce consistently. If I can get some specific error messages I will post them here for further clarification. But for now I was just wondering what are the limits of serialization to help me further debug.

+2  A: 

You can't properly serialize resources, such as file handles or database connections. You also can't serialize built-in PHP objects, though I'm not exactly sure what that covers.

Greg
He's calling the serialize() on the objects before base64 encoding them. I'm pretty sure you can do that. If I remember right I think I have some production code that's doing that and handling it properly. But not then base64 encoding it. http://us.php.net/serialize
Thomas Schultz
You can serialize almost anything, including built in PHP objects (they're still objects, just provided by the core). However, you are correct, you CANNOT serialize resources. Since the OP refers to data objects not serializing, I have a feeling said objects contain connection resources to the DB.
dcousineau
I do remember not being able to serialize a RecursiveIteratorIterator but that seems to be fixed now - in my simple test anyway
Greg
As for "built-in objects" is specifically states in the manual they can't be serialized but doesn't give an example of what it means by a built-in object
Greg
+3  A: 

On php.net/bas64_decode there is some mention of large strings not decoding well. Also, if you have unsupported character formats in the object it may cause problems.

  1. Make sure that you don't have any unsupported character formats in your objects
  2. Try and log how big the objects are that are being serialized
Thomas Schultz
+1  A: 

Gotta go with Tom on this one; to quote php.net/serialize:

The value to be serialized. serialize() handles all types, except the resource-type. You can even serialize() arrays that contain references to itself. Circular references inside the array/object you are serializing will also be stored. Any other reference will be lost.

As far as standard objects are concerned you shouldn't have a problem. Log the data you're getting after base64_encoding/decoding, then use the following line to check your data.

echo '<pre>'; print_r($decodedObject); echo '</pre>';
Akoi Meexx
+1  A: 

Are you storing the serialized data inside a database? If so, is the field large enough to hold the data? Base64 encoding adds about 1.3 times to the length of the string which would be truncated on some DB systems.

MANCHUCK
the field should be long enough. I set it to longvarchar (in MySQL). It there a longer field type I should use?But for the most part my script works. And most of the objects are about the same size so I don't think the problem is saving to the database. I think it fails upon serialization or else encoding.
Gordon Potter
Do you know if the data is getting inserted into the database or is the failure happening before hand? Why not try to write a simple iterator that goes through all the records to decode and un-serialize the data and look for the error (base64_decode and un-serialize both return false if they fail).Also I was checking the bugs for serialize and un-serialize and found that there are some issues with on certian builds and certian OS's. Posting which PHP version and OS you are using might help to identify if those bugs are the culprit.
MANCHUCK
Also try using a text field to store the data. That should be long enough to store the data.
MANCHUCK
+1  A: 

@Greg is correct in that you cannot serialize resources.

Given that you describe your objects as "Data objects" I have a feeling that they contain your database connection resources? (e.g. $object->rs = mysql_connect(...);).

If so, consider using __sleep() and __wakeup() functions in your data objects (__sleep() is called immediately before serialization, __wakeup() immediately after de-serialization).

The __sleep() function should close any database or file resources while the __wakeup() function should reconnect to the database.

The PHP manual entry I linked above has an example of a class that manages a DB connection that is serializeable:

<?php
class Connection {
    protected $link;
    private $server, $username, $password, $db;

    public function __construct($server, $username, $password, $db)
    {
        $this->server = $server;
        $this->username = $username;
        $this->password = $password;
        $this->db = $db;
        $this->connect();
    }

    private function connect()
    {
        $this->link = mysql_connect($this->server, $this->username, $this->password);
        mysql_select_db($this->db, $this->link);
    }

    public function __sleep()
    {
        return array('server', 'username', 'password', 'db');
    }

    public function __wakeup()
    {
        $this->connect();
    }
}
dcousineau
+2  A: 

Resources can't be serialized which might be the problem. A way to avoid this problem is to use the magic methods: __sleep and __wakeup.

Basically, your __sleep function is called when you call serialize, and __wakeup is for when you unserialize, so say it's a database connection: in sleep() close the connection and store the connection string somewhere (perhaps), and in wakeup, reconnect.

nickf