@@ -95,6 +95,61 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
95
95
}
96
96
}
97
97
98
+ enum property_status {
99
+ PROPERTY_STATUS_UNDEF ,
100
+ PROPERTY_STATUS_DYNAMIC ,
101
+ PROPERTY_STATUS_NOT_DYNAMIC ,
102
+ };
103
+
104
+ static zend_always_inline zval * compute_is_undef_or_dynamic_property (zval * zdata , enum property_status * status ) {
105
+ if (Z_TYPE_P (zdata ) == IS_INDIRECT ) {
106
+ zdata = Z_INDIRECT_P (zdata );
107
+ if (Z_ISUNDEF_P (zdata )) {
108
+ * status = PROPERTY_STATUS_UNDEF ;
109
+ }
110
+
111
+ * status = PROPERTY_STATUS_NOT_DYNAMIC ;
112
+ } else {
113
+ * status = PROPERTY_STATUS_DYNAMIC ;
114
+ }
115
+
116
+ return zdata ;
117
+ }
118
+
119
+ static bool has_public_properties (HashTable * ht , zval * type ) {
120
+ zend_string * key = NULL ;
121
+ zend_ulong _unused_idx ;
122
+ zval * zdata = NULL ;
123
+ ZEND_ASSERT (ht );
124
+ ZEND_ASSERT (type );
125
+
126
+ ZEND_HASH_FOREACH_KEY_VAL (ht , _unused_idx , key , zdata ) {
127
+ enum property_status status ;
128
+ zdata = compute_is_undef_or_dynamic_property (zdata , & status );
129
+ if (status == PROPERTY_STATUS_UNDEF ) {
130
+ continue ;
131
+ }
132
+ bool is_dynamic = status == PROPERTY_STATUS_DYNAMIC ;
133
+
134
+ if (zend_check_property_access (Z_OBJ_P (type ), key , is_dynamic ) == SUCCESS ) {
135
+ /* property visible in this scope */
136
+ return true;
137
+ }
138
+ } ZEND_HASH_FOREACH_END ();
139
+
140
+ return false;
141
+ }
142
+
143
+ static bool should_handle_object_as_stringable (zval * zdata , zval * tmp ) {
144
+ /* If the data object is stringable and has no properties handle it like a string instead of recursively */
145
+ if (Z_TYPE_P (zdata ) == IS_OBJECT &&
146
+ !has_public_properties (HASH_OF (zdata ), zdata ) &&
147
+ Z_OBJ_HT_P (zdata )-> cast_object (Z_OBJ_P (zdata ), tmp , IS_STRING ) == SUCCESS ) {
148
+ return true;
149
+ }
150
+ return false;
151
+ }
152
+
98
153
/* {{{ php_url_encode_hash */
99
154
PHPAPI void php_url_encode_hash_ex (HashTable * ht , smart_str * formstr ,
100
155
const char * num_prefix , size_t num_prefix_len ,
@@ -124,21 +179,15 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
124
179
arg_sep_len = strlen (arg_sep );
125
180
126
181
ZEND_HASH_FOREACH_KEY_VAL (ht , idx , key , zdata ) {
127
- bool is_dynamic = 1 ;
128
- if (Z_TYPE_P (zdata ) == IS_INDIRECT ) {
129
- zdata = Z_INDIRECT_P (zdata );
130
- if (Z_ISUNDEF_P (zdata )) {
131
- continue ;
132
- }
133
-
134
- is_dynamic = 0 ;
182
+ enum property_status status ;
183
+ zdata = compute_is_undef_or_dynamic_property (zdata , & status );
184
+ if (status == PROPERTY_STATUS_UNDEF ) {
185
+ continue ;
135
186
}
187
+ bool is_dynamic = status == PROPERTY_STATUS_DYNAMIC ;
136
188
137
189
/* handling for private & protected object properties */
138
190
if (key ) {
139
- prop_name = ZSTR_VAL (key );
140
- prop_len = ZSTR_LEN (key );
141
-
142
191
if (type != NULL && zend_check_property_access (Z_OBJ_P (type ), key , is_dynamic ) != SUCCESS ) {
143
192
/* property not visible in this scope */
144
193
continue ;
@@ -158,17 +207,16 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
158
207
159
208
ZVAL_DEREF (zdata );
160
209
if (Z_TYPE_P (zdata ) == IS_ARRAY || Z_TYPE_P (zdata ) == IS_OBJECT ) {
161
- /* If the data object is stringable handle it like a string instead of recursively */
162
210
zval tmp ;
163
- if (Z_TYPE_P (zdata ) == IS_OBJECT &&
164
- Z_OBJ_HT_P (zdata )-> cast_object (Z_OBJ_P (zdata ), & tmp , IS_STRING ) == SUCCESS ) {
211
+ if (should_handle_object_as_stringable (zdata , & tmp )) {
165
212
php_url_encode_scalar (& tmp , formstr ,
166
213
enc_type , idx ,
167
214
prop_name , prop_len ,
168
215
num_prefix , num_prefix_len ,
169
216
key_prefix , key_prefix_len ,
170
217
key_suffix , key_suffix_len ,
171
218
arg_sep , arg_sep_len );
219
+ zval_ptr_dtor (& tmp );
172
220
continue ;
173
221
}
174
222
@@ -269,7 +317,20 @@ PHP_FUNCTION(http_build_query)
269
317
Z_PARAM_LONG (enc_type )
270
318
ZEND_PARSE_PARAMETERS_END ();
271
319
272
- php_url_encode_hash_ex (HASH_OF (formdata ), & formstr , prefix , prefix_len , NULL , 0 , NULL , 0 , (Z_TYPE_P (formdata ) == IS_OBJECT ? formdata : NULL), arg_sep , (int )enc_type );
320
+ /* Special case when we get an object that's stringable as input */
321
+ zval tmp ;
322
+ if (should_handle_object_as_stringable (formdata , & tmp )) {
323
+ php_url_encode_scalar (& tmp , & formstr ,
324
+ enc_type , 0 ,
325
+ NULL , 0 ,
326
+ prefix , prefix_len ,
327
+ NULL , 0 ,
328
+ NULL , 0 ,
329
+ arg_sep , arg_sep_len );
330
+ zval_ptr_dtor (& tmp );
331
+ } else {
332
+ php_url_encode_hash_ex (HASH_OF (formdata ), & formstr , prefix , prefix_len , NULL , 0 , NULL , 0 , (Z_TYPE_P (formdata ) == IS_OBJECT ? formdata : NULL ), arg_sep , (int )enc_type );
333
+ }
273
334
274
335
if (!formstr .s ) {
275
336
RETURN_EMPTY_STRING ();
0 commit comments