PHP严格反序列化

4

我有一个存在于MemCached中的带有错别字的类。以下是一个例子:

class Person { public $n1ame; }
echo serialize(new Person());

我在下一个代码版本中修复了拼写错误:
class Person { public $name; }
var_dump(unserialize($previousSerializedPersion));

但是实际上会发生这样的情况:PHP隐式地向我的对象中添加了不存在的字段:
object(Person)#1 (2) {
  ["name"]=>
  NULL
  ["n1ame"]=>
  NULL
}

我的人员获得了带有数据的额外字段。我期望会出现异常。

有没有办法实现这一点?


你从哪里获取$previousSerializedPersion,它是否已经包含旧的n1ame属性? - RiggsFolly
在这个例子中,我从上一次执行的serialize(new Person())中获取$previousSerializedPersionPerson::$n1ame。假设我将其存储在Memcache中,然后接收它 :) - zored
3
那么旧的错误版本就在缓存中。清除缓存,然后重新开始。 - RiggsFolly
1
我期望的是一个异常。然后使用静态类型语言,而不是动态类型语言。虽然在您的情况下,抛出异常可能是一种理想的结果,但在更新其上层代码时处理大型数据集时,当PHP在反序列化时不抛出异常会更加容易。 - symcbean
1
虽然我的答案是为了“纠正”这个问题,但如果你真的需要的话,你可以使用__wakeup()来抛出异常。 - Scuzzy
1个回答

6

三个建议:

1.) 在调用unserialize()之前,对序列化的数据字符串进行手动字符串翻译以进行纠正。

O:6:"Person":1:{s:5:"n1ame";N;}

s:5 表示原始序列化中属性 n1ame 的字符长度,您需要将其更改为 s:4 以将其恢复为 name,其中的 s 表示字符串数据类型,数字是文本值的长度,在此示例中是属性键。

O:6:"Person":1:{s:4:"name";N;}

你可以尝试一下。
unserialize( str_replace( 's:5:"n1ame"', 's:4:"name"', $previousSerializedPersion ) );

2.) 另一个解决方案是使用__wakup()函数来纠正您的数据。此函数在序列化对象后但在分配和使用之前运行,这可能是一种“更好”的解决方案,因为它在代码中清晰地展现出来。

class Person
{
  public $name;
  public function __wakeup()
  {
    if( property_exists( $this, 'n1ame' ) )
    {
      $this->name = $this->n1ame;
      unset( $this->n1ame );
    }
  }
}

unserialize('O:6:"Person":1:{s:5:"n1ame";s:4:"mark";}');

3.) 使用相同的 __wakup() 概念,但是抛出一个异常。

class Person
{
  public $name;
  public function __wakeup()
  {
    if( property_exists( $this, 'n1ame' ) )
    {
      throw new Exception('oh no this data is bad');
    }
  }
}

unserialize('O:6:"Person":1:{s:5:"n1ame";s:4:"mark";}');

https://3v4l.org/h8pss


1
谢谢您如此详细的回答 :) - zored

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接