forcing access to __PHP_Incomplete_Class object properties

前端 未结 8 1858
夕颜
夕颜 2020-11-30 06:43

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.

This object is of type __PHP_Incomp

相关标签:
8条回答
  • 2020-11-30 07:12

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

    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/

    So you can do:

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

    and then access properties as normal.


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

    0 讨论(0)
  • 2020-11-30 07:18

    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.

    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->key because actually it is something like $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 );
    }
    

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

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

    There you see:

    • The private property is prefixed with NULL + classname + NULL
    • The protected property is prefixed with NULL + "*" + NULL
    0 讨论(0)
提交回复
热议问题