[英]What's the point of having __wakeup in source code of PHP 7.4 Exceptions?
有一種(相當新的)利用技術,稱為phar 反序列化 ,它由PHP的文件系統功能(如file_exists
, unlink
,...)觸發,然后在實例化的類中執行未序列化的代碼,該類至少需要包含兩種魔術方法之一__wakeup
和__destruct
。
我的想法是在PHP的源代碼中搜索內置的PHP類,這些類可能具有此類方法的本地實現( __wakeup
和__destruct
),並且可以在異常處理期間的反序列化過程中以某種方式利用(可能觸發某些使用-釋放后的錯誤)。 實際上,我在幾個Exception類中找到了__wakeup
(獲取所有內置類並檢查它們是否具有__wakeup
和__destruct
方法的簡便方法是使用PHP函數get_declared_classes()
)。 但是目前看來,這是無法解釋的。
因此,問題不在於開發事物。
問題:我不明白為什么要在異常 __wakeup
實現__wakeup
? 它只是用於擴展此類Exception類並稍后編寫自己的__wakeup
/ __destruct
方法的占位符方法嗎?
源代碼: https : //github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L316
在306-333行( php-src / Zend / zend_exceptions.c ,PHP 7.4)中:
/* }}} */
/* {{{ proto Exception::__wakeup()
Exception unserialize checks */
#define CHECK_EXC_TYPE(id, type) \
pvalue = zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &value); \
if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \
zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \
}
ZEND_METHOD(exception, __wakeup)
{
zval value, *pvalue;
zval *object = ZEND_THIS;
CHECK_EXC_TYPE(ZEND_STR_MESSAGE, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_STRING, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_CODE, IS_LONG);
CHECK_EXC_TYPE(ZEND_STR_FILE, IS_STRING);
CHECK_EXC_TYPE(ZEND_STR_LINE, IS_LONG);
CHECK_EXC_TYPE(ZEND_STR_TRACE, IS_ARRAY);
pvalue = zend_read_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1, 1, &value);
if (pvalue && Z_TYPE_P(pvalue) != IS_NULL && (Z_TYPE_P(pvalue) != IS_OBJECT ||
!instanceof_function(Z_OBJCE_P(pvalue), zend_ce_throwable) ||
pvalue == object)) {
zend_unset_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1);
}
}
/* }}} */
及以后的第788-801行: https : //github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L788
static const zend_function_entry default_exception_functions[] = {
ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, __toString, NULL, 0)
ZEND_FE_END
};
據我所知,這段代碼正在驗證異常屬性的類型,如果類型不正確,則將它們設置為null
。 例如:
CHECK_EXC_TYPE(ZEND_STR_MESSAGE, IS_STRING);
大致等同於PHP代碼:
if (!is_string($this->message))
$this->message = null;
同樣,以pvalue = zend_read_property(…)
開頭的結尾的代碼正在檢查$this->previous
是實現Throwable
的對象。 在PHP中,它大致等同於:
if (!is_object($this->previous) || !($this->previous instanceof Throwable)
$this->previous = null;
至於為什么此代碼是PHP解釋器的一部分? Exception
類的全部在此處用C代碼定義。 內置類或方法都不是用PHP編寫的-不能這樣,因為該語言無法將方法的PHP實現安裝到用C聲明的類中。
我想說的是,由於Exception類應該是可反序列化的,因此它需要已經在C級別添加了__wakeup()
方法(因為Exception類的屬性也已在C中定義)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.