принудительный доступ к свойствам объекта __PHP_Incomplete_Class - PullRequest
31 голосов
/ 08 июня 2009

Я пишу модуль для php cms. В функции (обратный вызов) я могу получить доступ к объекту, который поступает из кода платформы.

Этот объект имеет тип __PHP_Incomplete_Class, поскольку необходимый файл заголовка не включен до начала сеанса. Я не могу включить его без взлома основного кода CMS.

Интересно, можно ли в любом случае получить доступ к свойствам объекта (приведение к массиву не работает). Я спрашиваю об этом, потому что я могу видеть значения с var_dump(), но с помощью $object->var я всегда получаю нули.

Ответы [ 6 ]

59 голосов
/ 23 июля 2009

Эта проблема возникает, когда вы не сериализуете объект класса, который еще не был включен. Например, если вы вызываете session_start перед включением класса.

Объект PHPIncompleteClass не может быть доступен напрямую, но он подходит для foreach, serialize и gettype. Вызов is_object с объектом PHPIncompleteClass приведет к false.

Итак, если вы нашли объект '__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']);
18 голосов
/ 08 июня 2009

Я нашел этот хак, который позволит вам разыграть объект:

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 голосов
/ 05 февраля 2015

В качестве дополнения приведу мою версию функции 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
0 голосов
/ 21 июля 2016

Поместите session_start () после вашего требования к классу объекта, который вы пытаетесь прочитать из СЕССИИ

0 голосов
/ 08 марта 2016

Я прочитал много предложений о том, как исправить неполные классы объектов, и мне действительно нужно было решить эти проблемы самостоятельно, в проекте электронной коммерции.

Одно предложение, которое я нашел, - просто использовать json_decode / json_encode для преобразования неполных классов без предварительной загрузки чего-либо. Однако я не хотел рисковать, используя это, если есть более старые версии PHP, которые зависят, например, от PECL, который описан в http://php.net/manual/en/function.json-encode.php - так что мне наконец удалось найти собственное решение. 1005 *

Однако код - это способ правильно извлечь данные из объекта, поэтому он может не соответствовать всем потребностям - и в первую очередь он будет использовать решение 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;
}
0 голосов
/ 13 июня 2013

Если вам просто нужен доступ к необработанным данным (например, переменным класса) из объекта PHP_Incomplete_Class, вы можете использовать хак foreach или также сделать:

$result_array = (array)$_SESSION['incomplete_object_index'];
echo $result_array['desired_item'];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...