对具有不同访问级别的属性的对象进行反序列化

时间:2017-10-06 11:42:52

标签: php oop object serialization

我有一个有这种定义的课程:

class AClass {
    private $member;
}

我在不同的页面中对此类进行序列化和反序列化,并且工作正常。

现在由于某些原因,我不得不将类定义更改为:

class AClass {
    public $member;
}

现在,当反序列化时,我得到一个null $ member值而不是存储在serialize字符串中的值。

很难给出一个有效的例子,因为这需要两个执行周期,但可以这样合成:https://3v4l.org/eTp6j

解决此问题的最佳方法是什么?我现在唯一想到的就是编辑序列化的字符串,这似乎是一个草率的黑客。

由于

2 个答案:

答案 0 :(得分:0)

你不能只改变类定义,希望一切都会好起来的。
当成员私有序列化字符串如下所示:

string(53) "O:5:"ATest":1:{s:13:"ATestmember";s:9:"something";}"

当成员公开时 - 序列化字符串为:

string(45) "O:5:"ATest":1:{s:6:"member";s:9:"something";}"

这就是您获得null的原因 - 您无法从外部访问私人会员。 解决方案是更新数据库中的序列化字符串 - 通过从字段定义中删除ATest类名称部分。

答案 1 :(得分:0)

我最终更改了数据库中的序列化字符串,但我必须知道哪些类的属性访问级别已更改。您可以批量为整个数据库执行此操作,但是当我们在一段时间后转储旧结果时,我已选择即时修改序列化字符串。

<?php

function newUnserializeFunction($response)
{
    // Edit string
    $classes = [
        ATest::class
    ];

    foreach ($classes as $class) {
        do {
            // Private class name
            $result = replaceClassPrivateProtectedToPublic("\0" . $class . "\0", $response);
        } while ($result);
        do {
            // Protected class name
            $result = replaceClassPrivateProtectedToPublic("\0*\0" . $class . "\0*\0", $response);
        } while ($result);
    }

    // Unserialize
    $return = \unserialize($response);

    return $return;
}

function replaceClassPrivateProtectedToPublic($className, &$content)
{
    $classNameWithSlashes = preg_quote($className, '/');
    $result = preg_match('/(([\d]+)\:\"' . $classNameWithSlashes . '([a-zA-Z0-9_]+))/', $content, $matches, PREG_OFFSET_CAPTURE);

    if($result && count($matches) >= 4) {
        $lengthOffset = $matches[2][1];
        $lengthLength = strlen($matches[2][0]);

        $length = strlen($matches[3][0]);

        // Replace the class name
        $content = preg_replace('/'.$classNameWithSlashes.'/', '', $content, 1);

        // Replace the class name length
        $content = substr_replace($content, $length, $lengthOffset, $lengthLength);
    }

    return $result;
}