php 强制访问 __PHP_Incomplete_Class 对象属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/965611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 00:31:12  来源:igfitidea点击:

forcing access to __PHP_Incomplete_Class object properties

php

提问by gpilotino

I'm writing a module for a php cms. In a function (a callback) I can access an object that comes from the framework code.

我正在为 php cms 编写一个模块。在函数(回调)中,我可以访问来自框架代码的对象。

This object is of type __PHP_Incomplete_Classbecause the needed header file is not included before the session starts. I cannot include it without hacking the core cms code.

此对象属于类型,__PHP_Incomplete_Class因为在会话开始之前不包含所需的头文件。我不能在不破解核心 cms 代码的情况下包含它。

I wonder if is possibile to access the object properties anyway (casting to array does not work). I ask this because I can see the values with var_dump()but using $object->varI always get nulls.

我想知道是否可以访问对象属性(转换为数组不起作用)。我问这个是因为我可以看到值,var_dump()但使用$object->var我总是得到空值。

回答by

This issue appends when you un serialize an object of a class that hasn't been included yet. For exemple, if you call session_start before include the class.

当您取消序列化尚未包含的类的对象时,会附加此问题。例如,如果在包含类之前调用​​ session_start。

A PHPIncompleteClass object can't be accessed directly, but it's ok with foreach, serialize and gettype. Calling is_object with an PHPIncompleteClass object will result false.

不能直接访问 PHPIncompleteClass 对象,但可以使用 foreach、serialize 和 gettype。使用 PHPIncompleteClass 对象调用 is_object 将导致 false。

So, if you find a '__PHP_Incomplete_Class' object in your session and you've included your class after the session_load, you can use this function :

因此,如果您在会话中找到一个 '__PHP_Incomplete_Class' 对象并且在 session_load 之后包含了您的类,则可以使用此函数:

function fixObject (&$object)
{
  if (!is_object ($object) && gettype ($object) == 'object')
    return ($object = unserialize (serialize ($object)));
  return $object;
}

This will results a usable object :

这将产生一个可用的对象:

fixObject($_SESSION['member']);

回答by Tom Haigh

I found this hack which will let you cast an object:

我发现了这个 hack 可以让你投射一个对象:

function casttoclass($class, $object)
{
  return unserialize(preg_replace('/^O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', serialize($object)));
}

From http://blog.adaniels.nl/articles/a-dark-corner-of-php-class-casting/

来自http://blog.adaniels.nl/articles/a-dark-corner-of-php-class-casting/

So you can do:

所以你可以这样做:

$obj = casttoclass('stdClass', $incompleteObject);

and then access properties as normal.

然后像往常一样访问属性。



You could also define an unserialize_callback_funcin a .htaccess/Apache configuration file. That way you wouldn't need to hack any PHP but you could include the file on demand.

您还可以unserialize_callback_func在 .htaccess/Apache 配置文件中定义 。这样您就不需要破解任何 PHP,但您可以按需包含该文件。

回答by Philipp

As an addition here is my version of the fix_object() function: The main change is step 3 in the code: Make all properties public.

作为补充,这是我的 fix_object() 函数版本:主要更改是代码中的第 3 步:将所有属性设为 public

When PHP serializes an object, all private and protected properties are prefixed with two null-bytes! These null-bytes are the actual reason, why the property cannot be accessed via $obj->keybecause actually it is something like $obj->{NULL*NULL}key.

当 PHP 序列化一个对象时,所有私有和受保护的属性都以两个空字节为前缀!这些空字节是实际原因,为什么不能通过访问该属性,$obj->key因为实际上它类似于$obj->{NULL*NULL}key.

/**
 * Takes an __PHP_Incomplete_Class and casts it to a stdClass object.
 * All properties will be made public in this step.
 *
 * @since  1.1.0
 * @param  object $object __PHP_Incomplete_Class
 * @return object
 */
