改变了 (un)serialize() 的行为?

2024-06-28

编辑:问题是现在已记录的 php 错误:https://bugs.php.net/bug.php?id=71617 https://bugs.php.net/bug.php?id=71617感谢您找到那个@Danack

我刚刚将应用程序从 PHPH 5.5 迁移到 PHP 7,在序列化对象时偶然发现了一些奇怪的行为。

我试图将其简化为一个最小的、完整的和可验证的示例,可以在以下位置找到:http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8 http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8

问题是如果一个类扩展数组对象 http://php.net/manual/en/class.arrayobject.php那么如果你serialize()进而unserialize()该对象:

  1. 创建一个具有私有属性的类以及该属性的 getter/setter 方法
  2. 创建该类的一个对象
  3. 通过setter方法设置私有属性
  4. serialize() object
  5. unserialize()步骤 4 的结果
  6. call getter method of private property, result depends on your PHP version
    • PHP 5.3 - PHP 5.6:结果是步骤 3 中设置的值
    • PHP 7:结果为空

我试图将其简化为一个最小的、完整的和可验证的示例,可以在以下位置找到:http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8 http://sandbox.onlinephpfunctions.com/code/e926a7398119ea715531cafe4ce6a22c329e53b8您可以在其中使用不同的 PHP 版本测试代码。

<?php
class demoStdObject {
    public $public = ''; protected $protected = ''; private $private = '';

    public function getPublic() { return $this->public; }    
    public function getProtected() { return $this->protected; }    
    public function getPrivate() { return $this->private; }        
    public function setPublic($public) { $this->public = $public; }    
    public function setProtected($protected) { $this->protected = $protected; }    
    public function setPrivate($private) { $this->private = $private; }
}

class demoArrayObject extends ArrayObject {
    public $public = ''; protected $protected = ''; private $private = '';
    public function getPublic() { return $this->public; }    
    public function getProtected() { return $this->protected; }    
    public function getPrivate() { return $this->private; }        
    public function setPublic($public) { $this->public = $public; }    
    public function setProtected($protected) { $this->protected = $protected; }    
    public function setPrivate($private) { $this->private = $private; }
}


$arrayObject = new demoArrayObject();
$stdObject = new demoStdObject();

testSerialize($arrayObject);
echo str_repeat('-',30) . "\n";
testSerialize($stdObject);

function testSerialize($object) {
  $object->setPublic('public');
  $object->setProtected('protected');
  $object->setPrivate('private');

  $serialized = serialize($object);

  $unserialized = unserialize($serialized);

  echo get_class($object) . ":\n";
  echo $unserialized->getPublic() . "\n";
  echo $unserialized->getProtected() . "\n";
  echo $unserialized->getPrivate() . "\n";
}

PHP 5.6 的输出:

demoArrayObject:
public
protected
private
------------------------------
demoStdObject:
public
protected
private

PHP 7 的输出:

demoArrayObject:
public
protected

------------------------------
demoStdObject:
public
protected
private

我找不到与以下内容相关的任何记录的更改serialize(), unserialize() or the ArrayObject类,所以我想知道发生了什么事。这是一个错误吗?未记录的功能? ;-)

正如我们做了很多serialize() / unserialize()在我们的项目中,我确实需要确保 PHP 7 的行为与 PHP 5.3+ 的行为 100% 兼容。

问题:如何使 PHP 7 表现得像 PHP 5.3+?


尽管这个问题在 PHP 的下一个版本中得到了修复,但您的代码依赖于未记录的行为这一事实是一个称为“巧合编程 https://pragprog.com/the-pragmatic-programmer/extracts/coincidence”。摘自精品文章:

如何通过巧合进行编程

假设 Fred 被分配了一项编程任务。弗雷德输入一些代码并尝试一下,它似乎有效。 Fred 输入了更多代码,尝试了一下,它似乎仍然有效。以这种方式编码几周后,程序突然停止工作,经过几个小时的尝试修复后,他仍然不知道为什么。 Fred 可能会花费大量时间来查找这段代码,但无法修复它。无论他做什么,似乎总是行不通。

实施事故

实施事故是指仅仅因为当前代码的编写方式而发生的事情。您最终会依赖未记录的错误或边界条件。

在这种情况下,不能保证当您扩展 ArrayObject 时,子类的值将被正确反序列化。

使用组合而不是继承会更安全,或者在子方法上编写序列化/反序列化方法将允许您控制序列化/反序列化。或者,不使用序列化/反序列化而使用您自己的接口也比“神奇”的内部方法更可预测。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

