1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP license, | |
8 | | that is bundled with this package in the file LICENSE, and is | |
9 | | available through the world-wide-web at the following url: | |
10 | | http://www.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Authors: Sara Golemon <pollita@php.net> | |
16 | +----------------------------------------------------------------------+ |
17 | */ |
18 | |
19 | /* $Id$ */ |
20 | |
21 | #include "php_http.h" |
22 | #include "php_ini.h" |
23 | #include "url.h" |
24 | |
25 | #define URL_DEFAULT_ARG_SEP "&" |
26 | |
27 | /* {{{ php_url_encode_hash */ |
28 | PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, |
29 | const char *num_prefix, int num_prefix_len, |
30 | const char *key_prefix, int key_prefix_len, |
31 | const char *key_suffix, int key_suffix_len, |
32 | zval *type, char *arg_sep, int enc_type TSRMLS_DC) |
33 | { |
34 | char *key = NULL; |
35 | char *ekey, *newprefix, *p; |
36 | int arg_sep_len, ekey_len, key_type, newprefix_len; |
37 | uint key_len; |
38 | ulong idx; |
39 | zval **zdata = NULL, *copyzval; |
40 | |
41 | if (!ht) { |
42 | return FAILURE; |
43 | } |
44 | |
45 | if (ht->nApplyCount > 0) { |
46 | /* Prevent recursion */ |
47 | return SUCCESS; |
48 | } |
49 | |
50 | if (!arg_sep) { |
51 | arg_sep = INI_STR("arg_separator.output" ); |
52 | if (!arg_sep || !strlen(arg_sep)) { |
53 | arg_sep = URL_DEFAULT_ARG_SEP; |
54 | } |
55 | } |
56 | arg_sep_len = strlen(arg_sep); |
57 | |
58 | for (zend_hash_internal_pointer_reset(ht); |
59 | (key_type = zend_hash_get_current_key_ex(ht, &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTENT; |
60 | zend_hash_move_forward(ht) |
61 | ) { |
62 | if (key_type == HASH_KEY_IS_STRING && key_len && key[key_len-1] == '\0') { |
63 | /* We don't want that trailing NULL */ |
64 | key_len -= 1; |
65 | } |
66 | |
67 | /* handling for private & protected object properties */ |
68 | if (key && *key == '\0' && type != NULL) { |
69 | const char *tmp; |
70 | |
71 | zend_object *zobj = zend_objects_get_address(type TSRMLS_CC); |
72 | if (zend_check_property_access(zobj, key, key_len TSRMLS_CC) != SUCCESS) { |
73 | /* private or protected property access outside of the class */ |
74 | continue; |
75 | } |
76 | zend_unmangle_property_name_ex(key, key_len, &tmp, (const char**)&key, &key_len); |
77 | } |
78 | |
79 | if (zend_hash_get_current_data_ex(ht, (void **)&zdata, NULL) == FAILURE || !zdata || !(*zdata)) { |
80 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error traversing form data array" ); |
81 | return FAILURE; |
82 | } |
83 | if (Z_TYPE_PP(zdata) == IS_ARRAY || Z_TYPE_PP(zdata) == IS_OBJECT) { |
84 | if (key_type == HASH_KEY_IS_STRING) { |
85 | if (enc_type == PHP_QUERY_RFC3986) { |
86 | ekey = php_raw_url_encode(key, key_len, &ekey_len); |
87 | } else { |
88 | ekey = php_url_encode(key, key_len, &ekey_len); |
89 | } |
90 | newprefix_len = key_suffix_len + ekey_len + key_prefix_len + 3 /* %5B */; |
91 | newprefix = emalloc(newprefix_len + 1); |
92 | p = newprefix; |
93 | |
94 | if (key_prefix) { |
95 | memcpy(p, key_prefix, key_prefix_len); |
96 | p += key_prefix_len; |
97 | } |
98 | |
99 | memcpy(p, ekey, ekey_len); |
100 | p += ekey_len; |
101 | efree(ekey); |
102 | |
103 | if (key_suffix) { |
104 | memcpy(p, key_suffix, key_suffix_len); |
105 | p += key_suffix_len; |
106 | } |
107 | *(p++) = '%'; |
108 | *(p++) = '5'; |
109 | *(p++) = 'B'; |
110 | *p = '\0'; |
111 | } else { |
112 | /* Is an integer key */ |
113 | ekey_len = spprintf(&ekey, 0, "%ld" , idx); |
114 | newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 3 /* %5B */; |
115 | newprefix = emalloc(newprefix_len + 1); |
116 | p = newprefix; |
117 | |
118 | if (key_prefix) { |
119 | memcpy(p, key_prefix, key_prefix_len); |
120 | p += key_prefix_len; |
121 | } |
122 | |
123 | memcpy(p, num_prefix, num_prefix_len); |
124 | p += num_prefix_len; |
125 | |
126 | memcpy(p, ekey, ekey_len); |
127 | p += ekey_len; |
128 | efree(ekey); |
129 | |
130 | if (key_suffix) { |
131 | memcpy(p, key_suffix, key_suffix_len); |
132 | p += key_suffix_len; |
133 | } |
134 | *(p++) = '%'; |
135 | *(p++) = '5'; |
136 | *(p++) = 'B'; |
137 | *p = '\0'; |
138 | } |
139 | ht->nApplyCount++; |
140 | php_url_encode_hash_ex(HASH_OF(*zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D" , 3, (Z_TYPE_PP(zdata) == IS_OBJECT ? *zdata : NULL), arg_sep, enc_type TSRMLS_CC); |
141 | ht->nApplyCount--; |
142 | efree(newprefix); |
143 | } else if (Z_TYPE_PP(zdata) == IS_NULL || Z_TYPE_PP(zdata) == IS_RESOURCE) { |
144 | /* Skip these types */ |
145 | continue; |
146 | } else { |
147 | if (formstr->len) { |
148 | smart_str_appendl(formstr, arg_sep, arg_sep_len); |
149 | } |
150 | /* Simple key=value */ |
151 | smart_str_appendl(formstr, key_prefix, key_prefix_len); |
152 | if (key_type == HASH_KEY_IS_STRING) { |
153 | if (enc_type == PHP_QUERY_RFC3986) { |
154 | ekey = php_raw_url_encode(key, key_len, &ekey_len); |
155 | } else { |
156 | ekey = php_url_encode(key, key_len, &ekey_len); |
157 | } |
158 | smart_str_appendl(formstr, ekey, ekey_len); |
159 | efree(ekey); |
160 | } else { |
161 | /* Numeric key */ |
162 | if (num_prefix) { |
163 | smart_str_appendl(formstr, num_prefix, num_prefix_len); |
164 | } |
165 | ekey_len = spprintf(&ekey, 0, "%ld" , idx); |
166 | smart_str_appendl(formstr, ekey, ekey_len); |
167 | efree(ekey); |
168 | } |
169 | smart_str_appendl(formstr, key_suffix, key_suffix_len); |
170 | smart_str_appendl(formstr, "=" , 1); |
171 | switch (Z_TYPE_PP(zdata)) { |
172 | case IS_STRING: |
173 | if (enc_type == PHP_QUERY_RFC3986) { |
174 | ekey = php_raw_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len); |
175 | } else { |
176 | ekey = php_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len); |
177 | } |
178 | break; |
179 | case IS_LONG: |
180 | case IS_BOOL: |
181 | ekey_len = spprintf(&ekey, 0, "%ld" , Z_LVAL_PP(zdata)); |
182 | break; |
183 | case IS_DOUBLE: |
184 | ekey_len = spprintf(&ekey, 0, "%.*G" , (int) EG(precision), Z_DVAL_PP(zdata)); |
185 | break; |
186 | default: |
187 | /* fall back on convert to string */ |
188 | MAKE_STD_ZVAL(copyzval); |
189 | *copyzval = **zdata; |
190 | zval_copy_ctor(copyzval); |
191 | convert_to_string_ex(©zval); |
192 | if (enc_type == PHP_QUERY_RFC3986) { |
193 | ekey = php_raw_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len); |
194 | } else { |
195 | ekey = php_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len); |
196 | } |
197 | zval_ptr_dtor(©zval); |
198 | } |
199 | smart_str_appendl(formstr, ekey, ekey_len); |
200 | efree(ekey); |
201 | } |
202 | } |
203 | |
204 | return SUCCESS; |
205 | } |
206 | /* }}} */ |
207 | |
208 | /* {{{ proto string http_build_query(mixed formdata [, string prefix [, string arg_separator [, int enc_type]]]) |
209 | Generates a form-encoded query string from an associative array or object. */ |
210 | PHP_FUNCTION(http_build_query) |
211 | { |
212 | zval *formdata; |
213 | char *prefix = NULL, *arg_sep=NULL; |
214 | int arg_sep_len = 0, prefix_len = 0; |
215 | smart_str formstr = {0}; |
216 | long enc_type = PHP_QUERY_RFC1738; |
217 | |
218 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ssl" , &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len, &enc_type) != SUCCESS) { |
219 | RETURN_FALSE; |
220 | } |
221 | |
222 | if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) { |
223 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter 1 expected to be Array or Object. Incorrect value given" ); |
224 | RETURN_FALSE; |
225 | } |
226 | |
227 | if (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, enc_type TSRMLS_CC) == FAILURE) { |
228 | if (formstr.c) { |
229 | efree(formstr.c); |
230 | } |
231 | RETURN_FALSE; |
232 | } |
233 | |
234 | if (!formstr.c) { |
235 | RETURN_EMPTY_STRING(); |
236 | } |
237 | |
238 | smart_str_0(&formstr); |
239 | |
240 | RETURN_STRINGL(formstr.c, formstr.len, 0); |
241 | } |
242 | /* }}} */ |
243 | |
244 | /* |
245 | * Local variables: |
246 | * tab-width: 4 |
247 | * c-basic-offset: 4 |
248 | * End: |
249 | * vim600: sw=4 ts=4 fdm=marker |
250 | * vim<600: sw=4 ts=4 |
251 | */ |
252 | |
253 | |