Принудительный доступ к свойствам объекта __PHP_Incomplete_Class
Я пишу модуль для php cms. В функции (обратном вызове) я могу получить доступ к объекту, который поступает из кода рамки.
Этот объект имеет тип __PHP_Incomplete_Class
, потому что необходимый заголовочный файл не включается до начала сеанса. Я не могу включить его без взлома кода cms cms.
Интересно, возможно ли вообще получить доступ к свойствам объекта (приведение в массив не работает). Я спрашиваю об этом, потому что я вижу значения с помощью var_dump()
, но используя $object->var
, я всегда получаю null.
Ответы
Ответ 1
Эта проблема добавляется, когда вы сериализуете объект класса, который еще не был включен.
Например, если вы вызываете session_start перед включением класса.
Объект PHPIncompleteClass не может быть доступен напрямую, но это нормально с foreach, serialize и gettype.
Вызов is_object с объектом PHPIncompleteClass приведет к ошибке.
Итак, если вы обнаружите объект __PHP_Incomplete_Class в своем сеансе, и вы включили свой класс после session_load, вы можете использовать эту функцию:
function fixObject (&$object)
{
if (!is_object ($object) && gettype ($object) == 'object')
return ($object = unserialize (serialize ($object)));
return $object;
}
Это приведет к использованию полезного объекта:
fixObject($_SESSION['member']);
Ответ 2
Я нашел этот хак, который позволит вам создать объект:
function casttoclass($class, $object)
{
return unserialize(preg_replace('/^O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', serialize($object)));
}
От http://blog.adaniels.nl/articles/a-dark-corner-of-php-class-casting/
Итак, вы можете сделать:
$obj = casttoclass('stdClass', $incompleteObject);
а затем доступ к свойствам как обычно.
Вы также можете определить unserialize_callback_func
в файле конфигурации .htaccess/Apache. Таким образом, вам не нужно будет взломать любой PHP, но вы можете включить файл по требованию.
Ответ 3
В качестве дополнения здесь представлена моя версия функции fix_object():
Основное изменение - это шаг 3 в коде: Сделать все свойства общедоступными.
Когда 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 );
}
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;}"
Там вы видите:
- Частная собственность имеет префикс
NULL + classname + NULL
- Защищенное свойство имеет префикс
NULL + "*" + NULL
Ответ 4
Если вам просто нужно получить доступ к необработанным данным (например, переменным класса) из объекта PHP_Incomplete_Class, вы можете использовать foreach hack, или вы также можете:
$result_array = (array)$_SESSION['incomplete_object_index'];
echo $result_array['desired_item'];
Ответ 5
Я прочитал много предложений о том, как исправить неполные классные объекты, и мне действительно нужно было самостоятельно решить эти проблемы в проекте электронной коммерции.
Одно из предложений, которое я нашел, - просто использовать json_decode/json_encode для преобразования неполных классов без предварительной загрузки. Тем не менее, я не хотел рисковать этим, если есть более старые версии PHP, которые зависят, например, от PECL, описанного в http://php.net/manual/en/function.json-encode.php - поэтому мне, наконец, удалось сделать свое собственное решение.
Однако код является способом получения данных из объекта должным образом, поэтому он может не соответствовать всем потребностям - и в первую очередь он будет использовать json-решение, если он доступен в среде и завершится с ошибкой при необходимости вручную.
Он также работает рекурсивно, что в моем случае необходимо, чтобы сохранить весь массив.
/**
* 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;
}
Ответ 6
Поместите session_start() после вашего требования к классу объекта, который вы пытаетесь прочитать из СЕССИИ