改变了 (un)serialize() 的行为? 的相关文章

  • PHP SFTP 简单文件上传

    我正在使用 phpseclib SFTP 类 并尝试上传这样的文件 sftp new Net SFTP mydomain com if sftp gt login user password exit Login Failed sftp g
  • PHPUnit:当将类型作为第二个参数作为非字符串传递时,assertInstanceOf() 不起作用

    我需要检查变量是否是User type User是我的班级 user我的对象 this gt assertInstanceOf user User 这是行不通的 我有以下错误 use of undefined constant User a
  • android php 连接错误? (添加java代码)

    我试图从 android 应用程序获取位置 纬度 经度 并使用 php 插入数据库 然后提取 10m 半径内的数据 问题是 当我使用智能手机测试代码时 本地测试正常 数据未正确插入 表 usergps 有 3 列 名称 纬度 经度 在我测试
  • 如果 Woocommerce 单一产品中的库存数量少于 10,请在库存数量旁边添加文本

    我发现这是作为另一个线程的评论发布的 但我不知道应该用它做什么 if product gt get stock quantity lt 10 echo Limited supply left 我想它应该有一个钩子 我试过woocommerc
  • 循环引用和ScriptIgnore问题

    我有几个相互引用的 BusinessObject 类 我需要在 JsonResponse 中序列化一个类并将其返回到我的视图 我不断收到循环引用异常 但无法摆脱它 我已经放置了 ScriptIgnore 每个不是简单数据类型属性的属性上的装
  • Codeigniter Cart - 将数据保存在数据库中 - 如何处理?

    我需要帮助在我的网络应用程序中处理订单和购物车 我决定使用 Codeigniter 2 中内置的 Cart 库 我看过一些关于 Cart 库的教程 我知道如何使用它 但我不知道 我什么时候应该在数据库中创建 保存该订单 当用户将商品添加到购
  • 正则表达式多次匹配多行

    我有一个像这样的字符串 Name John Doe Age 23 Primary Language English Description This is a multiline description field that I want
  • 查找定义类的 PHP 文件(在运行时)

    PHP 中是否有任何反射 内省 魔法可以让您找到定义特定类 或函数 的 PHP 文件 换句话说 我有一个 PHP 类的名称 或者一个实例化对象的名称 我想把这个传递给某物 函数 反射类等 将返回定义该类的文件系统路径 path to cla
  • 使用 Wikipedia API 查找文章的主要类别

    我有一个文章列表 我想找到每篇文章的主要类别 维基百科在这里列出了它的主要类别 http en wikipedia org wiki Portal Contents Categories http en wikipedia org wiki
  • 如何使用 DbSession 在 Yii2 中创建用户会话管理系统 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 今天 当我想为我的网站创建用户个人资料页面并希望创建系统用户可以管理他在此系统中的活动会话时 需要 查看活动会话 浏览器和平台 查看当
  • WordPress 中的多词搜索不显示搜索结果

    我自定义了一个主题 但在使用多词查询的搜索结果时遇到一些问题 网站上线时间为www aetterworldbydesign com http abetterworldbydesign com 搜索单个单词 http www abetterw
  • 将 WooCommerce 属性标签替换为每个的自定义图像

    我正在做一个项目 我需要一些团体的帮助 我正在使用 woocommerce 产品系统 在商店存档页面产品上我显示属性标签 属性值 就像文本一样 属性标签 属性值 例如传输 手动 有没有办法将属性标签显示为图像 我无法添加 html 代码 i
  • PHP 数组比较

    如何比较两个数组 例如我有array a b c and array a c b 当它们进行比较时 它会返回 true 但如果其中一个字母没有在其中之一中找到 它将返回 false 顺序并不重要 在比较之前 您需要将两个数组的内容调整为相同
  • PHP curl 获取标头参数

    我将curl 与PHP 结合使用来获取API 调用的标头响应 这是我的代码 curl curl init curl setopt curl CURLOPT URL http localapi com v1 users curl setopt
  • PHP 会话混乱

    好吧 我已经很困惑了 我有一个存储在会话中的对象 我可以向该对象添加项目 到目前为止非常简单 我像这样初始化对象 template new Template mysqli SESSION template serialize templat
  • Codeigniter 错误:不允许您尝试上传的文件类型

    如果我上传一个csv文件 没有问题localhost一切工作正常 但是当我在实时服务器上上传我的应用程序并上传csv文件然后抛出此错误 The filetype you are attempting to upload is not all
  • 在cakephp中调用函数

    public function data if old status prev lat lat prev long long if status Village Unknown exec query else if status Town
  • 比在配置文件中以纯文本形式存储 mysql 密码更好的方法吗?

    许多 PHP 程序要求用户将 mysql 密码以纯文本 字符串或常量 形式存储在应用程序根目录的配置文件中 这一直困扰着我 这么多年过去了 还有更好的方法吗 到目前为止 我已经提出了两个最小的安全提升方案 使用 htaccess 中的规则使
  • PHP 中的金字塔星号

    请看我的代码 for row var row gt 1 row for j 0 j lt row j echo echo echo nbsp Output 但我需要输出如下 您可能想查看一些字符串函数
  • 当我在对象上调用函数时,为什么会在非对象上出现此函数调用错误? [复制]

    这个问题在这里已经有答案了 Error 致命错误 调用成员函数 中的非对象上的bind param var www web55 web pdftest events php 76号线 Code public function countDa

随机推荐