【问题标题】:Unserialize an object which had properties with different level of access反序列化具有不同访问级别的属性的对象
【发布时间】:2018-03-18 05:06:32
【问题描述】:

我有一个具有这种定义的类:

class AClass {
    private $member;
}

我在不同的页面中序列化和反序列化这个类,它工作正常。

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

class AClass {
    public $member;
}

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

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

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

谢谢

【问题讨论】:

  • 你能举个例子吗?
  • 我认为这会很困难,因为它意味着两个执行周期。一个定义第一种类型的类,对序列化对象的成员具有私有访问级别,另一个执行定义第二种类型的类,对尝试反序列化的成员具有公共访问级别。
  • 无论如何,像这样 - 3v4l.org/eTp6j
  • 编辑序列化字符串可能看起来很草率,但不幸的是,这可能也是最好的方法。
  • 也许在类定义中将属性可见性恢复为私有,以便反序列化再次工作,但提供魔术 __get()/__set() 方法使其可公开访问

标签: php oop object serialization


【解决方案1】:

您不能只是更改类定义并希望一切都会好起来。
当成员为private时,序列化字符串如下:

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

当成员为 public - 序列化字符串为:

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

这就是你得到null 的原因——你不能从外部访问私人成员。 解决方案是更新数据库中的序列化字符串 - 通过从字段定义中删除 ATest 类名部分。

【讨论】:

    【解决方案2】:

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

    <?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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 2022-12-15
      相关资源
      最近更新 更多