Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a PDO object be serialized?

Tags:

php

pdo

I am making a multi-threaded CLI-PHP application and need to serialize PDO object to pass it between work inside the thread, and wake it up from a sleeping thread using magic methods __sleep() and __wakeup(). However nor the PDO or mysqli extension supports it. The old mysql_*() api did this but it has been deprecated and removed.

<?php
    // Application
    $link = new PDO('mysql:host=localhost;port=3306;dbname=testdatabase', 'root', '');

    $obj = serialize($link);

well generate error

PHP Fatal error: Uncaught exception 'PDOException' with message 'You cannot ser ialize or unserialize PDO instances' in W:\workspace\Sandbox\application.php:5 Stack trace:

#0 [internal function]: PDO->__sleep()

#1 W:\workspace\Sandbox\application.php(5): serialize(Object(PDO))

#2 {main} thrown in W:\workspace\Sandbox\application.php on line 5

like image 619
Junior Avatar asked Dec 06 '22 00:12

Junior


2 Answers

A PDO object contains state that cannot be represented in the serialization format. For example, the PDO object contains an open connection to a database server.

If you were to try to deserialize a serialized PDO object, the __wakeup() method would have to reconnect to the database server. This would require that authentication credentials be stored in a readable manner in the serialized PDO object, which is a security no-no.

I worked on the Zend Framework's Zend_Db component a long time ago, and I deliberately designed the Zend_Db_Adapter object to not be serializable for this reason. Instances of Zend_Db_Table, Zend_Db_Table_Row, etc. could be serializable, but could not be "live" after deserialization until you assigned it a freshly connected Zend_Db_Adapter instance.

Also, there's no guarantee that the database server would be reachable at the time you deserialize the PDO object. It's unclear whether this means the deserialization would be considered "failed."

The same restrictions on serialization apply to other resources such as sockets or file handles.

See also Why isn't every type of object serializable?

like image 102
Bill Karwin Avatar answered Dec 11 '22 11:12

Bill Karwin


What's being done at http://php.net/manual/en/language.oop5.magic.php is creating a wrapper that can be serialized since the PDO link itself cannot be.

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

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

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

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

    public function __wakeup()
    {
        $this->connect();
    }
}?>

The PDO object apparently does not keep the dsn, user, pwd after connecting, and so cannot be directly serialized. But if you created a wrapper like in the example above, where you stored this information, you could serialize the wrapper. Then when you unserialize, it will create a new PDO object and reconnect by passing the credentials in from the wrapper to PDO.

like image 40
developerwjk Avatar answered Dec 11 '22 10:12

developerwjk