@@ -62,7 +62,7 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
62
62
encoded_data = php_url_encode (Z_STRVAL_P (scalar ), Z_STRLEN_P (scalar ));
63
63
}
64
64
smart_str_append (form_str , encoded_data );
65
- zend_string_free (encoded_data );
65
+ zend_string_release_ex (encoded_data , false );
66
66
break ;
67
67
}
68
68
case IS_LONG :
@@ -77,8 +77,8 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
77
77
encoded_data = php_url_encode (ZSTR_VAL (tmp ), ZSTR_LEN (tmp ));
78
78
}
79
79
smart_str_append (form_str , encoded_data );
80
- zend_string_free (tmp );
81
- zend_string_free (encoded_data );
80
+ zend_string_release_ex (tmp , false );
81
+ zend_string_release_ex (encoded_data , false );
82
82
break ;
83
83
}
84
84
case IS_FALSE :
@@ -92,11 +92,135 @@ static void php_url_encode_scalar(zval *scalar, smart_str *form_str,
92
92
}
93
93
}
94
94
95
+ static HashTable * php_object_get_visible_properties (/* const */ zend_object * object )
96
+ {
97
+ /* const */ HashTable * properties = object -> handlers -> get_properties (object );
98
+ //HashTable *visible_properties = zend_new_array(zend_hash_num_elements(properties));
99
+ HashTable * visible_properties = zend_array_dup (object -> handlers -> get_properties (object ));
100
+ zend_string * property_name ;
101
+ zval * value ;
102
+
103
+ ZEND_HASH_FOREACH_STR_KEY_VAL (properties , property_name , value ) {
104
+ bool is_dynamic = true;
105
+ if (Z_TYPE_P (value ) == IS_INDIRECT ) {
106
+ value = Z_INDIRECT_P (value );
107
+ if (Z_ISUNDEF_P (value )) {
108
+ continue ;
109
+ }
110
+ is_dynamic = false;
111
+ }
112
+
113
+ if (zend_check_property_access (object , property_name , is_dynamic ) == FAILURE ) {
114
+ /* property not visible in this scope */
115
+ zend_hash_del (visible_properties , property_name );
116
+ continue ;
117
+ }
118
+
119
+ /* handling for private & protected object properties */
120
+ if (UNEXPECTED (ZSTR_VAL (property_name )[0 ] == '\0' )) {
121
+ zend_hash_del (visible_properties , property_name );
122
+ const char * tmp ;
123
+ const char * unmangled_name ;
124
+ size_t unmangled_name_len ;
125
+ zend_unmangle_property_name_ex (property_name , & tmp , & unmangled_name , & unmangled_name_len );
126
+ zend_hash_str_add (visible_properties , unmangled_name , unmangled_name_len , value );
127
+ }
128
+ } ZEND_HASH_FOREACH_END ();
129
+ return visible_properties ;
130
+ }
131
+
132
+ static zend_string * php_url_encode_get_new_prefix (
133
+ int encoding_type , zend_ulong index_int ,
134
+ const char * index_string , size_t index_string_len ,
135
+ const char * num_prefix , size_t num_prefix_len ,
136
+ const zend_string * key_prefix
137
+ ) {
138
+ zend_string * new_prefix ;
139
+
140
+ if (index_string ) {
141
+ zend_string * encoded_key ;
142
+ if (encoding_type == PHP_QUERY_RFC3986 ) {
143
+ encoded_key = php_raw_url_encode (index_string , index_string_len );
144
+ } else {
145
+ encoded_key = php_url_encode (index_string , index_string_len );
146
+ }
147
+
148
+ if (key_prefix ) {
149
+ new_prefix = zend_string_concat3 (ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ), ZSTR_VAL (encoded_key ), ZSTR_LEN (encoded_key ), "%5D%5B" , strlen ("%5D%5B" ));
150
+ } else {
151
+ new_prefix = zend_string_concat2 (ZSTR_VAL (encoded_key ), ZSTR_LEN (encoded_key ), "%5B" , strlen ("%5B" ));
152
+ }
153
+ zend_string_release_ex (encoded_key , false);
154
+ } else { /* is integer index */
155
+ char * index_int_as_str ;
156
+ size_t index_int_as_str_len ;
157
+
158
+ index_int_as_str_len = spprintf (& index_int_as_str , 0 , ZEND_LONG_FMT , index_int );
159
+
160
+ if (key_prefix && num_prefix ) {
161
+ /* zend_string_concat4() */
162
+ size_t len = ZSTR_LEN (key_prefix ) + num_prefix_len + index_int_as_str_len + strlen ("%5D%5B" );
163
+ new_prefix = zend_string_alloc (len , 0 );
164
+
165
+ memcpy (ZSTR_VAL (new_prefix ), ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ));
166
+ memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ), num_prefix , num_prefix_len );
167
+ memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ) + num_prefix_len , index_int_as_str , index_int_as_str_len );
168
+ memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ) + num_prefix_len + index_int_as_str_len , "%5D%5B" , strlen ("%5D%5B" ));
169
+ ZSTR_VAL (new_prefix )[len ] = '\0' ;
170
+ } else if (key_prefix ) {
171
+ new_prefix = zend_string_concat3 (ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ), index_int_as_str , index_int_as_str_len , "%5D%5B" , strlen ("%5D%5B" ));
172
+ } else if (num_prefix ) {
173
+ new_prefix = zend_string_concat3 (num_prefix , num_prefix_len , index_int_as_str , index_int_as_str_len , "%5B" , strlen ("%5B" ));
174
+ } else {
175
+ new_prefix = zend_string_concat2 (index_int_as_str , index_int_as_str_len , "%5B" , strlen ("%5B" ));
176
+ }
177
+ efree (index_int_as_str );
178
+ }
179
+
180
+ return new_prefix ;
181
+ }
182
+
183
+ static void php_url_encode_object (zend_object * object , smart_str * form_str ,
184
+ int encoding_type , zend_ulong index_int ,
185
+ const char * index_string , size_t index_string_len ,
186
+ const char * num_prefix , size_t num_prefix_len ,
187
+ const zend_string * key_prefix ,
188
+ const zend_string * arg_sep )
189
+ {
190
+ if (GC_IS_RECURSIVE (object )) {
191
+ /* Prevent recursion */
192
+ return ;
193
+ }
194
+
195
+ HashTable * properties = php_object_get_visible_properties (object );
196
+ if (zend_hash_num_elements (properties ) == 0 ) {
197
+ zend_array_destroy (properties );
198
+
199
+ zval tmp ;
200
+ /* If the data object is stringable without visible properties handle it like a string instead of empty array */
201
+ if (object -> handlers -> cast_object (object , & tmp , IS_STRING ) == SUCCESS ) {
202
+ php_url_encode_scalar (& tmp , form_str ,
203
+ encoding_type , index_int ,
204
+ index_string , index_string_len ,
205
+ num_prefix , num_prefix_len ,
206
+ NULL ,
207
+ arg_sep );
208
+ zval_ptr_dtor (& tmp );
209
+ }
210
+ return ;
211
+ }
212
+
213
+ GC_TRY_PROTECT_RECURSION (object );
214
+ php_url_encode_hash_ex (properties , form_str , num_prefix , num_prefix_len , key_prefix , NULL , arg_sep , encoding_type );
215
+ GC_TRY_UNPROTECT_RECURSION (object );
216
+ zend_array_destroy (properties );
217
+ }
218
+
95
219
/* {{{ php_url_encode_hash */
96
220
PHPAPI void php_url_encode_hash_ex (HashTable * ht , smart_str * formstr ,
97
221
const char * num_prefix , size_t num_prefix_len ,
98
222
const zend_string * key_prefix ,
99
- zval * type , const zend_string * arg_sep , int enc_type )
223
+ ZEND_ATTRIBUTE_UNUSED zval * type , const zend_string * arg_sep , int enc_type )
100
224
{
101
225
zend_string * key = NULL ;
102
226
const char * prop_name ;
@@ -118,84 +242,32 @@ PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
118
242
}
119
243
120
244
ZEND_HASH_FOREACH_KEY_VAL (ht , idx , key , zdata ) {
121
- bool is_dynamic = 1 ;
122
- if (Z_TYPE_P (zdata ) == IS_INDIRECT ) {
123
- zdata = Z_INDIRECT_P (zdata );
124
- if (Z_ISUNDEF_P (zdata )) {
125
- continue ;
126
- }
127
-
128
- is_dynamic = 0 ;
129
- }
130
-
131
- /* handling for private & protected object properties */
132
245
if (key ) {
133
246
prop_name = ZSTR_VAL (key );
134
247
prop_len = ZSTR_LEN (key );
135
-
136
- if (type != NULL && zend_check_property_access (Z_OBJ_P (type ), key , is_dynamic ) != SUCCESS ) {
137
- /* property not visible in this scope */
138
- continue ;
139
- }
140
-
141
- if (ZSTR_VAL (key )[0 ] == '\0' && type != NULL ) {
142
- const char * tmp ;
143
- zend_unmangle_property_name_ex (key , & tmp , & prop_name , & prop_len );
144
- } else {
145
- prop_name = ZSTR_VAL (key );
146
- prop_len = ZSTR_LEN (key );
147
- }
148
248
} else {
149
249
prop_name = NULL ;
150
250
prop_len = 0 ;
151
251
}
152
252
153
253
ZVAL_DEREF (zdata );
154
- if (Z_TYPE_P (zdata ) == IS_ARRAY || Z_TYPE_P (zdata ) == IS_OBJECT ) {
155
- zend_string * new_prefix ;
156
- if (key ) {
157
- zend_string * encoded_key ;
158
- if (enc_type == PHP_QUERY_RFC3986 ) {
159
- encoded_key = php_raw_url_encode (prop_name , prop_len );
160
- } else {
161
- encoded_key = php_url_encode (prop_name , prop_len );
162
- }
163
-
164
- if (key_prefix ) {
165
- new_prefix = zend_string_concat3 (ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ), ZSTR_VAL (encoded_key ), ZSTR_LEN (encoded_key ), "%5D%5B" , strlen ("%5D%5B" ));
166
- } else {
167
- new_prefix = zend_string_concat2 (ZSTR_VAL (encoded_key ), ZSTR_LEN (encoded_key ), "%5B" , strlen ("%5B" ));
168
- }
169
- zend_string_release_ex (encoded_key , false);
170
- } else { /* is integer index */
171
- char * index_int_as_str ;
172
- size_t index_int_as_str_len ;
173
-
174
- index_int_as_str_len = spprintf (& index_int_as_str , 0 , ZEND_LONG_FMT , idx );
175
-
176
- if (key_prefix && num_prefix ) {
177
- /* zend_string_concat4() */
178
- size_t len = ZSTR_LEN (key_prefix ) + num_prefix_len + index_int_as_str_len + strlen ("%5D%5B" );
179
- new_prefix = zend_string_alloc (len , 0 );
180
-
181
- memcpy (ZSTR_VAL (new_prefix ), ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ));
182
- memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ), num_prefix , num_prefix_len );
183
- memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ) + num_prefix_len , index_int_as_str , index_int_as_str_len );
184
- memcpy (ZSTR_VAL (new_prefix ) + ZSTR_LEN (key_prefix ) + num_prefix_len + index_int_as_str_len , "%5D%5B" , strlen ("%5D%5B" ));
185
- ZSTR_VAL (new_prefix )[len ] = '\0' ;
186
- } else if (key_prefix ) {
187
- new_prefix = zend_string_concat3 (ZSTR_VAL (key_prefix ), ZSTR_LEN (key_prefix ), index_int_as_str , index_int_as_str_len , "%5D%5B" , strlen ("%5D%5B" ));
188
- } else if (num_prefix ) {
189
- new_prefix = zend_string_concat3 (num_prefix , num_prefix_len , index_int_as_str , index_int_as_str_len , "%5B" , strlen ("%5B" ));
190
- } else {
191
- new_prefix = zend_string_concat2 (index_int_as_str , index_int_as_str_len , "%5B" , strlen ("%5B" ));
192
- }
193
- efree (index_int_as_str );
194
- }
254
+ if (Z_TYPE_P (zdata ) == IS_ARRAY ) {
255
+ zend_string * new_prefix = php_url_encode_get_new_prefix (enc_type , idx , prop_name , prop_len ,
256
+ num_prefix , num_prefix_len , key_prefix );
195
257
GC_TRY_PROTECT_RECURSION (ht );
196
- php_url_encode_hash_ex (HASH_OF (zdata ), formstr , NULL , 0 , new_prefix , ( Z_TYPE_P ( zdata ) == IS_OBJECT ? zdata : NULL ) , arg_sep , enc_type );
258
+ php_url_encode_hash_ex (Z_ARRVAL_P (zdata ), formstr , NULL , 0 , new_prefix , NULL , arg_sep , enc_type );
197
259
GC_TRY_UNPROTECT_RECURSION (ht );
198
260
zend_string_release_ex (new_prefix , false);
261
+ } else if (Z_TYPE_P (zdata ) == IS_OBJECT ) {
262
+ zend_string * new_prefix = php_url_encode_get_new_prefix (enc_type , idx , prop_name , prop_len ,
263
+ num_prefix , num_prefix_len , key_prefix );
264
+ php_url_encode_object (Z_OBJ_P (zdata ), formstr ,
265
+ enc_type , idx ,
266
+ prop_name , prop_len ,
267
+ num_prefix , num_prefix_len ,
268
+ new_prefix ,
269
+ arg_sep );
270
+ zend_string_release_ex (new_prefix , false);
199
271
} else if (Z_TYPE_P (zdata ) == IS_NULL || Z_TYPE_P (zdata ) == IS_RESOURCE ) {
200
272
/* Skip these types */
201
273
continue ;
@@ -230,7 +302,16 @@ PHP_FUNCTION(http_build_query)
230
302
Z_PARAM_LONG (enc_type )
231
303
ZEND_PARSE_PARAMETERS_END ();
232
304
233
- 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 );
305
+ if (Z_TYPE_P (formdata ) == IS_OBJECT ) {
306
+ php_url_encode_object (Z_OBJ_P (formdata ), & formstr ,
307
+ (int ) enc_type , /* int_index */ 0 ,
308
+ /* string_index */ NULL , 0 ,
309
+ prefix , prefix_len ,
310
+ NULL ,
311
+ arg_sep );
312
+ } else {
313
+ php_url_encode_hash_ex (Z_ARRVAL_P (formdata ), & formstr , prefix , prefix_len , /* key_prefix */ NULL , NULL , arg_sep , (int )enc_type );
314
+ }
234
315
235
316
RETURN_STR (smart_str_extract (& formstr ));
236
317
}
0 commit comments