2009-06-08 3 views
30

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

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

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

ответ

57

Эта проблема добавляется, когда вы не сериализуете объект класса, который еще не был включен. Например, если вы вызываете 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']); 
+0

На этом втором фрагменте кода вы имели в виду fixObject вместо fixclass? Может быть, смущает. – Cyprus106

+2

вы можете также использовать автозагрузчик для загрузки класса, что бы устранить всю проблему. – StasM

+0

после unserialized, я не могу получить доступ к свойствам, но foreach в порядке для меня. – Sithu

18

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

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); 

и затем свойства доступа, как обычно.


Можно также определить в конфигурационном файле .htaccess/Apache в unserialize_callback_func. Таким образом, вам не нужно будет взломать любой PHP, но вы можете включить файл по требованию.

+0

аккуратного. Мне просто нравится делать такие взломанные вещи;) – n3rd

+0

умный, но «хакерский»:] Сначала я думал об eval (что-то). – gpilotino

+0

Спасибо за сообщение! Примечание: это должен быть casttoclass ('stdClass', $ incompleteObject). – Langdon

0

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

$result_array = (array)$_SESSION['incomplete_object_index']; 
echo $result_array['desired_item']; 
+0

кастинг не работает в этом случае – gpilotino

+1

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

+0

его полезно, когда вам нужно выполнить миграцию базы данных и нужны только простые данные, хранящиеся в серийном объекте. –

3

В добавление к здесь, моя версия функции fix_object(): основное изменение - это шаг 3 в тексте: Сделать любую недвижимость публичной.

Когда PHP сериализует объект, все частные и защищенные свойства имеют префикс с двумя нулевыми байтами! Эти null-байты являются фактической причиной, почему свойство не может быть доступно через $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
  • Защищенное свойство - p refixed с NULL + "*" + NULL
0

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

Одно из предложений, которое я нашел, - это просто использовать 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; 
} 
0

Поместите session_start() после того, как ваши требуйте к классу объекта, который вы пытаетесь прочитать от ЗАСЕДАНИЯ