Skip to content

Commit

Permalink
Implement backed enum coercion in http_build_query()
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Sep 18, 2024
1 parent 7a8767f commit 1b9568d
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 1 deletion.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ PHP NEWS
. Fixed bug GH-15711 (SoapClient can't convert BackedEnum to scalar value).
(nielsdos)

- Standard:
. Add support for backed enums in http_build_query(). (ilutov)

12 Sep 2024, PHP 8.4.0beta5

- BCMath:
Expand Down
1 change: 1 addition & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ PHP 8.4 UPGRADE NOTES
. php_uname() now throws ValueErrors on invalid inputs.
. The "allowed_classes" option for unserialize() now throws TypeErrors and
ValueErrors if it is not an array of class names.
. http_build_query() now correctly handles backed enums.

- Tidy:
. Failures in the constructor now throw exceptions rather than emitting
Expand Down
19 changes: 18 additions & 1 deletion ext/standard/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "SAPI.h"
#include "zend_exceptions.h"
#include "basic_functions.h"
#include "zend_enum.h"

static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
int encoding_type, zend_ulong index_int,
Expand Down Expand Up @@ -56,6 +57,7 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
}
smart_str_appendc(form_str, '=');

try_again:
switch (Z_TYPE_P(scalar)) {
case IS_STRING: {
zend_string *encoded_data;
Expand Down Expand Up @@ -90,6 +92,14 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
case IS_TRUE:
smart_str_appendc(form_str, '1');
break;
case IS_OBJECT:
ZEND_ASSERT(Z_OBJCE_P(scalar)->ce_flags & ZEND_ACC_ENUM);
if (Z_OBJCE_P(scalar)->enum_backing_type == IS_UNDEF) {
zend_value_error("Unbacked enum %s cannot be converted to a string", ZSTR_VAL(Z_OBJCE_P(scalar)->name));
return;
}
scalar = zend_enum_fetch_case_value(Z_OBJ_P(scalar));
goto try_again;
/* All possible types are either handled here or previously */
EMPTY_SWITCH_DEFAULT_CASE();
}
Expand Down Expand Up @@ -154,7 +164,9 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
}

ZVAL_DEREF(zdata);
if (Z_TYPE_P(zdata) == IS_ARRAY || Z_TYPE_P(zdata) == IS_OBJECT) {
if (Z_TYPE_P(zdata) == IS_ARRAY
|| (Z_TYPE_P(zdata) == IS_OBJECT
&& !(Z_OBJCE_P(zdata)->ce_flags & ZEND_ACC_ENUM))) {
zend_string *new_prefix;
if (key) {
zend_string *encoded_key;
Expand Down Expand Up @@ -233,6 +245,11 @@ PHP_FUNCTION(http_build_query)
Z_PARAM_LONG(enc_type)
ZEND_PARSE_PARAMETERS_END();

if (UNEXPECTED(Z_TYPE_P(formdata) == IS_OBJECT && (Z_OBJCE_P(formdata)->ce_flags & ZEND_ACC_ENUM))) {
zend_argument_type_error(1, "must be of type array, %s given", zend_zval_value_name(formdata));
RETURN_THROWS();
}

php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, /* key_prefix */ NULL, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type);

RETURN_STR(smart_str_extract(&formstr));
Expand Down
36 changes: 36 additions & 0 deletions ext/standard/tests/http/gh15650.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
GH-15650: http_build_query() with enum
--FILE--
<?php

enum E1: string {
case C = 'hello world!';
}

enum E2: int {
case C = 42;
}

enum E3 {
case C;
}

echo http_build_query(['e1' => E1::C, 'e2' => E2::C]), "\n";

try {
echo http_build_query(['e3' => E3::C]);
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}

try {
echo http_build_query(E1::C);
} catch (Throwable $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}

?>
--EXPECT--
e1=hello+world%21&e2=42
ValueError: Unbacked enum E3 cannot be converted to a string
TypeError: http_build_query(): Argument #1 ($data) must be of type array, E1 given

0 comments on commit 1b9568d

Please sign in to comment.