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.
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.
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 :
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']);
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.
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:
NULL + classname + NULL
NULL + "*" + NULL
None of the above answers actually worked for me, except this solution:
$object = unserialize(serialize($object));
$object->function();
Hope it helps someone
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:
$result_array = (array)$_SESSION['incomplete_object_index'];
echo $result_array['desired_item'];
I tried the answer of Tom Haigh here, but discovered 2 problems.
__PHP_Incomplete_Class Object
stdClass
objectSo I rewrote the function handle this:
/**
* @see: https://stackoverflow.com/a/965704/2377961
*
* @param object $object The object that should be casted
* @param String $class The name of the class
* @return mixed The new created object
*/
function casttoclass($object, $class = 'stdClass')
{
$ser_data = serialize($object);
# preg_match_all('/O:\d+:"([^"]++)"/', $ser_data, $matches); // find all classes
/*
* make private and protected properties public
* privates is stored as "s:14:\0class_name\0property_name")
* protected is stored as "s:14:\0*\0property_name")
*/
$ser_data = preg_replace_callback('/s:\d+:"\0([^\0]+)\0([^"]+)"/',
function($prop_match) {
list($old, $classname, $propname) = $prop_match;
return 's:'.strlen($propname) . ':"' . $propname . '"';
}, $ser_data);
// replace object-names
$ser_data = preg_replace('/O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', $ser_data);
return unserialize($ser_data);
}
I switch tha function arguments too, so that you can use
$obj = casttoclass($incompleteObject);
And you get an stdClass
object with only public properties.
Even if you have objects in childclasses they are converted to stdClass
with public properties too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With