强制访问__PHP_Incomplete_Class对象属性

gpi*_*ino 32 php

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

此对象的类型__PHP_Incomplete_Class是因为在会话启动之前不包含所需的头文件.我不能在不破解核心cms代码的情况下包含它.

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

小智 60

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

无法直接访问PHPIncompleteClass对象,但foreach,serialize和gettype都可以.使用PHPIncompleteClass对象调用is_object将导致false.

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

function fixObject (&$object)
{
  if (!is_object ($object) && gettype ($object) == 'object')
    return ($object = unserialize (serialize ($object)));
  return $object;
}
Run Code Online (Sandbox Code Playgroud)

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

fixObject($_SESSION['member']);
Run Code Online (Sandbox Code Playgroud)

  • 你也可以使用自动加载器加载类,这会使整个问题消失. (2认同)
  • 从 PHP 7.2 开始,这将不再有效,因为 is_object() 将为不完整的对象返回 true。您需要使用不同的方法来检测对象是否不完整。https://www.php.net/manual/en/function.is-object.php#refsect1-function.is-object-changelog (2认同)

Tom*_*igh 18

我发现这个hack会让你施放一个物体:

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

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

所以你可以这样做:

$obj = casttoclass('stdClass', $incompleteObject);
Run Code Online (Sandbox Code Playgroud)

然后正常访问属性.


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


Mir*_*rya 6

除了这个解决方案之外,上述答案实际上都不适合我:

$object = 反序列化(serialize($object));

$对象->函数();

希望它可以帮助某人

  • 是的,这对我有帮助。$object = 反序列化(serialize($object)); 独自一人似乎已经奏效 (2认同)

Phi*_*ipp 5

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

当 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+:"\0.*?\0([^"]+)"/', $fix_key, $dump );

    // 4. Unserialize the modified object again.
    return unserialize( $dump );
}
Run Code Online (Sandbox Code Playgroud)

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

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;}"
Run Code Online (Sandbox Code Playgroud)

在那里你看到:

  • 私有财产以 NULL + classname + NULL
  • 受保护的属性以 NULL + "*" + NULL