如何使用pdo php在数据库中存储带有命名空间的序列化对象

时间:2014-01-06 20:55:06

标签: php postgresql pdo

当我尝试使用命名空间存储序列化对象时我无法做到这一点,因为我在“'O:22:”保护\ classes \ Router“或附近得到错误未终止引用的字符串。”代码:

$router = new protect\classes\Router();
$tmp = serialize($router);

$dsn = 'pgsql:dbname=system;host=127.0.0.1';
$user = 'postgres';
$password = 'mypassword';
$pdo = new PDO($dsn, $user, $password, $options);
$pdo->exec('SET search_path = temporary');
$pdo->query("SELECT replace_value('protect\classes\Router','$tmp','serialized_classes')");  // this is my function it`s work fine

如果我在执行查询之前使用php函数addslashes

  $tmp = addslashes(serialize($router));

查询成功执行。不幸的是,带有额外斜线的序列化对象是无序的。

我将感谢你对这个话题的帮助。

2 个答案:

答案 0 :(得分:2)

这里有几个问题,但最大的问题是你没有使用查询参数。

不要使用addslashes。如果你发现自己使用它,你应该想“哎呀,我需要修改查询,所以我改用参数”。

在这种情况下,你应该写一些类似的东西:

$sth = $pdo->prepare('SELECT replace_value(?, ?, ?)');
$sth->execute(array('protect\classes\Router', $tmp, 'serialized_classes'));

您还没有提到您传递序列化数据的参数的数据类型是什么。以上内容仅在textvarchar或类似内容时有效。

如果bytea类似于序列化对象数据,则必须告诉PHP该参数是二进制字段:

$sth = $pdo->prepare('SELECT replace_value(:router, :serialbytes, :mode)');
$sth->bindParam(':router', 'protect\classes\Router');
$sth->bindParam(':mode', 'serialized_classes');
$sth->bindParam(':serialbytes', $tmp, PDO::PARAM_LOB);
$sth->execute();

请注意使用PDO::PARAM_LOB来填充PDO,$tmp包含要以bytea的形式传递给PostgreSQL的二进制数据。

(可以将'protect\classes\Router'之类的常量直接放入你的查询中,顺便说一句,只要你把它们分成params,如果它们变成变量的话。我大多将它们分开,因为我发现它在查询中更具可读性像这样。)

答案 1 :(得分:1)

我遇到了同样的问题 - 在这里发现这是零字节问题。 经过一些开发后,我为Zend Serializer(ZF2)创建了一个适配器,它以一种可以在PostgreSQL中存储这些序列化值的方式重载serialize / unserialize方法。

您可以在下面找到的代码 - 希望它在某种程度上有用:)

use Zend\Serializer\Adapter\PhpSerialize;

/**
 *
 * Class overloads serialization methods so serialized objects will be PostgreSQL safe
 * For further information on safe/unsafe objects:
 * http://php.net/manual/en/function.serialize.php#96504
 *
 */
class PostgresSerialize extends PhpSerialize {

    const DEFAULT_SAFE_NULLBYTE_REPLACEMENT = "~~NULL_BYTE~~";

    protected static $serializedFalse = null;

    public function serialize($value) {
        $serializedString = parent::serialize($value);
        if (strpos($this->options['safe_nullbyte_replacement'], $serializedString))
            throw new \RuntimeException('Cannot perform safe nullbyte replace operation since safe_nullbyte_replacement="' .  $this->options['safe_nullbyte_replacement'] . '"value already exists in the serialized string', \Zend\Log\Logger::ERR);
        if ($this->options['safe_nullbyte_replacement'] == null)
            $this->options['safe_nullbyte_replacement'] = self::DEFAULT_SAFE_NULLBYTE_REPLACEMENT;
        return str_replace("\0", $this->options['safe_nullbyte_replacement'], $serializedString);
    }

    public function unserialize($serialized) {
        if ($this->options['safe_nullbyte_replacement'] == null)
            $this->options['safe_nullbyte_replacement'] = self::DEFAULT_SAFE_NULLBYTE_REPLACEMENT;
        $serializedString = str_replace($this->options['safe_nullbyte_replacement'], "\0", $serialized);
        return parent::unserialize($serializedString);
    }

}