2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 static php_http_params_token_t def_param_sep
= {",", 1}, *def_param_sep_ptr
[] = {&def_param_sep
, NULL
};
16 static php_http_params_token_t def_arg_sep
= {";", 1}, *def_arg_sep_ptr
[] = {&def_arg_sep
, NULL
};
17 static php_http_params_token_t def_val_sep
= {"=", 1}, *def_val_sep_ptr
[] = {&def_val_sep
, NULL
};
18 static php_http_params_opts_t def_opts
= {
24 PHP_HTTP_PARAMS_DEFAULT
27 PHP_HTTP_API php_http_params_opts_t
*php_http_params_opts_default_get(php_http_params_opts_t
*opts
)
30 opts
= emalloc(sizeof(*opts
));
33 memcpy(opts
, &def_opts
, sizeof(def_opts
));
38 typedef struct php_http_params_state
{
39 php_http_params_token_t input
;
40 php_http_params_token_t param
;
41 php_http_params_token_t arg
;
42 php_http_params_token_t val
;
48 } php_http_params_state_t
;
50 static inline void sanitize_default(zval
*zv TSRMLS_DC
)
52 if (Z_STRVAL_P(zv
)[0] == '"' && Z_STRVAL_P(zv
)[Z_STRLEN_P(zv
) - 1] == '"') {
53 size_t deq_len
= Z_STRLEN_P(zv
) - 2;
54 char *deq
= estrndup(Z_STRVAL_P(zv
) + 1, deq_len
);
57 ZVAL_STRINGL(zv
, deq
, deq_len
, 0);
60 php_stripslashes(Z_STRVAL_P(zv
), &Z_STRLEN_P(zv
) TSRMLS_CC
);
63 static inline void prepare_default(zval
*zv TSRMLS_DC
)
65 if (Z_TYPE_P(zv
) == IS_STRING
) {
66 int len
= Z_STRLEN_P(zv
);
68 Z_STRVAL_P(zv
) = php_addslashes(Z_STRVAL_P(zv
), Z_STRLEN_P(zv
), &Z_STRLEN_P(zv
), 1 TSRMLS_CC
);
70 if (len
!= Z_STRLEN_P(zv
)) {
72 int len
= Z_STRLEN_P(zv
) + 2;
73 char *str
= emalloc(len
+ 1);
76 memcpy(&str
[1], Z_STRVAL_P(zv
), Z_STRLEN_P(zv
));
81 ZVAL_STRINGL(zv
, str
, len
, 0);
85 ZVAL_EMPTY_STRING(zv
);
89 static inline void sanitize_urlencoded(zval
*zv TSRMLS_DC
)
91 Z_STRLEN_P(zv
) = php_raw_url_decode(Z_STRVAL_P(zv
), Z_STRLEN_P(zv
));
94 static inline void prepare_urlencoded(zval
*zv TSRMLS_DC
)
97 char *str
= php_url_encode(Z_STRVAL_P(zv
), Z_STRLEN_P(zv
), &len
);
100 ZVAL_STRINGL(zv
, str
, len
, 0);
103 static void sanitize_dimension(zval
*zv TSRMLS_DC
)
105 zval
*arr
= NULL
, *tmp
= NULL
, **cur
= NULL
;
106 char *var
= NULL
, *ptr
= Z_STRVAL_P(zv
), *end
= Z_STRVAL_P(zv
) + Z_STRLEN_P(zv
);
120 if (++level
> PG(max_input_nesting_level
)) {
122 php_http_error(HE_WARNING
, PHP_HTTP_E_QUERYSTRING
, "Max input nesting level of %ld exceeded", PG(max_input_nesting_level
));
125 if (ptr
- var
== 0) {
135 convert_to_array(*cur
);
140 zend_symtable_update(Z_ARRVAL_PP(cur
), var
, ptr
- var
+ 1, (void *) &tmp
, sizeof(zval
*), (void *) &cur
);
143 zend_hash_next_index_insert(Z_ARRVAL_PP(cur
), (void *) &tmp
, sizeof(zval
*), (void *) &cur
);
153 if (zend_hash_num_elements(Z_ARRVAL_P(arr
))) {
155 #if PHP_VERSION_ID >= 50400
156 ZVAL_COPY_VALUE(zv
, arr
);
158 zv
->value
= arr
->value
;
159 Z_TYPE_P(zv
) = Z_TYPE_P(arr
);
167 static inline void shift_key(php_http_buffer_t
*buf
, char *key_str
, size_t key_len
, const char *ass
, size_t asl
, unsigned flags TSRMLS_DC
);
168 static inline void shift_val(php_http_buffer_t
*buf
, zval
*zvalue
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
);
170 static void prepare_dimension(php_http_buffer_t
*buf
, php_http_buffer_t
*keybuf
, zval
*zvalue
, const char *pss
, size_t psl
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
)
172 HashTable
*ht
= HASH_OF(zvalue
);
174 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
176 php_http_buffer_t prefix
;
178 if (!ht
->nApplyCount
++) {
179 php_http_buffer_init(&prefix
);
180 php_http_buffer_append(&prefix
, keybuf
->data
, keybuf
->used
);
182 FOREACH_HASH_KEYVAL(pos
, ht
, key
, val
) {
183 if (key
.type
== HASH_KEY_IS_STRING
&& !*key
.str
) {
184 /* only public properties */
188 php_http_buffer_appends(&prefix
, "[");
189 if (key
.type
== HASH_KEY_IS_STRING
) {
190 php_http_buffer_append(&prefix
, key
.str
, key
.len
- 1);
192 php_http_buffer_appendf(&prefix
, "%lu", key
.num
);
194 php_http_buffer_appends(&prefix
, "]");
196 if (Z_TYPE_PP(val
) == IS_ARRAY
|| Z_TYPE_PP(val
) == IS_OBJECT
) {
197 prepare_dimension(buf
, &prefix
, *val
, pss
, psl
, vss
, vsl
, flags TSRMLS_CC
);
199 zval
*cpy
= php_http_ztyp(IS_STRING
, *val
);
201 shift_key(buf
, prefix
.data
, prefix
.used
, pss
, psl
, flags TSRMLS_CC
);
202 shift_val(buf
, cpy
, vss
, vsl
, flags TSRMLS_CC
);
206 php_http_buffer_cut(&prefix
, keybuf
->used
, prefix
.used
- keybuf
->used
);
208 php_http_buffer_dtor(&prefix
);
213 static inline void sanitize_key(unsigned flags
, char *str
, size_t len
, zval
*zv TSRMLS_DC
)
216 php_trim(str
, len
, NULL
, 0, zv
, 3 TSRMLS_CC
);
218 if (flags
& PHP_HTTP_PARAMS_DEFAULT
) {
219 sanitize_default(zv TSRMLS_CC
);
222 if (flags
& PHP_HTTP_PARAMS_URLENCODED
) {
223 sanitize_urlencoded(zv TSRMLS_CC
);
226 if (flags
& PHP_HTTP_PARAMS_DIMENSION
) {
227 sanitize_dimension(zv TSRMLS_CC
);
231 static inline void sanitize_value(unsigned flags
, char *str
, size_t len
, zval
*zv TSRMLS_DC
)
234 php_trim(str
, len
, NULL
, 0, zv
, 3 TSRMLS_CC
);
236 if (flags
& PHP_HTTP_PARAMS_DEFAULT
) {
237 sanitize_default(zv TSRMLS_CC
);
240 if (flags
& PHP_HTTP_PARAMS_URLENCODED
) {
241 sanitize_urlencoded(zv TSRMLS_CC
);
245 static inline void prepare_key(unsigned flags
, char *old_key
, size_t old_len
, char **new_key
, size_t *new_len TSRMLS_DC
)
250 ZVAL_STRINGL(&zv
, old_key
, old_len
, 1);
252 if (flags
& PHP_HTTP_PARAMS_URLENCODED
) {
253 prepare_urlencoded(&zv TSRMLS_CC
);
256 if (flags
& PHP_HTTP_PARAMS_DEFAULT
) {
257 prepare_default(&zv TSRMLS_CC
);
260 *new_key
= Z_STRVAL(zv
);
261 *new_len
= Z_STRLEN(zv
);
264 static inline void prepare_value(unsigned flags
, zval
*zv TSRMLS_DC
)
266 if (flags
& PHP_HTTP_PARAMS_URLENCODED
) {
267 prepare_urlencoded(zv TSRMLS_CC
);
270 if (flags
& PHP_HTTP_PARAMS_DEFAULT
) {
271 prepare_default(zv TSRMLS_CC
);
275 static void merge_param(HashTable
*params
, zval
*zdata
, zval
***current_param
, zval
***current_args TSRMLS_DC
)
277 zval
**ptr
, **zdata_ptr
;
278 php_http_array_hashkey_t hkey
= php_http_array_hashkey_init(0);
283 INIT_PZVAL_ARRAY(&tmp
, params
);
284 fprintf(stderr
, "params = ");
285 zend_print_zval_r(&tmp
, 1 TSRMLS_CC
);
286 fprintf(stderr
, "\n");
290 hkey
.type
= zend_hash_get_current_key_ex(Z_ARRVAL_P(zdata
), &hkey
.str
, &hkey
.len
, &hkey
.num
, hkey
.dup
, NULL
);
292 if ((hkey
.type
== HASH_KEY_IS_STRING
&& !zend_hash_exists(params
, hkey
.str
, hkey
.len
))
293 || (hkey
.type
== HASH_KEY_IS_LONG
&& !zend_hash_index_exists(params
, hkey
.num
))
295 zval
*tmp
, *arg
, **args
;
297 /* create the entry if it doesn't exist */
298 zend_hash_get_current_data(Z_ARRVAL_P(zdata
), (void *) &ptr
);
302 add_assoc_zval_ex(tmp
, ZEND_STRS("value"), *ptr
);
306 zend_hash_update(Z_ARRVAL_P(tmp
), "arguments", sizeof("arguments"), (void *) &arg
, sizeof(zval
*), (void *) &args
);
307 *current_args
= args
;
309 if (hkey
.type
== HASH_KEY_IS_STRING
) {
310 zend_hash_update(params
, hkey
.str
, hkey
.len
, (void *) &tmp
, sizeof(zval
*), (void *) &ptr
);
312 zend_hash_index_update(params
, hkey
.num
, (void *) &tmp
, sizeof(zval
*), (void *) &ptr
);
316 if (hkey
.type
== HASH_KEY_IS_STRING
) {
317 zend_hash_find(params
, hkey
.str
, hkey
.len
, (void *) &ptr
);
319 zend_hash_index_find(params
, hkey
.num
, (void *) &ptr
);
324 if (Z_TYPE_PP(ptr
) == IS_ARRAY
325 && SUCCESS
== zend_hash_find(Z_ARRVAL_PP(ptr
), "value", sizeof("value"), (void *) &ptr
)
326 && SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr
), (void *) &zdata_ptr
)
329 * params = [arr => [value => [0 => 1]]]
331 * zdata = [arr => [0 => NULL]]
336 while (Z_TYPE_PP(zdata_ptr
) == IS_ARRAY
337 && SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr
), (void *) &test_ptr
)
339 if (Z_TYPE_PP(test_ptr
) == IS_ARRAY
) {
341 /* now find key in ptr */
342 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key_ex(Z_ARRVAL_PP(zdata_ptr
), &hkey
.str
, &hkey
.len
, &hkey
.num
, hkey
.dup
, NULL
)) {
343 if (SUCCESS
== zend_hash_find(Z_ARRVAL_PP(ptr
), hkey
.str
, hkey
.len
, (void *) &ptr
)) {
344 zdata_ptr
= test_ptr
;
346 Z_ADDREF_PP(test_ptr
);
347 zend_hash_update(Z_ARRVAL_PP(ptr
), hkey
.str
, hkey
.len
, (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
351 if (SUCCESS
== zend_hash_index_find(Z_ARRVAL_PP(ptr
), hkey
.num
, (void *) &ptr
)) {
352 zdata_ptr
= test_ptr
;
353 } else if (hkey
.num
) {
354 Z_ADDREF_PP(test_ptr
);
355 zend_hash_index_update(Z_ARRVAL_PP(ptr
), hkey
.num
, (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
358 Z_ADDREF_PP(test_ptr
);
359 zend_hash_next_index_insert(Z_ARRVAL_PP(ptr
), (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
364 /* this is the leaf */
365 Z_ADDREF_PP(test_ptr
);
366 if (Z_TYPE_PP(ptr
) != IS_ARRAY
) {
370 if (HASH_KEY_IS_STRING
== zend_hash_get_current_key_ex(Z_ARRVAL_PP(zdata_ptr
), &hkey
.str
, &hkey
.len
, &hkey
.num
, hkey
.dup
, NULL
)) {
371 zend_hash_update(Z_ARRVAL_PP(ptr
), hkey
.str
, hkey
.len
, (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
372 } else if (hkey
.num
) {
373 zend_hash_index_update(Z_ARRVAL_PP(ptr
), hkey
.num
, (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
375 zend_hash_next_index_insert(Z_ARRVAL_PP(ptr
), (void *) test_ptr
, sizeof(zval
*), (void *) &ptr
);
385 while (Z_TYPE_PP(ptr
) == IS_ARRAY
&& SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_PP(ptr
), (void *) &ptr
));
386 *current_param
= ptr
;
389 static void push_param(HashTable
*params
, php_http_params_state_t
*state
, const php_http_params_opts_t
*opts TSRMLS_DC
)
391 if (state
->val
.str
) {
392 if (0 < (state
->val
.len
= state
->input
.str
- state
->val
.str
)) {
393 sanitize_value(opts
->flags
, state
->val
.str
, state
->val
.len
, *(state
->current
.val
) TSRMLS_CC
);
395 } else if (state
->arg
.str
) {
396 if (0 < (state
->arg
.len
= state
->input
.str
- state
->arg
.str
)) {
401 sanitize_key(opts
->flags
, state
->arg
.str
, state
->arg
.len
, &key TSRMLS_CC
);
402 if (Z_TYPE(key
) == IS_STRING
&& Z_STRLEN(key
)) {
405 zend_symtable_update(Z_ARRVAL_PP(state
->current
.args
), Z_STRVAL(key
), Z_STRLEN(key
) + 1, (void *) &val
, sizeof(zval
*), (void *) &state
->current
.val
);
409 } else if (state
->param
.str
) {
410 if (0 < (state
->param
.len
= state
->input
.str
- state
->param
.str
)) {
411 zval
*prm
, *arg
, *val
, *key
;
415 sanitize_key(opts
->flags
, state
->param
.str
, state
->param
.len
, key TSRMLS_CC
);
416 if (Z_TYPE_P(key
) != IS_STRING
) {
417 merge_param(params
, key
, &state
->current
.val
, &state
->current
.args TSRMLS_CC
);
418 } else if (Z_STRLEN_P(key
)) {
424 #if PHP_VERSION_ID >= 50400
425 ZVAL_COPY_VALUE(val
, opts
->defval
);
427 val
->value
= opts
->defval
->value
;
428 Z_TYPE_P(val
) = Z_TYPE_P(opts
->defval
);
434 zend_hash_update(Z_ARRVAL_P(prm
), "value", sizeof("value"), (void *) &val
, sizeof(zval
*), (void *) &state
->current
.val
);
438 zend_hash_update(Z_ARRVAL_P(prm
), "arguments", sizeof("arguments"), (void *) &arg
, sizeof(zval
*), (void *) &state
->current
.args
);
440 zend_symtable_update(params
, Z_STRVAL_P(key
), Z_STRLEN_P(key
) + 1, (void *) &prm
, sizeof(zval
*), (void *) &state
->current
.param
);
447 static inline zend_bool
check_str(const char *chk_str
, size_t chk_len
, const char *sep_str
, size_t sep_len
) {
448 return 0 < sep_len
&& chk_len
>= sep_len
&& !memcmp(chk_str
, sep_str
, sep_len
);
451 static size_t check_sep(php_http_params_state_t
*state
, php_http_params_token_t
**separators
)
453 php_http_params_token_t
**sep
= separators
;
455 if (sep
) while (*sep
) {
456 if (check_str(state
->input
.str
, state
->input
.len
, (*sep
)->str
, (*sep
)->len
)) {
464 static void skip_sep(size_t skip
, php_http_params_state_t
*state
, php_http_params_token_t
**param
, php_http_params_token_t
**arg
, php_http_params_token_t
**val TSRMLS_DC
)
468 state
->input
.str
+= skip
;
469 state
->input
.len
-= skip
;
471 while ( (param
&& (sep_len
= check_sep(state
, param
)))
472 || (arg
&& (sep_len
= check_sep(state
, arg
)))
473 || (val
&& (sep_len
= check_sep(state
, val
)))
475 state
->input
.str
+= sep_len
;
476 state
->input
.len
-= sep_len
;
480 PHP_HTTP_API HashTable
*php_http_params_parse(HashTable
*params
, const php_http_params_opts_t
*opts TSRMLS_DC
)
482 php_http_params_state_t state
= {{NULL
,0}, {NULL
,0}, {NULL
,0}, {NULL
,0}, {NULL
,NULL
,NULL
}};
484 state
.input
.str
= opts
->input
.str
;
485 state
.input
.len
= opts
->input
.len
;
488 ALLOC_HASHTABLE(params
);
489 ZEND_INIT_SYMTABLE(params
);
492 while (state
.input
.len
) {
493 if (*state
.input
.str
== '\\') {
496 } else if (!state
.param
.str
) {
498 skip_sep(0, &state
, opts
->param
, opts
->arg
, opts
->val TSRMLS_CC
);
499 state
.param
.str
= state
.input
.str
;
502 /* are we at a param separator? */
503 if (0 < (sep_len
= check_sep(&state
, opts
->param
))) {
504 push_param(params
, &state
, opts TSRMLS_CC
);
506 skip_sep(sep_len
, &state
, opts
->param
, opts
->arg
, opts
->val TSRMLS_CC
);
508 /* start off with a new param */
509 state
.param
.str
= state
.input
.str
;
511 state
.arg
.str
= NULL
;
513 state
.val
.str
= NULL
;
519 /* are we at an arg separator? */
520 if (0 < (sep_len
= check_sep(&state
, opts
->arg
))) {
521 push_param(params
, &state
, opts TSRMLS_CC
);
523 skip_sep(sep_len
, &state
, NULL
, opts
->arg
, opts
->val TSRMLS_CC
);
525 /* continue with a new arg */
526 state
.arg
.str
= state
.input
.str
;
528 state
.val
.str
= NULL
;
534 /* are we at a val separator? */
535 if (0 < (sep_len
= check_sep(&state
, opts
->val
))) {
536 /* only handle separator if we're not already reading in a val */
537 if (!state
.val
.str
) {
538 push_param(params
, &state
, opts TSRMLS_CC
);
540 skip_sep(sep_len
, &state
, NULL
, NULL
, opts
->val TSRMLS_CC
);
542 state
.val
.str
= state
.input
.str
;
550 if (state
.input
.len
) {
556 push_param(params
, &state
, opts TSRMLS_CC
);
561 static inline void shift_key(php_http_buffer_t
*buf
, char *key_str
, size_t key_len
, const char *ass
, size_t asl
, unsigned flags TSRMLS_DC
)
567 php_http_buffer_append(buf
, ass
, asl
);
570 prepare_key(flags
, key_str
, key_len
, &str
, &len TSRMLS_CC
);
571 php_http_buffer_append(buf
, str
, len
);
575 static inline void shift_val(php_http_buffer_t
*buf
, zval
*zvalue
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
)
577 if (Z_TYPE_P(zvalue
) != IS_BOOL
) {
578 zval
*tmp
= php_http_zsep(1, IS_STRING
, zvalue
);
580 prepare_value(flags
, tmp TSRMLS_CC
);
581 php_http_buffer_append(buf
, vss
, vsl
);
582 php_http_buffer_append(buf
, Z_STRVAL_P(tmp
), Z_STRLEN_P(tmp
));
585 } else if (!Z_BVAL_P(zvalue
)) {
586 php_http_buffer_append(buf
, vss
, vsl
);
587 php_http_buffer_appends(buf
, "0");
591 static void shift_arg(php_http_buffer_t
*buf
, char *key_str
, size_t key_len
, zval
*zvalue
, const char *ass
, size_t asl
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
)
593 if (Z_TYPE_P(zvalue
) == IS_ARRAY
|| Z_TYPE_P(zvalue
) == IS_OBJECT
) {
595 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
598 FOREACH_KEYVAL(pos
, zvalue
, key
, val
) {
599 /* did you mean recursion? */
600 php_http_array_hashkey_stringify(&key
);
601 shift_arg(buf
, key
.str
, key
.len
-1, *val
, ass
, asl
, vss
, vsl
, flags TSRMLS_CC
);
602 php_http_array_hashkey_stringfree(&key
);
605 shift_key(buf
, key_str
, key_len
, ass
, asl
, flags TSRMLS_CC
);
606 shift_val(buf
, zvalue
, vss
, vsl
, flags TSRMLS_CC
);
610 static void shift_param(php_http_buffer_t
*buf
, char *key_str
, size_t key_len
, zval
*zvalue
, const char *pss
, size_t psl
, const char *ass
, size_t asl
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
)
612 if (Z_TYPE_P(zvalue
) == IS_ARRAY
|| Z_TYPE_P(zvalue
) == IS_OBJECT
) {
613 /* treat as arguments, unless we care for dimensions */
614 if (flags
& PHP_HTTP_PARAMS_DIMENSION
) {
615 php_http_buffer_t
*keybuf
= php_http_buffer_from_string(key_str
, key_len
);
616 prepare_dimension(buf
, keybuf
, zvalue
, pss
, psl
, vss
, vsl
, flags TSRMLS_CC
);
617 php_http_buffer_free(&keybuf
);
619 shift_arg(buf
, key_str
, key_len
, zvalue
, ass
, asl
, vss
, vsl
, flags TSRMLS_CC
);
622 shift_key(buf
, key_str
, key_len
, pss
, psl
, flags TSRMLS_CC
);
623 shift_val(buf
, zvalue
, vss
, vsl
, flags TSRMLS_CC
);
627 PHP_HTTP_API php_http_buffer_t
*php_http_params_to_string(php_http_buffer_t
*buf
, HashTable
*params
, const char *pss
, size_t psl
, const char *ass
, size_t asl
, const char *vss
, size_t vsl
, unsigned flags TSRMLS_DC
)
630 HashPosition pos
, pos1
;
631 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0), key1
= php_http_array_hashkey_init(0);
634 buf
= php_http_buffer_init(NULL
);
637 FOREACH_HASH_KEYVAL(pos
, params
, key
, zparam
) {
638 zval
**zvalue
, **zargs
;
640 if (Z_TYPE_PP(zparam
) != IS_ARRAY
|| SUCCESS
!= zend_hash_find(Z_ARRVAL_PP(zparam
), ZEND_STRS("value"), (void *) &zvalue
)) {
644 php_http_array_hashkey_stringify(&key
);
645 shift_param(buf
, key
.str
, key
.len
- 1, *zvalue
, pss
, psl
, ass
, asl
, vss
, vsl
, flags TSRMLS_CC
);
646 php_http_array_hashkey_stringfree(&key
);
648 if (Z_TYPE_PP(zparam
) == IS_ARRAY
&& SUCCESS
!= zend_hash_find(Z_ARRVAL_PP(zparam
), ZEND_STRS("arguments"), (void *) &zvalue
)) {
649 if (zvalue
== zparam
) {
655 if (Z_TYPE_PP(zvalue
) == IS_ARRAY
) {
656 FOREACH_KEYVAL(pos1
, *zvalue
, key1
, zargs
) {
657 if (zvalue
== zparam
&& key1
.type
== HASH_KEY_IS_STRING
&& !strcmp(key1
.str
, "value")) {
661 php_http_array_hashkey_stringify(&key1
);
662 shift_arg(buf
, key1
.str
, key1
.len
- 1, *zargs
, ass
, asl
, vss
, vsl
, flags TSRMLS_CC
);
663 php_http_array_hashkey_stringfree(&key1
);
668 php_http_buffer_shrink(buf
);
669 php_http_buffer_fix(buf
);
674 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpParams, method, 0, req_args)
675 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpParams, method, 0)
676 #define PHP_HTTP_PARAMS_ME(method, visibility) PHP_ME(HttpParams, method, PHP_HTTP_ARGS(HttpParams, method), visibility)
677 #define PHP_HTTP_PARAMS_GME(method, visibility) PHP_ME(HttpParams, method, PHP_HTTP_ARGS(HttpParams, __getter), visibility)
679 PHP_HTTP_BEGIN_ARGS(__construct
, 0)
680 PHP_HTTP_ARG_VAL(params
, 0)
681 PHP_HTTP_ARG_VAL(param_sep
, 0)
682 PHP_HTTP_ARG_VAL(arg_sep
, 0)
683 PHP_HTTP_ARG_VAL(val_sep
, 0)
684 PHP_HTTP_ARG_VAL(flags
, 0)
687 PHP_HTTP_EMPTY_ARGS(toArray
);
688 PHP_HTTP_EMPTY_ARGS(toString
);
690 PHP_HTTP_BEGIN_ARGS(offsetExists
, 1)
691 PHP_HTTP_ARG_VAL(name
, 0)
694 PHP_HTTP_BEGIN_ARGS(offsetUnset
, 1)
695 PHP_HTTP_ARG_VAL(name
, 0)
698 PHP_HTTP_BEGIN_ARGS(offsetGet
, 1)
699 PHP_HTTP_ARG_VAL(name
, 0)
702 PHP_HTTP_BEGIN_ARGS(offsetSet
, 2)
703 PHP_HTTP_ARG_VAL(name
, 0)
704 PHP_HTTP_ARG_VAL(value
, 0)
707 static zend_class_entry
*php_http_params_class_entry
;
709 zend_class_entry
*php_http_params_get_class_entry(void)
711 return php_http_params_class_entry
;
714 static zend_function_entry php_http_params_method_entry
[] = {
715 PHP_HTTP_PARAMS_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
|ZEND_ACC_FINAL
)
717 PHP_HTTP_PARAMS_ME(toArray
, ZEND_ACC_PUBLIC
)
718 PHP_HTTP_PARAMS_ME(toString
, ZEND_ACC_PUBLIC
)
719 ZEND_MALIAS(HttpParams
, __toString
, toString
, PHP_HTTP_ARGS(HttpParams
, toString
), ZEND_ACC_PUBLIC
)
721 PHP_HTTP_PARAMS_ME(offsetExists
, ZEND_ACC_PUBLIC
)
722 PHP_HTTP_PARAMS_ME(offsetUnset
, ZEND_ACC_PUBLIC
)
723 PHP_HTTP_PARAMS_ME(offsetSet
, ZEND_ACC_PUBLIC
)
724 PHP_HTTP_PARAMS_ME(offsetGet
, ZEND_ACC_PUBLIC
)
729 PHP_MINIT_FUNCTION(http_params
)
731 PHP_HTTP_REGISTER_CLASS(http
, Params
, http_params
, php_http_object_get_class_entry(), 0);
733 zend_class_implements(php_http_params_class_entry TSRMLS_CC
, 1, zend_ce_arrayaccess
);
735 zend_declare_class_constant_stringl(php_http_params_class_entry
, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(",") TSRMLS_CC
);
736 zend_declare_class_constant_stringl(php_http_params_class_entry
, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";") TSRMLS_CC
);
737 zend_declare_class_constant_stringl(php_http_params_class_entry
, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("=") TSRMLS_CC
);
738 zend_declare_class_constant_stringl(php_http_params_class_entry
, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("") TSRMLS_CC
);
740 zend_declare_class_constant_long(php_http_params_class_entry
, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW TSRMLS_CC
);
741 zend_declare_class_constant_long(php_http_params_class_entry
, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC
);
742 zend_declare_class_constant_long(php_http_params_class_entry
, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED TSRMLS_CC
);
743 zend_declare_class_constant_long(php_http_params_class_entry
, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION TSRMLS_CC
);
744 zend_declare_class_constant_long(php_http_params_class_entry
, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY TSRMLS_CC
);
746 zend_declare_property_null(php_http_params_class_entry
, ZEND_STRL("params"), ZEND_ACC_PUBLIC TSRMLS_CC
);
747 zend_declare_property_stringl(php_http_params_class_entry
, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC TSRMLS_CC
);
748 zend_declare_property_stringl(php_http_params_class_entry
, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC TSRMLS_CC
);
749 zend_declare_property_stringl(php_http_params_class_entry
, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC TSRMLS_CC
);
750 zend_declare_property_long(php_http_params_class_entry
, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT
, ZEND_ACC_PUBLIC TSRMLS_CC
);
755 PHP_HTTP_API php_http_params_token_t
**php_http_params_separator_init(zval
*zv TSRMLS_DC
)
759 php_http_params_token_t
**ret
, **tmp
;
765 zv
= php_http_ztyp(IS_ARRAY
, zv
);
766 ret
= ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zv
)) + 1, sizeof(*ret
));
769 FOREACH_VAL(pos
, zv
, sep
) {
770 zval
*zt
= php_http_ztyp(IS_STRING
, *sep
);
772 if (Z_STRLEN_P(zt
)) {
773 *tmp
= emalloc(sizeof(**tmp
));
774 (*tmp
)->str
= estrndup(Z_STRVAL_P(zt
), (*tmp
)->len
= Z_STRLEN_P(zt
));
785 PHP_HTTP_API
void php_http_params_separator_free(php_http_params_token_t
**separator
)
787 php_http_params_token_t
**sep
= separator
;
790 STR_FREE((*sep
)->str
);
798 PHP_METHOD(HttpParams
, __construct
)
800 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
801 zval
*zcopy
, *zparams
= NULL
, *param_sep
= NULL
, *arg_sep
= NULL
, *val_sep
= NULL
;
802 long flags
= PHP_HTTP_PARAMS_DEFAULT
;
804 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|z!/z/z/z/l", &zparams
, ¶m_sep
, &arg_sep
, &val_sep
, &flags
)) {
805 switch (ZEND_NUM_ARGS()) {
807 zend_update_property_long(php_http_params_class_entry
, getThis(), ZEND_STRL("flags"), flags TSRMLS_CC
);
810 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("val_sep"), val_sep TSRMLS_CC
);
813 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("arg_sep"), arg_sep TSRMLS_CC
);
816 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("param_sep"), param_sep TSRMLS_CC
);
821 switch (Z_TYPE_P(zparams
)) {
824 zcopy
= php_http_zsep(1, IS_ARRAY
, zparams
);
825 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), zcopy TSRMLS_CC
);
826 zval_ptr_dtor(&zcopy
);
829 zcopy
= php_http_ztyp(IS_STRING
, zparams
);
830 if (Z_STRLEN_P(zcopy
)) {
831 php_http_params_opts_t opts
= {
832 {Z_STRVAL_P(zcopy
), Z_STRLEN_P(zcopy
)},
833 php_http_params_separator_init(zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC
) TSRMLS_CC
),
834 php_http_params_separator_init(zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC
) TSRMLS_CC
),
835 php_http_params_separator_init(zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC
) TSRMLS_CC
),
839 MAKE_STD_ZVAL(zparams
);
841 php_http_params_parse(Z_ARRVAL_P(zparams
), &opts TSRMLS_CC
);
842 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC
);
843 zval_ptr_dtor(&zparams
);
845 php_http_params_separator_free(opts
.param
);
846 php_http_params_separator_free(opts
.arg
);
847 php_http_params_separator_free(opts
.val
);
849 zval_ptr_dtor(&zcopy
);
853 MAKE_STD_ZVAL(zparams
);
855 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC
);
856 zval_ptr_dtor(&zparams
);
859 } end_error_handling();
862 PHP_METHOD(HttpParams
, toArray
)
864 if (SUCCESS
!= zend_parse_parameters_none()) {
867 RETURN_PROP(php_http_params_class_entry
, "params");
870 PHP_METHOD(HttpParams
, toString
)
872 zval
**tmp
, *zparams
, *zpsep
, *zasep
, *zvsep
, *zflags
;
873 php_http_buffer_t buf
;
875 zparams
= php_http_zsep(1, IS_ARRAY
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC
));
876 zflags
= php_http_ztyp(IS_LONG
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("flags"), 0 TSRMLS_CC
));
878 zpsep
= zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC
);
879 if (Z_TYPE_P(zpsep
) == IS_ARRAY
&& SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_P(zpsep
), (void *) &tmp
)) {
880 zpsep
= php_http_ztyp(IS_STRING
, *tmp
);
882 zpsep
= php_http_ztyp(IS_STRING
, zpsep
);
884 zasep
= zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC
);
885 if (Z_TYPE_P(zasep
) == IS_ARRAY
&& SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_P(zasep
), (void *) &tmp
)) {
886 zasep
= php_http_ztyp(IS_STRING
, *tmp
);
888 zasep
= php_http_ztyp(IS_STRING
, zasep
);
890 zvsep
= zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC
);
891 if (Z_TYPE_P(zvsep
) == IS_ARRAY
&& SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_P(zvsep
), (void *) &tmp
)) {
892 zvsep
= php_http_ztyp(IS_STRING
, *tmp
);
894 zvsep
= php_http_ztyp(IS_STRING
, zvsep
);
897 php_http_buffer_init(&buf
);
898 php_http_params_to_string(&buf
, Z_ARRVAL_P(zparams
), Z_STRVAL_P(zpsep
), Z_STRLEN_P(zpsep
), Z_STRVAL_P(zasep
), Z_STRLEN_P(zasep
), Z_STRVAL_P(zvsep
), Z_STRLEN_P(zvsep
), Z_LVAL_P(zflags
) TSRMLS_CC
);
900 zval_ptr_dtor(&zparams
);
901 zval_ptr_dtor(&zpsep
);
902 zval_ptr_dtor(&zasep
);
903 zval_ptr_dtor(&zvsep
);
904 zval_ptr_dtor(&zflags
);
906 RETVAL_PHP_HTTP_BUFFER_VAL(&buf
);
909 PHP_METHOD(HttpParams
, offsetExists
)
914 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &name_str
, &name_len
)) {
915 zval
**zparam
, *zparams
= php_http_ztyp(IS_ARRAY
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC
));
917 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(zparams
), name_str
, name_len
+ 1, (void *) &zparam
)) {
918 RETVAL_BOOL(Z_TYPE_PP(zparam
) != IS_NULL
);
922 zval_ptr_dtor(&zparams
);
926 PHP_METHOD(HttpParams
, offsetGet
)
931 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &name_str
, &name_len
)) {
932 zval
**zparam
, *zparams
= php_http_ztyp(IS_ARRAY
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC
));
934 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(zparams
), name_str
, name_len
+ 1, (void *) &zparam
)) {
935 RETVAL_ZVAL(*zparam
, 1, 0);
938 zval_ptr_dtor(&zparams
);
943 PHP_METHOD(HttpParams
, offsetUnset
)
948 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &name_str
, &name_len
)) {
949 zval
*zparams
= php_http_zsep(1, IS_ARRAY
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC
));
951 zend_symtable_del(Z_ARRVAL_P(zparams
), name_str
, name_len
+ 1);
952 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC
);
954 zval_ptr_dtor(&zparams
);
958 PHP_METHOD(HttpParams
, offsetSet
)
964 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "sz", &name_str
, &name_len
, &nvalue
)) {
965 zval
**zparam
, *zparams
= php_http_zsep(1, IS_ARRAY
, zend_read_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC
));
968 if (Z_TYPE_P(nvalue
) == IS_ARRAY
) {
971 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(zparams
), name_str
, name_len
+ 1, (void *) &zparam
)) {
972 new_zparam
= php_http_zsep(1, IS_ARRAY
, *zparam
);
973 array_join(Z_ARRVAL_P(nvalue
), Z_ARRVAL_P(new_zparam
), 0, 0);
976 Z_ADDREF_P(new_zparam
);
978 add_assoc_zval_ex(zparams
, name_str
, name_len
+ 1, new_zparam
);
982 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(zparams
), name_str
, name_len
+ 1, (void *) &zparam
)) {
983 tmp
= php_http_zsep(1, IS_ARRAY
, *zparam
);
990 add_assoc_zval_ex(tmp
, ZEND_STRS("value"), nvalue
);
991 add_assoc_zval_ex(zparams
, name_str
, name_len
+ 1, tmp
);
994 zval
*tmp
= php_http_ztyp(IS_STRING
, nvalue
), *arr
;
998 add_assoc_bool_ex(arr
, ZEND_STRS("value"), 1);
999 add_assoc_zval_ex(zparams
, Z_STRVAL_P(tmp
), Z_STRLEN_P(tmp
) + 1, arr
);
1000 zval_ptr_dtor(&tmp
);
1003 zend_update_property(php_http_params_class_entry
, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC
);
1004 zval_ptr_dtor(&zparams
);
1013 * vim600: noet sw=4 ts=4 fdm=marker
1014 * vim<600: noet sw=4 ts=4