function fix_object( $object ) {
    // preg_replace_callback handler. Needed to calculate new key-length.
    $fix_key = create_function(
        '$matches',
        'return ":" . strlen( $matches[1] ) . ":\"" . $matches[1] . "\"";'
    );

    // 1. Serialize the object to a string.
    $dump = serialize( $object );

    // 2. Change class-type to 'stdClass'.
    $dump = preg_replace( '/^O:\d+:"[^"]++"/', 'O:8:"stdClass"', $dump );

    // 3. Make private and protected properties public.
    $dump = preg_replace_callback( '/:\d+:"
class Test {
    private $AAA = 1;
    protected $BBB = 2;
    public $CCC = 3;
}

$test = new Test();
echo json_encode( serialize( $test ) );

// Output:
// "O:4:\"Test\":3:{s:9:\"\u0000Test\u0000AAA\";i:1;s:6:\"\u0000*\u0000BBB\";i:2;s:3:\"CCC\";i:3;}"

$test2 = fix_object( $test );
echo json_encode( serialize( $test2 ) );

// Output:
// "O:8:\"stdClass\":3:{s:3:\"AAA\";i:1;s:3:\"BBB\";i:2;s:3:\"CCC\";i:3;}"
.*?
$result_array = (array)$_SESSION['incomplete_object_index'];
echo $result_array['desired_item'];
([^"]+)"/', $fix_key, $dump ); // 4. Unserialize the modified object again. return unserialize( $dump ); }


var_dumpwill not display these NULL byte prefixes to you, but you can see them with this code:

var_dump不会向您显示这些 NULL 字节前缀,但您可以使用以下代码查看它们:

/**
 * Convert a object to a data object (used for repairing __PHP_Incomplete_Class objects)
 * @param array $d
 * @return array|mixed|object
 */
function arrayObjectToStdClass($d = array())
{
    /**
     * If json_decode and json_encode exists as function, do it the simple way.
     * http://php.net/manual/en/function.json-encode.php
     */
    if (function_exists('json_decode') && function_exists('json_encode')) {
        return json_decode(json_encode($d));
    }
    $newArray = array();
    if (is_array($d) || is_object($d)) {
        foreach ($d as $itemKey => $itemValue) {
            if (is_array($itemValue)) {
                $newArray[$itemKey] = (array)$this->arrayObjectToStdClass($itemValue);
            } elseif (is_object($itemValue)) {
                $newArray[$itemKey] = (object)(array)$this->arrayObjectToStdClass($itemValue);
            } else {
                $newArray[$itemKey] = $itemValue;
            }
        }
    }
    return $newArray;
}

There you see:

在那里你看到:

  • The private property is prefixed with NULL + classname + NULL
  • The protected property is prefixed with NULL + "*" + NULL
  • 私有财产以 NULL + classname + NULL
  • 受保护的属性以 NULL + "*" + NULL

回答by Eric

If you just need to access raw data (like class variables) from a PHP_Incomplete_Class object, you can use the foreach hack, or you can also do:

如果您只需要从 PHP_Incomplete_Class 对象访问原始数据(如类变量),您可以使用 foreach hack,或者您也可以这样做:

##代码##

回答by Tomas Tornevall

I've read a lot of suggestions on how to fix incomplete classobjects and I actually needed to fix those problems myself, in a ecommerce-project.

我已经阅读了很多关于如何修复不完整的类对象的建议,实际上我需要在电子商务项目中自己解决这些问题。

One suggestion I've found is to simply use json_decode/json_encode to convert incomplete classes without preloading anything. However, I didn't want to take the risk using this, if there are older PHP versions that are dependent in for example PECL, that is described at http://php.net/manual/en/function.json-encode.php- so I finally succeeded to make my own solution.

我发现的一个建议是简单地使用 json_decode/json_encode 来转换不完整的类而不预加载任何东西。但是,我不想冒险使用它,如果有旧的 PHP 版本依赖于例如 PECL,在http://php.net/manual/en/function.json-encode 中描述。 php- 所以我终于成功地做出了自己的解决方案。

However, the code is a way to get the data out of the object properly, so it may not fit all needs - and it will primarily, use the json-solution first, if it is available in the environment and fail over to manual handling if needed.

但是,该代码是一种从对象中正确获取数据的方法,因此它可能无法满足所有需求 - 并且主要是首先使用 json-solution,如果它在环境中可用并故障转移到手动处理如果需要的话。

It also works recursively, which in my own case is required, to save the whole array.

它也可以递归地工作,这在我自己的情况下是必需的,以保存整个数组。

##代码##

回答by Mahder

Put the session_start() after your require to the class of the object you are trying to read from the SESSION

将 session_start() 放在您想要从 SESSION 中读取的对象的类之后

回答by Mirwais Shah Arya

None of the above answers actually worked for me, except this solution:

除了这个解决方案外,以上答案都没有对我有用:

$object = unserialize(serialize($object));

$object = unserialize(serialize($object));

$object->function();

$object->function();

Hope it helps someone

希望它可以帮助某人