2009-06-08 53 views
30

我正在爲php cms編寫一個模塊。在函數(回調函數)中,我可以訪問來自框架代碼的對象。強制訪問__PHP_Incomplete_Class對象屬性

此對象的類型爲__PHP_Incomplete_Class,因爲會話啓動之前不包括所需的頭文件。我不能在不侵犯核心cms代碼的情況下包含它。

我想知道是否可以訪問對象屬性無論如何(鑄造陣列不工作)。我問這個,因爲我可以看到var_dump()的值,但使用$object->var我總是得到空值。

回答

57

當您序列化尚未包含的類的對象時,會出現此問題。 例如,如果在包含類之前調用​​session_start。

PHPIncompleteClass對象不能直接訪問,但可以使用foreach,serialize和gettype。 使用PHPIncompleteClass對象調用is_object將導致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

我發現這個技巧可以讓你施放一個對象:

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

整潔讀取對象後,把在session_start()。我只是喜歡做這樣的黑客東西;) – n3rd 2009-06-08 16:21:06

+0

聰明但「hackish」:]我首先想到了eval(東西)。 – gpilotino 2009-06-08 17:11:09

+0

感謝發佈!注意:它應該是casttoclass('stdClass',$ incompleteObject)。 – Langdon 2010-02-06 22:29:51

0

如果你只是需要從PHP_Incomplete_Class對象訪問原始數據(如類變量),你可以使用foreach黑客,或者你也可以這樣做:

$result_array = (array)$_SESSION['incomplete_object_index']; 
echo $result_array['desired_item']; 
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將不顯示這些空字節前綴給你,但你可以看到他們使用此代碼:

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
  • 受保護的原型RTY加上前綴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

您需要的類,你正試圖從會話