diff --git a/NEWS b/NEWS index 1c1cf6acae6..44c6a11c17c 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS . Fixed bug #73182 (PHP SOAPClient does not support stream context HTTP headers in array form). (nielsdos) . Fixed bug #62900 (Wrong namespace on xsd import error message). (nielsdos) + . Fixed bug GH-15711 (SoapClient can't convert BackedEnum to scalar value). + (nielsdos) 12 Sep 2024, PHP 8.3.12 diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 790a7029a63..fda34b080e3 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -826,11 +826,46 @@ static zval *to_zval_hexbin(zval *ret, encodeTypePtr type, xmlNodePtr data) static zend_string *get_serialization_string_from_zval(zval *data) { switch (Z_TYPE_P(data)) { + case IS_OBJECT: + if (Z_OBJCE_P(data)->ce_flags & ZEND_ACC_ENUM) { + if (UNEXPECTED(Z_OBJCE_P(data)->enum_backing_type == IS_UNDEF)) { + zend_value_error("Non-backed enums have no default serialization"); + return zend_empty_string; + } else { + zval *value = zend_enum_fetch_case_value(Z_OBJ_P(data)); + return zval_get_string_func(value); + } + } + ZEND_FALLTHROUGH; default: return zval_get_string_func(data); } } +static zend_long get_serialization_long_from_zval(zval *data) +{ + switch (Z_TYPE_P(data)) { + case IS_OBJECT: + if (Z_OBJCE_P(data)->ce_flags & ZEND_ACC_ENUM) { + if (UNEXPECTED(Z_OBJCE_P(data)->enum_backing_type != IS_LONG)) { + if (Z_OBJCE_P(data)->enum_backing_type == IS_UNDEF) { + zend_value_error("Non-backed enums have no default serialization"); + } else { + zend_value_error("String-backed enum cannot be serialized as int"); + } + return 0; + } else { + zval *value = zend_enum_fetch_case_value(Z_OBJ_P(data)); + ZEND_ASSERT(Z_TYPE_P(value) == IS_LONG); + return Z_LVAL_P(value); + } + } + ZEND_FALLTHROUGH; + default: + return zval_get_long(data); + } +} + static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { xmlNodePtr ret, text; @@ -1056,7 +1091,7 @@ static xmlNodePtr to_xml_long(encodeTypePtr type, zval *data, int style, xmlNode snprintf(s, sizeof(s), "%0.0F",floor(Z_DVAL_P(data))); xmlNodeSetContent(ret, BAD_CAST(s)); } else { - zend_string *str = zend_long_to_str(zval_get_long(data)); + zend_string *str = zend_long_to_str(get_serialization_long_from_zval(data)); xmlNodeSetContentLen(ret, BAD_CAST(ZSTR_VAL(str)), ZSTR_LEN(str)); zend_string_release_ex(str, 0); } diff --git a/ext/soap/tests/gh15711.phpt b/ext/soap/tests/gh15711.phpt new file mode 100644 index 00000000000..a49ff280fee --- /dev/null +++ b/ext/soap/tests/gh15711.phpt @@ -0,0 +1,88 @@ +--TEST-- +GH-15711 (SoapClient can't convert BackedEnum to scalar value) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- + ['book' => 'book']]); + +echo "--- Test with backed enum ---\n"; + +$book = new stdClass(); +$book->base64 = StringBackedEnum::First; +$book->string = StringBackedEnum::Second; +$book->any = StringBackedEnum::Third; +$book->hexbin = StringBackedEnum::Fourth; +$book->nmtokens = StringBackedEnum::Fifth; +$book->integer = IntBackedEnum::First; +$book->short = IntBackedEnum::Second; + +try { + $client->dotest($book); +} catch (Throwable) {} + +echo "--- Test with non-backed enum ---\n"; + +$book = new stdClass(); +$book->base64 = NonBackedEnum::First; +$book->string = NonBackedEnum::First; +$book->any = NonBackedEnum::First; +$book->hexbin = NonBackedEnum::First; +$book->nmtokens = NonBackedEnum::First; +$book->integer = NonBackedEnum::First; +$book->short = NonBackedEnum::First; + +try { + $client->dotest($book); +} catch (ValueError $e) { + echo "ValueError: ", $e->getMessage(), "\n"; +} + +echo "--- Test with mismatched enum backing type ---\n"; + +$book->integer = StringBackedEnum::First; +$book->short = StringBackedEnum::First; +try { + $client->dotest($book); +} catch (ValueError $e) { + echo "ValueError: ", $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +--- Test with backed enum --- + +QmFja2luZ1ZhbHVlMQ==BackingValue2ThirdBackingValue34261636B696E6756616C756534BackingValue512 +--- Test with non-backed enum --- +ValueError: Non-backed enums have no default serialization +--- Test with mismatched enum backing type --- +ValueError: String-backed enum cannot be serialized as int diff --git a/ext/soap/tests/gh15711.wsdl b/ext/soap/tests/gh15711.wsdl new file mode 100644 index 00000000000..b49ef987b82 --- /dev/null +++ b/ext/soap/tests/gh15711.wsdl @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +