LCOV - code coverage report
Current view: top level - ext/http - php_http_params.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 579 610 94.9 %
Date: 2015-02-17 20:30:22 Functions: 35 35 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     +--------------------------------------------------------------------+
       3             :     | PECL :: http                                                       |
       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-2014, Michael Wallner <mike@php.net>            |
      10             :     +--------------------------------------------------------------------+
      11             : */
      12             : 
      13             : #include "php_http_api.h"
      14             : 
      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 = {
      19             :         {NULL, 0},
      20             :         def_param_sep_ptr,
      21             :         def_arg_sep_ptr,
      22             :         def_val_sep_ptr,
      23             :         NULL,
      24             :         PHP_HTTP_PARAMS_DEFAULT
      25             : };
      26             : 
      27          41 : php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts)
      28             : {
      29          41 :         if (!opts) {
      30           0 :                 opts = emalloc(sizeof(*opts));
      31             :         }
      32             : 
      33          41 :         memcpy(opts, &def_opts, sizeof(def_opts));
      34             : 
      35          41 :         return opts;
      36             : }
      37             : 
      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;
      43             :         struct {
      44             :                 zval **param;
      45             :                 zval **args;
      46             :                 zval **val;
      47             :         } current;
      48             :         unsigned quotes:1;
      49             :         unsigned escape:1;
      50             :         unsigned rfc5987:1;
      51             : } php_http_params_state_t;
      52             : 
      53         269 : static inline void sanitize_escaped(zval *zv TSRMLS_DC)
      54             : {
      55         269 :         if (Z_STRVAL_P(zv)[0] == '"' && Z_STRVAL_P(zv)[Z_STRLEN_P(zv) - 1] == '"') {
      56           9 :                 size_t deq_len = Z_STRLEN_P(zv) - 2;
      57           9 :                 char *deq = estrndup(Z_STRVAL_P(zv) + 1, deq_len);
      58             : 
      59           9 :                 zval_dtor(zv);
      60           9 :                 ZVAL_STRINGL(zv, deq, deq_len, 0);
      61             :         }
      62             : 
      63         269 :         php_stripcslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv));
      64         269 : }
      65             : 
      66          72 : static inline void prepare_escaped(zval *zv TSRMLS_DC)
      67             : {
      68          72 :         if (Z_TYPE_P(zv) == IS_STRING) {
      69          72 :                 int len = Z_STRLEN_P(zv);
      70             : 
      71          72 :                 Z_STRVAL_P(zv) = php_addcslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1,
      72             :                                 ZEND_STRL("\0..\37\173\\\"") TSRMLS_CC);
      73             : 
      74          72 :                 if (len != Z_STRLEN_P(zv) || strpbrk(Z_STRVAL_P(zv), "()<>@,;:\"[]?={} ")) {
      75           1 :                         zval tmp = *zv;
      76           1 :                         int len = Z_STRLEN_P(zv) + 2;
      77           1 :                         char *str = emalloc(len + 1);
      78             : 
      79           1 :                         str[0] = '"';
      80           1 :                         memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv));
      81           1 :                         str[len-1] = '"';
      82           1 :                         str[len] = '\0';
      83             : 
      84           1 :                         zval_dtor(&tmp);
      85           1 :                         ZVAL_STRINGL(zv, str, len, 0);
      86             :                 }
      87             :         } else {
      88           0 :                 zval_dtor(zv);
      89           0 :                 ZVAL_EMPTY_STRING(zv);
      90             :         }
      91          72 : }
      92             : 
      93         115 : static inline void sanitize_urlencoded(zval *zv TSRMLS_DC)
      94             : {
      95         115 :         Z_STRLEN_P(zv) = php_raw_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
      96         115 : }
      97             : 
      98         279 : static inline void prepare_urlencoded(zval *zv TSRMLS_DC)
      99             : {
     100             :         int len;
     101         279 :         char *str =     php_raw_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &len);
     102             : 
     103         279 :         zval_dtor(zv);
     104         279 :         ZVAL_STRINGL(zv, str, len, 0);
     105         279 : }
     106             : 
     107          52 : static void sanitize_dimension(zval *zv TSRMLS_DC)
     108             : {
     109          52 :         zval *arr = NULL, *tmp = NULL, **cur = NULL;
     110          52 :         char *var = NULL, *ptr = Z_STRVAL_P(zv), *end = Z_STRVAL_P(zv) + Z_STRLEN_P(zv);
     111          52 :         long level = 0;
     112             : 
     113          52 :         MAKE_STD_ZVAL(arr);
     114          52 :         array_init(arr);
     115          52 :         cur = &arr;
     116             : 
     117         341 :         while (ptr < end) {
     118         237 :                 if (!var) {
     119          90 :                         var = ptr;
     120             :                 }
     121             : 
     122         237 :                 switch (*ptr) {
     123             :                         case '[':
     124          38 :                                 if (++level > PG(max_input_nesting_level)) {
     125           0 :                                         zval_ptr_dtor(&arr);
     126           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Max input nesting level of %ld exceeded", (long) PG(max_input_nesting_level));
     127          52 :                                         return;
     128             :                                 }
     129          38 :                                 if (ptr - var == 0) {
     130          10 :                                         ++var;
     131          10 :                                         break;
     132             :                                 }
     133             :                                 /* no break */
     134             : 
     135             :                         case ']':
     136             : 
     137          66 :                                 MAKE_STD_ZVAL(tmp);
     138          66 :                                 ZVAL_NULL(tmp);
     139          66 :                                 convert_to_array(*cur);
     140             : 
     141          66 :                                 if (ptr - var) {
     142          44 :                                         char chr = *ptr;
     143          44 :                                         *ptr = '\0';
     144          44 :                                         zend_symtable_update(Z_ARRVAL_PP(cur), var, ptr - var + 1, (void *) &tmp, sizeof(zval *), (void *) &cur);
     145          44 :                                         *ptr = chr;
     146             :                                 } else {
     147          22 :                                         zend_hash_next_index_insert(Z_ARRVAL_PP(cur), (void *) &tmp, sizeof(zval *), (void *) &cur);
     148             :                                 }
     149             : 
     150          66 :                                 var = NULL;
     151          66 :                                 break;
     152             :                 }
     153             : 
     154         237 :                 ++ptr;
     155             :         }
     156             : 
     157          52 :         if (zend_hash_num_elements(Z_ARRVAL_P(arr))) {
     158          28 :                 zval_dtor(zv);
     159             : #if PHP_VERSION_ID >= 50400
     160          28 :                 ZVAL_COPY_VALUE(zv, arr);
     161             : #else
     162             :                 zv->value = arr->value;
     163             :                 Z_TYPE_P(zv) = Z_TYPE_P(arr);
     164             : #endif
     165          28 :                 FREE_ZVAL(arr);
     166             :         } else {
     167          24 :                 zval_ptr_dtor(&arr);
     168             :         }
     169             : }
     170             : 
     171             : 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);
     172             : static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC);
     173             : 
     174          56 : 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)
     175             : {
     176          56 :         HashTable *ht = HASH_OF(zvalue);
     177             :         HashPosition pos;
     178          56 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
     179             :         zval **val;
     180             :         php_http_buffer_t prefix;
     181             : 
     182          56 :         if (!ht->nApplyCount++) {
     183          56 :                 php_http_buffer_init(&prefix);
     184          56 :                 php_http_buffer_append(&prefix, keybuf->data, keybuf->used);
     185             : 
     186         153 :                 FOREACH_HASH_KEYVAL(pos, ht, key, val) {
     187          97 :                         if (key.type == HASH_KEY_IS_STRING && !*key.str) {
     188             :                                 /* only public properties */
     189           0 :                                 continue;
     190             :                         }
     191             : 
     192          97 :                         php_http_buffer_appends(&prefix, "[");
     193          97 :                         if (key.type == HASH_KEY_IS_STRING) {
     194          29 :                                 php_http_buffer_append(&prefix, key.str, key.len - 1);
     195             :                         } else {
     196          68 :                                 php_http_buffer_appendf(&prefix, "%lu", key.num);
     197             :                         }
     198          97 :                         php_http_buffer_appends(&prefix, "]");
     199             : 
     200          97 :                         if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) {
     201          24 :                                 prepare_dimension(buf, &prefix, *val, pss, psl, vss, vsl, flags TSRMLS_CC);
     202             :                         } else {
     203          73 :                                 zval *cpy = php_http_ztyp(IS_STRING, *val);
     204             : 
     205          73 :                                 shift_key(buf, prefix.data, prefix.used, pss, psl, flags TSRMLS_CC);
     206          73 :                                 shift_val(buf, cpy, vss, vsl, flags TSRMLS_CC);
     207          73 :                                 zval_ptr_dtor(&cpy);
     208             :                         }
     209             : 
     210          97 :                         php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used);
     211             :                 }
     212          56 :                 php_http_buffer_dtor(&prefix);
     213             :         }
     214          56 :         --ht->nApplyCount;
     215          56 : }
     216             : 
     217         235 : static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv, zend_bool *rfc5987 TSRMLS_DC)
     218             : {
     219             :         char *eos;
     220             : 
     221         235 :         zval_dtor(zv);
     222         235 :         php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC);
     223             : 
     224         235 :         if (flags & PHP_HTTP_PARAMS_ESCAPED) {
     225         178 :                 sanitize_escaped(zv TSRMLS_CC);
     226             :         }
     227             :         
     228         235 :         if (!Z_STRLEN_P(zv)) {
     229         237 :                 return;
     230             :         }
     231             : 
     232         233 :         eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1];
     233         233 :         if (*eos == '*') {
     234          18 :                 *eos = '\0';
     235          18 :                 *rfc5987 = 1;
     236          18 :                 Z_STRLEN_P(zv) -= 1;
     237             :         }
     238             : 
     239         233 :         if (flags & PHP_HTTP_PARAMS_URLENCODED) {
     240          55 :                 sanitize_urlencoded(zv TSRMLS_CC);
     241             :         }
     242             : 
     243         233 :         if (flags & PHP_HTTP_PARAMS_DIMENSION) {
     244          52 :                 sanitize_dimension(zv TSRMLS_CC);
     245             :         }
     246             : }
     247             : 
     248           7 : static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1 TSRMLS_DC)
     249             : {
     250             :         char *ptr;
     251             : 
     252             :         /* examples:
     253             :          * iso-8850-1'de'bl%f6der%20schei%df%21
     254             :          * utf-8'de-DE'bl%c3%b6der%20schei%c3%9f%21
     255             :          */
     256             : 
     257           7 :         switch (Z_STRVAL_P(zv)[0]) {
     258             :         case 'I':
     259             :         case 'i':
     260           2 :                 if (!strncasecmp(Z_STRVAL_P(zv), "iso-8859-1", lenof("iso-8859-1"))) {
     261           2 :                         *latin1 = 1;
     262           2 :                         ptr = Z_STRVAL_P(zv) + lenof("iso-8859-1");
     263           2 :                         break;
     264             :                 }
     265             :                 /* no break */
     266             :         case 'U':
     267             :         case 'u':
     268           5 :                 if (!strncasecmp(Z_STRVAL_P(zv), "utf-8", lenof("utf-8"))) {
     269           5 :                         *latin1 = 0;
     270           5 :                         ptr = Z_STRVAL_P(zv) + lenof("utf-8");
     271           5 :                         break;
     272             :                 }
     273             :                 /* no break */
     274             :         default:
     275           0 :                 return;
     276             :         }
     277             : 
     278             :         /* extract language */
     279           7 :         if (*ptr == '\'') {
     280           7 :                 for (*language = ++ptr; *ptr && *ptr != '\''; ++ptr);
     281           7 :                 if (!*ptr) {
     282           0 :                         *language = NULL;
     283           0 :                         return;
     284             :                 }
     285           7 :                 *language = estrndup(*language, ptr - *language);
     286             : 
     287             :                 /* remainder */
     288           7 :                 ptr = estrdup(++ptr);
     289           7 :                 zval_dtor(zv);
     290           7 :                 ZVAL_STRING(zv, ptr, 0);
     291             :         }
     292             : }
     293             : 
     294           2 : static void utf8encode(zval *zv)
     295             : {
     296           2 :         size_t pos, len = 0;
     297           2 :         unsigned char *ptr = (unsigned char *) Z_STRVAL_P(zv);
     298             : 
     299          20 :         while (*ptr) {
     300          16 :                 if (*ptr++ >= 0x80) {
     301           2 :                         ++len;
     302             :                 }
     303          16 :                 ++len;
     304             :         }
     305             : 
     306           2 :         ptr = safe_emalloc(1, len, 1);
     307          20 :         for (len = 0, pos = 0; len <= Z_STRLEN_P(zv); ++len, ++pos) {
     308          18 :                 ptr[pos] = Z_STRVAL_P(zv)[len];
     309          18 :                 if ((ptr[pos]) >= 0x80) {
     310           2 :                         ptr[pos + 1] = 0x80 | (ptr[pos] & 0x3f);
     311           2 :                         ptr[pos] = 0xc0 | ((ptr[pos] >> 6) & 0x1f);
     312           2 :                         ++pos;
     313             :                 }
     314             :         }
     315           2 :         zval_dtor(zv);
     316           2 :         ZVAL_STRINGL(zv, (char *) ptr, pos-1, 0);
     317           2 : }
     318             : 
     319         145 : static inline void sanitize_value(unsigned flags, char *str, size_t len, zval *zv, zend_bool rfc5987 TSRMLS_DC)
     320             : {
     321         145 :         char *language = NULL;
     322         145 :         zend_bool latin1 = 0;
     323             : 
     324         145 :         zval_dtor(zv);
     325         145 :         php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC);
     326             : 
     327         145 :         if (rfc5987) {
     328           7 :                 sanitize_rfc5987(zv, &language, &latin1 TSRMLS_CC);
     329             :         }
     330             : 
     331         145 :         if (flags & PHP_HTTP_PARAMS_ESCAPED) {
     332          91 :                 sanitize_escaped(zv TSRMLS_CC);
     333             :         }
     334             : 
     335         145 :         if ((flags & PHP_HTTP_PARAMS_URLENCODED) || (rfc5987 && language)) {
     336          60 :                 sanitize_urlencoded(zv TSRMLS_CC);
     337             :         }
     338             : 
     339         145 :         if (rfc5987 && language) {
     340             :                 zval *tmp;
     341             : 
     342           7 :                 if (latin1) {
     343           2 :                         utf8encode(zv);
     344             :                 }
     345             : 
     346           7 :                 MAKE_STD_ZVAL(tmp);
     347           7 :                 ZVAL_COPY_VALUE(tmp, zv);
     348           7 :                 array_init(zv);
     349           7 :                 add_assoc_zval(zv, language, tmp);
     350           7 :                 PTR_FREE(language);
     351             :         }
     352         145 : }
     353             : 
     354         182 : static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, char **new_key, size_t *new_len TSRMLS_DC)
     355             : {
     356             :         zval zv;
     357             : 
     358         182 :         INIT_PZVAL(&zv);
     359         182 :         ZVAL_STRINGL(&zv, old_key, old_len, 1);
     360             : 
     361         182 :         if (flags & PHP_HTTP_PARAMS_URLENCODED) {
     362         134 :                 prepare_urlencoded(&zv TSRMLS_CC);
     363             :         }
     364             : 
     365         182 :         if (flags & PHP_HTTP_PARAMS_ESCAPED) {
     366          46 :                 prepare_escaped(&zv TSRMLS_CC);
     367             :         }
     368             : 
     369         182 :         *new_key = Z_STRVAL(zv);
     370         182 :         *new_len = Z_STRLEN(zv);
     371         182 : }
     372             : 
     373         161 : static inline void prepare_value(unsigned flags, zval *zv TSRMLS_DC)
     374             : {
     375         161 :         if (flags & PHP_HTTP_PARAMS_URLENCODED) {
     376         145 :                 prepare_urlencoded(zv TSRMLS_CC);
     377             :         }
     378             : 
     379         161 :         if (flags & PHP_HTTP_PARAMS_ESCAPED) {
     380          26 :                 prepare_escaped(zv TSRMLS_CC);
     381             :         }
     382         161 : }
     383             : 
     384          28 : static void merge_param(HashTable *params, zval *zdata, zval ***current_param, zval ***current_args TSRMLS_DC)
     385             : {
     386             :         zval **ptr, **zdata_ptr;
     387          28 :         php_http_array_hashkey_t hkey = php_http_array_hashkey_init(0);
     388             : 
     389             : #if 0
     390             :         {
     391             :                 zval tmp;
     392             :                 INIT_PZVAL_ARRAY(&tmp, params);
     393             :                 fprintf(stderr, "params = ");
     394             :                 zend_print_zval_r(&tmp, 1 TSRMLS_CC);
     395             :                 fprintf(stderr, "\n");
     396             :         }
     397             : #endif
     398             : 
     399          28 :         hkey.type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zdata), &hkey.str, &hkey.len, &hkey.num, hkey.dup, NULL);
     400             : 
     401          28 :         if ((hkey.type == HASH_KEY_IS_STRING && !zend_hash_exists(params, hkey.str, hkey.len))
     402          15 :         ||      (hkey.type == HASH_KEY_IS_LONG && !zend_hash_index_exists(params, hkey.num))
     403          13 :         ) {
     404             :                 zval *tmp, *arg, **args;
     405             : 
     406             :                 /* create the entry if it doesn't exist */
     407          13 :                 zend_hash_get_current_data(Z_ARRVAL_P(zdata), (void *) &ptr);
     408          13 :                 Z_ADDREF_PP(ptr);
     409          13 :                 MAKE_STD_ZVAL(tmp);
     410          13 :                 array_init(tmp);
     411          13 :                 add_assoc_zval_ex(tmp, ZEND_STRS("value"), *ptr);
     412             : 
     413          13 :                 MAKE_STD_ZVAL(arg);
     414          13 :                 array_init(arg);
     415          13 :                 zend_hash_update(Z_ARRVAL_P(tmp), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &args);
     416          13 :                 *current_args = args;
     417             : 
     418          13 :                 if (hkey.type == HASH_KEY_IS_STRING) {
     419          13 :                         zend_hash_update(params, hkey.str, hkey.len, (void *) &tmp, sizeof(zval *), (void *) &ptr);
     420             :                 } else {
     421           0 :                         zend_hash_index_update(params, hkey.num, (void *) &tmp, sizeof(zval *), (void *) &ptr);
     422             :                 }
     423             :         } else {
     424             :                 /* merge */
     425          15 :                 if (hkey.type == HASH_KEY_IS_STRING) {
     426          15 :                         zend_hash_find(params, hkey.str, hkey.len, (void *) &ptr);
     427             :                 } else {
     428           0 :                         zend_hash_index_find(params, hkey.num, (void *) &ptr);
     429             :                 }
     430             : 
     431          15 :                 zdata_ptr = &zdata;
     432             : 
     433          15 :                 if (Z_TYPE_PP(ptr) == IS_ARRAY
     434          15 :                 &&      SUCCESS == zend_hash_find(Z_ARRVAL_PP(ptr), "value", sizeof("value"), (void *) &ptr)
     435          15 :                 &&      SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr), (void *) &zdata_ptr)
     436             :                 ) {
     437             :                         /*
     438             :                          * params = [arr => [value => [0 => 1]]]
     439             :                          *                            ^- ptr
     440             :                          * zdata  = [arr => [0 => NULL]]
     441             :                          *                  ^- zdata_ptr
     442             :                          */
     443             :                         zval **test_ptr;
     444             : 
     445          33 :                         while (Z_TYPE_PP(zdata_ptr) == IS_ARRAY
     446          18 :                         &&      SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(zdata_ptr), (void *) &test_ptr)
     447             :                         ) {
     448          18 :                                 if (Z_TYPE_PP(test_ptr) == IS_ARRAY) {
     449             : 
     450             :                                         /* now find key in ptr */
     451           4 :                                         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)) {
     452           1 :                                                 if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) &ptr)) {
     453           0 :                                                         zdata_ptr = test_ptr;
     454             :                                                 } else {
     455           1 :                                                         Z_ADDREF_PP(test_ptr);
     456           1 :                                                         zend_hash_update(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     457           1 :                                                         break;
     458             :                                                 }
     459             :                                         } else {
     460           3 :                                                 if (SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(ptr), hkey.num, (void *) &ptr)) {
     461           3 :                                                         zdata_ptr = test_ptr;
     462           0 :                                                 } else if (hkey.num) {
     463           0 :                                                         Z_ADDREF_PP(test_ptr);
     464           0 :                                                         zend_hash_index_update(Z_ARRVAL_PP(ptr), hkey.num, (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     465           0 :                                                         break;
     466             :                                                 } else {
     467           0 :                                                         Z_ADDREF_PP(test_ptr);
     468           0 :                                                         zend_hash_next_index_insert(Z_ARRVAL_PP(ptr), (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     469           0 :                                                         break;
     470             :                                                 }
     471             :                                         }
     472             :                                 } else {
     473             :                                         /* this is the leaf */
     474          14 :                                         Z_ADDREF_PP(test_ptr);
     475          14 :                                         if (Z_TYPE_PP(ptr) != IS_ARRAY) {
     476           0 :                                                 zval_dtor(*ptr);
     477           0 :                                                 array_init(*ptr);
     478             :                                         }
     479          14 :                                         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)) {
     480           0 :                                                 zend_hash_update(Z_ARRVAL_PP(ptr), hkey.str, hkey.len, (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     481          14 :                                         } else if (hkey.num) {
     482           5 :                                                 zend_hash_index_update(Z_ARRVAL_PP(ptr), hkey.num, (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     483             :                                         } else {
     484           9 :                                                 zend_hash_next_index_insert(Z_ARRVAL_PP(ptr), (void *) test_ptr, sizeof(zval *), (void *) &ptr);
     485             :                                         }
     486          14 :                                         break;
     487             :                                 }
     488             :                         }
     489             : 
     490             :                 }
     491             :         }
     492             : 
     493             :         /* bubble up */
     494          28 :         while (Z_TYPE_PP(ptr) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_PP(ptr), (void *) &ptr));
     495          28 :         *current_param = ptr;
     496          28 : }
     497             : 
     498         383 : static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts TSRMLS_DC)
     499             : {
     500         383 :         if (state->val.str) {
     501         146 :                 if (0 < (state->val.len = state->input.str - state->val.str)) {
     502         145 :                         sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val), state->rfc5987 TSRMLS_CC);
     503             :                 }
     504         146 :                 state->rfc5987 = 0;
     505         237 :         } else if (state->arg.str) {
     506          78 :                 if (0 < (state->arg.len = state->input.str - state->arg.str)) {
     507             :                         zval *val, key;
     508          78 :                         zend_bool rfc5987 = 0;
     509             : 
     510          78 :                         INIT_PZVAL(&key);
     511          78 :                         ZVAL_NULL(&key);
     512          78 :                         sanitize_key(opts->flags, state->arg.str, state->arg.len, &key, &rfc5987 TSRMLS_CC);
     513          78 :                         state->rfc5987 = rfc5987;
     514          78 :                         if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) {
     515          76 :                                 MAKE_STD_ZVAL(val);
     516          76 :                                 ZVAL_TRUE(val);
     517             : 
     518          76 :                                 if (rfc5987) {
     519             :                                         zval **rfc;
     520             : 
     521           5 :                                         if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(state->current.args), ZEND_STRS("*rfc5987*"), (void *) &rfc)) {
     522           1 :                                                 zend_symtable_update(Z_ARRVAL_PP(rfc), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
     523             :                                         } else {
     524             :                                                 zval *tmp;
     525             : 
     526           4 :                                                 MAKE_STD_ZVAL(tmp);
     527           4 :                                                 array_init_size(tmp, 1);
     528           4 :                                                 zend_symtable_update(Z_ARRVAL_P(tmp), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
     529           4 :                                                 zend_symtable_update(Z_ARRVAL_PP(state->current.args), ZEND_STRS("*rfc5987*"), (void *) &tmp, sizeof(zval *), NULL);
     530             :                                         }
     531             :                                 } else {
     532          71 :                                         zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val);
     533             :                                 }
     534             :                         }
     535          78 :                         zval_dtor(&key);
     536             :                 }
     537         159 :         } else if (state->param.str) {
     538         158 :                 if (0 < (state->param.len = state->input.str - state->param.str)) {
     539             :                         zval *prm, *arg, *val, *key;
     540         157 :                         zend_bool rfc5987 = 0;
     541             : 
     542         157 :                         MAKE_STD_ZVAL(key);
     543         157 :                         ZVAL_NULL(key);
     544         157 :                         sanitize_key(opts->flags, state->param.str, state->param.len, key, &rfc5987 TSRMLS_CC);
     545         157 :                         state->rfc5987 = rfc5987;
     546         157 :                         if (Z_TYPE_P(key) != IS_STRING) {
     547          28 :                                 merge_param(params, key, &state->current.val, &state->current.args TSRMLS_CC);
     548         129 :                         } else if (Z_STRLEN_P(key)) {
     549         129 :                                 MAKE_STD_ZVAL(prm);
     550         129 :                                 array_init_size(prm, 2);
     551             : 
     552         129 :                                 MAKE_STD_ZVAL(val);
     553         129 :                                 if (opts->defval) {
     554          21 :                                         ZVAL_COPY_VALUE(val, opts->defval);
     555          21 :                                         zval_copy_ctor(val);
     556             :                                 } else {
     557         108 :                                         ZVAL_TRUE(val);
     558             :                                 }
     559         129 :                                 if (rfc5987 && (opts->flags & PHP_HTTP_PARAMS_RFC5987)) {
     560          13 :                                         zend_hash_update(Z_ARRVAL_P(prm), "*rfc5987*", sizeof("*rfc5987*"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
     561             :                                 } else {
     562         116 :                                         zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
     563             :                                 }
     564             : 
     565         129 :                                 MAKE_STD_ZVAL(arg);
     566         129 :                                 array_init_size(arg, 3);
     567         129 :                                 zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args);
     568             : 
     569         129 :                                 zend_symtable_update(params, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param);
     570             :                         }
     571         157 :                         zval_ptr_dtor(&key);
     572             :                 }
     573             :         }
     574         383 : }
     575             : 
     576        6044 : static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) {
     577        6044 :         return 0 < sep_len && chk_len >= sep_len && *chk_str == *sep_str && !memcmp(chk_str + 1, sep_str + 1, sep_len - 1);
     578             : }
     579             : 
     580        7038 : static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators)
     581             : {
     582        7038 :         php_http_params_token_t **sep = separators;
     583             : 
     584        7038 :         if (state->quotes || state->escape) {
     585         156 :                 return 0;
     586             :         }
     587             :         
     588       18727 :         if (sep) while (*sep) {
     589        6044 :                 if (check_str(state->input.str, state->input.len, (*sep)->str, (*sep)->len)) {
     590         313 :                         return (*sep)->len;
     591             :                 }
     592        5731 :                 ++sep;
     593             :         }
     594        6569 :         return 0;
     595             : }
     596             : 
     597         382 : 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)
     598             : {
     599             :         size_t sep_len;
     600             : 
     601         382 :         state->input.str += skip;
     602         382 :         state->input.len -= skip;
     603             : 
     604         764 :         while ( (param && (sep_len = check_sep(state, param)))
     605         382 :         ||              (arg && (sep_len = check_sep(state, arg)))
     606         382 :         ||              (val && (sep_len = check_sep(state, val)))
     607             :         ) {
     608           0 :                 state->input.str += sep_len;
     609           0 :                 state->input.len -= sep_len;
     610             :         }
     611         382 : }
     612             : 
     613          70 : HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts TSRMLS_DC)
     614             : {
     615          70 :         php_http_params_state_t state = {{NULL,0}, {NULL,0}, {NULL,0}, {NULL,0}, {NULL,NULL,NULL}, 0, 0};
     616             : 
     617          70 :         state.input.str = opts->input.str;
     618          70 :         state.input.len = opts->input.len;
     619             : 
     620          70 :         if (!params) {
     621           0 :                 ALLOC_HASHTABLE(params);
     622           0 :                 ZEND_INIT_SYMTABLE(params);
     623             :         }
     624             : 
     625        2402 :         while (state.input.len) {
     626        2262 :                 if (*state.input.str == '"' && !state.escape) {
     627          18 :                         state.quotes = !state.quotes;
     628             :                 } else {
     629        2244 :                         state.escape = (*state.input.str == '\\');
     630             :                 }
     631             :                 
     632        2262 :                 if (!state.param.str) {
     633             :                         /* initialize */
     634          69 :                         skip_sep(0, &state, opts->param, opts->arg, opts->val TSRMLS_CC);
     635          69 :                         state.param.str = state.input.str;
     636             :                 } else {
     637             :                         size_t sep_len;
     638             :                         /* are we at a param separator? */
     639        2193 :                         if (0 < (sep_len = check_sep(&state, opts->param))) {
     640          89 :                                 push_param(params, &state, opts TSRMLS_CC);
     641             : 
     642          89 :                                 skip_sep(sep_len, &state, opts->param, opts->arg, opts->val TSRMLS_CC);
     643             : 
     644             :                                 /* start off with a new param */
     645          89 :                                 state.param.str = state.input.str;
     646          89 :                                 state.param.len = 0;
     647          89 :                                 state.arg.str = NULL;
     648          89 :                                 state.arg.len = 0;
     649          89 :                                 state.val.str = NULL;
     650          89 :                                 state.val.len = 0;
     651             : 
     652          89 :                                 continue;
     653             : 
     654             :                         } else
     655             :                         /* are we at an arg separator? */
     656        2104 :                         if (0 < (sep_len = check_sep(&state, opts->arg))) {
     657          78 :                                 push_param(params, &state, opts TSRMLS_CC);
     658             : 
     659          78 :                                 skip_sep(sep_len, &state, NULL, opts->arg, opts->val TSRMLS_CC);
     660             : 
     661             :                                 /* continue with a new arg */
     662          78 :                                 state.arg.str = state.input.str;
     663          78 :                                 state.arg.len = 0;
     664          78 :                                 state.val.str = NULL;
     665          78 :                                 state.val.len = 0;
     666             : 
     667          78 :                                 continue;
     668             : 
     669             :                         } else
     670             :                         /* are we at a val separator? */
     671        2026 :                         if (0 < (sep_len = check_sep(&state, opts->val))) {
     672             :                                 /* only handle separator if we're not already reading in a val */
     673         146 :                                 if (!state.val.str) {
     674         146 :                                         push_param(params, &state, opts TSRMLS_CC);
     675             : 
     676         146 :                                         skip_sep(sep_len, &state, NULL, NULL, opts->val TSRMLS_CC);
     677             : 
     678         146 :                                         state.val.str = state.input.str;
     679         146 :                                         state.val.len = 0;
     680             : 
     681         146 :                                         continue;
     682             :                                 }
     683             :                         }
     684             :                 }
     685             :                 
     686        1949 :                 if (state.input.len) {
     687        1949 :                         ++state.input.str;
     688        1949 :                         --state.input.len;
     689             :                 }
     690             :         }
     691             :         /* finalize */
     692          70 :         push_param(params, &state, opts TSRMLS_CC);
     693             : 
     694          70 :         return params;
     695             : }
     696             : 
     697         182 : 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)
     698             : {
     699             :         char *str;
     700             :         size_t len;
     701             : 
     702         182 :         if (buf->used) {
     703         137 :                 php_http_buffer_append(buf, ass, asl);
     704             :         }
     705             : 
     706         182 :         prepare_key(flags, key_str, key_len, &str, &len TSRMLS_CC);
     707         182 :         php_http_buffer_append(buf, str, len);
     708         182 :         efree(str);
     709         182 : }
     710             : 
     711          11 : static inline void shift_rfc5987(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
     712             : {
     713          11 :         HashTable *ht = HASH_OF(zvalue);
     714             :         zval **zdata, *tmp;
     715          11 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
     716             : 
     717          11 :         if (SUCCESS == zend_hash_get_current_data(ht, (void *) &zdata)
     718          11 :         &&      HASH_KEY_NON_EXISTENT != (key.type = zend_hash_get_current_key_ex(ht, &key.str, &key.len, &key.num, key.dup, NULL))
     719             :         ) {
     720          11 :                 php_http_array_hashkey_stringify(&key);
     721          33 :                 php_http_buffer_appendf(buf, "*%.*sutf-8'%.*s'",
     722             :                                 (int) (vsl > INT_MAX ? INT_MAX : vsl), vss,
     723          22 :                                 (int) (key.len > INT_MAX ? INT_MAX : key.len), key.str);
     724          11 :                 php_http_array_hashkey_stringfree(&key);
     725             : 
     726          11 :                 tmp = php_http_zsep(1, IS_STRING, *zdata);
     727          11 :                 prepare_value(flags | PHP_HTTP_PARAMS_URLENCODED, tmp TSRMLS_CC);
     728          11 :                 php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
     729          11 :                 zval_ptr_dtor(&tmp);
     730             :         }
     731          11 : }
     732             : 
     733         169 : static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
     734             : {
     735         169 :         if (Z_TYPE_P(zvalue) != IS_BOOL) {
     736         150 :                 zval *tmp = php_http_zsep(1, IS_STRING, zvalue);
     737             : 
     738         150 :                 prepare_value(flags, tmp TSRMLS_CC);
     739         150 :                 php_http_buffer_append(buf, vss, vsl);
     740         150 :                 php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
     741             : 
     742         150 :                 zval_ptr_dtor(&tmp);
     743          19 :         } else if (!Z_BVAL_P(zvalue)) {
     744           3 :                 php_http_buffer_append(buf, vss, vsl);
     745           3 :                 php_http_buffer_appends(buf, "0");
     746             :         }
     747         169 : }
     748             : 
     749          24 : 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)
     750             : {
     751          31 :         if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
     752             :                 HashPosition pos;
     753           7 :                 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
     754             :                 zval **val;
     755           7 :                 zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*");
     756             : 
     757           7 :                 if (!rfc5987) {
     758           2 :                         shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
     759             :                 }
     760          16 :                 FOREACH_KEYVAL(pos, zvalue, key, val) {
     761             :                         /* did you mean recursion? */
     762           9 :                         php_http_array_hashkey_stringify(&key);
     763           9 :                         if (rfc5987 && (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT)) {
     764           7 :                                 shift_key(buf, key.str, key.len-1, ass, asl, flags TSRMLS_CC);
     765           7 :                                 shift_rfc5987(buf, *val, vss, vsl, flags TSRMLS_CC);
     766             :                         } else {
     767           2 :                                 shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC);
     768             :                         }
     769           9 :                         php_http_array_hashkey_stringfree(&key);
     770             :                 }
     771             :         } else {
     772          17 :                 shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
     773          17 :                 shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
     774             :         }
     775          24 : }
     776             : 
     777         117 : 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, zend_bool rfc5987 TSRMLS_DC)
     778             : {
     779         117 :         if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
     780             :                 /* treat as arguments, unless we care for dimensions or rfc5987 */
     781          76 :                 if (flags & PHP_HTTP_PARAMS_DIMENSION) {
     782          32 :                         php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len);
     783          32 :                         prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags TSRMLS_CC);
     784          32 :                         php_http_buffer_free(&keybuf);
     785           6 :                 } else if (rfc5987) {
     786           4 :                         shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
     787           4 :                         shift_rfc5987(buf, zvalue, vss, vsl, flags TSRMLS_CC);
     788             :                 } else {
     789           2 :                         shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags TSRMLS_CC);
     790             :                 }
     791             :         } else {
     792          79 :                 shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
     793          79 :                 shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
     794             :         }
     795         117 : }
     796             : 
     797          64 : 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)
     798             : {
     799             :         zval **zparam;
     800             :         HashPosition pos, pos1;
     801          64 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0), key1 = php_http_array_hashkey_init(0);
     802          64 :         zend_bool rfc5987 = 0;
     803             : 
     804          64 :         if (!buf) {
     805           0 :                 buf = php_http_buffer_init(NULL);
     806             :         }
     807             : 
     808         181 :         FOREACH_HASH_KEYVAL(pos, params, key, zparam) {
     809             :                 zval **zvalue, **zargs;
     810             : 
     811         117 :                 if (Z_TYPE_PP(zparam) != IS_ARRAY) {
     812          55 :                         zvalue = zparam;
     813             :                 } else {
     814          62 :                         if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("value"), (void *) &zvalue)) {
     815          36 :                                 if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("*rfc5987*"), (void *) &zvalue)) {
     816          32 :                                         zvalue = zparam;
     817             :                                 } else {
     818           4 :                                         rfc5987 = 1;
     819             :                                 }
     820             :                         }
     821             :                 }
     822             : 
     823         117 :                 php_http_array_hashkey_stringify(&key);
     824         117 :                 shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags, rfc5987 TSRMLS_CC);
     825         117 :                 php_http_array_hashkey_stringfree(&key);
     826             : 
     827         117 :                 if (Z_TYPE_PP(zparam) == IS_ARRAY && SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("arguments"), (void *) &zvalue)) {
     828          34 :                         if (zvalue == zparam) {
     829          32 :                                 continue;
     830             :                         }
     831           2 :                         zvalue = zparam;
     832             :                 }
     833             : 
     834          85 :                 if (Z_TYPE_PP(zvalue) == IS_ARRAY) {
     835          52 :                         FOREACH_KEYVAL(pos1, *zvalue, key1, zargs) {
     836          22 :                                 if (zvalue == zparam && key1.type == HASH_KEY_IS_STRING && !strcmp(key1.str, "value")) {
     837           2 :                                         continue;
     838             :                                 }
     839             : 
     840          20 :                                 php_http_array_hashkey_stringify(&key1);
     841          20 :                                 shift_arg(buf, key1.str, key1.len - 1, *zargs, ass, asl, vss, vsl, flags TSRMLS_CC);
     842          20 :                                 php_http_array_hashkey_stringfree(&key1);
     843             :                         }
     844             :                 }
     845             :         }
     846             : 
     847          64 :         php_http_buffer_shrink(buf);
     848          64 :         php_http_buffer_fix(buf);
     849             : 
     850          64 :         return buf;
     851             : }
     852             : 
     853          59 : php_http_params_token_t **php_http_params_separator_init(zval *zv TSRMLS_DC)
     854             : {
     855             :         zval **sep;
     856             :         HashPosition pos;
     857             :         php_http_params_token_t **ret, **tmp;
     858             : 
     859          59 :         if (!zv) {
     860           0 :                 return NULL;
     861             :         }
     862             : 
     863          59 :         zv = php_http_ztyp(IS_ARRAY, zv);
     864          59 :         ret = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zv)) + 1, sizeof(*ret));
     865             : 
     866          59 :         tmp = ret;
     867         119 :         FOREACH_VAL(pos, zv, sep) {
     868          60 :                 zval *zt = php_http_ztyp(IS_STRING, *sep);
     869             : 
     870          60 :                 if (Z_STRLEN_P(zt)) {
     871          57 :                         *tmp = emalloc(sizeof(**tmp));
     872          57 :                         (*tmp)->str = estrndup(Z_STRVAL_P(zt), (*tmp)->len = Z_STRLEN_P(zt));
     873          57 :                         ++tmp;
     874             :                 }
     875          60 :                 zval_ptr_dtor(&zt);
     876             :         }
     877          59 :         zval_ptr_dtor(&zv);
     878             : 
     879          59 :         *tmp = NULL;
     880          59 :         return ret;
     881             : }
     882             : 
     883          59 : void php_http_params_separator_free(php_http_params_token_t **separator)
     884             : {
     885          59 :         php_http_params_token_t **sep = separator;
     886          59 :         if (sep) {
     887         175 :                 while (*sep) {
     888          57 :                         PTR_FREE((*sep)->str);
     889          57 :                         efree(*sep);
     890          57 :                         ++sep;
     891             :                 }
     892          59 :                 efree(separator);
     893             :         }
     894          59 : }
     895             : 
     896             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams___construct, 0, 0, 0)
     897             :         ZEND_ARG_INFO(0, params)
     898             :         ZEND_ARG_INFO(0, param_sep)
     899             :         ZEND_ARG_INFO(0, arg_sep)
     900             :         ZEND_ARG_INFO(0, val_sep)
     901             :         ZEND_ARG_INFO(0, flags)
     902             : ZEND_END_ARG_INFO();
     903          22 : PHP_METHOD(HttpParams, __construct)
     904             : {
     905          22 :         zval *zcopy, *zparams = NULL, *param_sep = NULL, *arg_sep = NULL, *val_sep = NULL;
     906          22 :         long flags = PHP_HTTP_PARAMS_DEFAULT;
     907             :         zend_error_handling zeh;
     908             : 
     909          44 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!/z/z/z/l", &zparams, &param_sep, &arg_sep, &val_sep, &flags), invalid_arg, return);
     910             : 
     911          22 :         zend_replace_error_handling(EH_THROW, php_http_exception_runtime_class_entry, &zeh TSRMLS_CC);
     912             :         {
     913          22 :                 switch (ZEND_NUM_ARGS()) {
     914             :                         case 5:
     915           4 :                                 zend_update_property_long(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), flags TSRMLS_CC);
     916             :                                 /* no break */
     917             :                         case 4:
     918           6 :                                 zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), val_sep TSRMLS_CC);
     919             :                                 /* no break */
     920             :                         case 3:
     921           6 :                                 zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), arg_sep TSRMLS_CC);
     922             :                                 /* no break */
     923             :                         case 2:
     924           6 :                                 zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), param_sep TSRMLS_CC);
     925             :                                 /* no break */
     926             :                 }
     927             : 
     928          22 :                 if (zparams) {
     929          18 :                         switch (Z_TYPE_P(zparams)) {
     930             :                                 case IS_OBJECT:
     931             :                                 case IS_ARRAY:
     932           3 :                                         zcopy = php_http_zsep(1, IS_ARRAY, zparams);
     933           3 :                                         zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zcopy TSRMLS_CC);
     934           3 :                                         zval_ptr_dtor(&zcopy);
     935           3 :                                         break;
     936             :                                 default:
     937          15 :                                         zcopy = php_http_ztyp(IS_STRING, zparams);
     938          15 :                                         if (Z_STRLEN_P(zcopy)) {
     939          75 :                                                 php_http_params_opts_t opts = {
     940          30 :                                                         {Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy)},
     941          15 :                                                         php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC) TSRMLS_CC),
     942          15 :                                                         php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC) TSRMLS_CC),
     943          15 :                                                         php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC) TSRMLS_CC),
     944             :                                                         NULL, flags
     945             :                                                 };
     946             : 
     947          15 :                                                 MAKE_STD_ZVAL(zparams);
     948          15 :                                                 array_init(zparams);
     949          15 :                                                 php_http_params_parse(Z_ARRVAL_P(zparams), &opts TSRMLS_CC);
     950          15 :                                                 zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC);
     951          15 :                                                 zval_ptr_dtor(&zparams);
     952             : 
     953          15 :                                                 php_http_params_separator_free(opts.param);
     954          15 :                                                 php_http_params_separator_free(opts.arg);
     955          15 :                                                 php_http_params_separator_free(opts.val);
     956             :                                         }
     957          15 :                                         zval_ptr_dtor(&zcopy);
     958          15 :                                         break;
     959             :                         }
     960             :                 } else {
     961           4 :                         MAKE_STD_ZVAL(zparams);
     962           4 :                         array_init(zparams);
     963           4 :                         zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC);
     964           4 :                         zval_ptr_dtor(&zparams);
     965             :                 }
     966             :         }
     967          22 :         zend_restore_error_handling(&zeh TSRMLS_CC);
     968             : }
     969             : 
     970             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toArray, 0, 0, 0)
     971             : ZEND_END_ARG_INFO();
     972           4 : PHP_METHOD(HttpParams, toArray)
     973             : {
     974             :         zval *zparams;
     975             : 
     976           4 :         if (SUCCESS != zend_parse_parameters_none()) {
     977           0 :                 return;
     978             :         }
     979           4 :         zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC);
     980           4 :         RETURN_ZVAL(zparams, 1, 0);
     981             : }
     982             : 
     983             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toString, 0, 0, 0)
     984             : ZEND_END_ARG_INFO();
     985          19 : PHP_METHOD(HttpParams, toString)
     986             : {
     987             :         zval **tmp, *zparams, *zpsep, *zasep, *zvsep, *zflags;
     988             :         php_http_buffer_t buf;
     989             : 
     990          19 :         zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC));
     991          19 :         zflags = php_http_ztyp(IS_LONG, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), 0 TSRMLS_CC));
     992             : 
     993          19 :         zpsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0 TSRMLS_CC);
     994          19 :         if (Z_TYPE_P(zpsep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zpsep), (void *) &tmp)) {
     995           1 :                 zpsep = php_http_ztyp(IS_STRING, *tmp);
     996             :         } else {
     997          18 :                 zpsep = php_http_ztyp(IS_STRING, zpsep);
     998             :         }
     999          19 :         zasep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0 TSRMLS_CC);
    1000          19 :         if (Z_TYPE_P(zasep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zasep), (void *) &tmp)) {
    1001           0 :                 zasep = php_http_ztyp(IS_STRING, *tmp);
    1002             :         } else {
    1003          19 :                 zasep = php_http_ztyp(IS_STRING, zasep);
    1004             :         }
    1005          19 :         zvsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0 TSRMLS_CC);
    1006          19 :         if (Z_TYPE_P(zvsep) == IS_ARRAY && SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zvsep), (void *) &tmp)) {
    1007           0 :                 zvsep = php_http_ztyp(IS_STRING, *tmp);
    1008             :         } else {
    1009          19 :                 zvsep = php_http_ztyp(IS_STRING, zvsep);
    1010             :         }
    1011             : 
    1012          19 :         php_http_buffer_init(&buf);
    1013          19 :         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);
    1014             : 
    1015          19 :         zval_ptr_dtor(&zparams);
    1016          19 :         zval_ptr_dtor(&zpsep);
    1017          19 :         zval_ptr_dtor(&zasep);
    1018          19 :         zval_ptr_dtor(&zvsep);
    1019          19 :         zval_ptr_dtor(&zflags);
    1020             : 
    1021          19 :         RETVAL_PHP_HTTP_BUFFER_VAL(&buf);
    1022          19 : }
    1023             : 
    1024             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetExists, 0, 0, 1)
    1025             :         ZEND_ARG_INFO(0, name)
    1026             : ZEND_END_ARG_INFO();
    1027           4 : PHP_METHOD(HttpParams, offsetExists)
    1028             : {
    1029             :         char *name_str;
    1030             :         int name_len;
    1031             :         zval **zparam, *zparams;
    1032             : 
    1033           4 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) {
    1034           4 :                 return;
    1035             :         }
    1036             : 
    1037           4 :         zparams = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC));
    1038             : 
    1039           4 :         if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) {
    1040           2 :                 RETVAL_BOOL(Z_TYPE_PP(zparam) != IS_NULL);
    1041             :         } else {
    1042           2 :                 RETVAL_FALSE;
    1043             :         }
    1044           4 :         zval_ptr_dtor(&zparams);
    1045             : }
    1046             : 
    1047             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetGet, 0, 0, 1)
    1048             :         ZEND_ARG_INFO(0, name)
    1049             : ZEND_END_ARG_INFO();
    1050          20 : PHP_METHOD(HttpParams, offsetGet)
    1051             : {
    1052             :         char *name_str;
    1053             :         int name_len;
    1054             :         zval **zparam, *zparams;
    1055             : 
    1056          20 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) {
    1057          20 :                 return;
    1058             :         }
    1059             : 
    1060          20 :         zparams = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC));
    1061             : 
    1062          20 :         if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) {
    1063          20 :                 RETVAL_ZVAL(*zparam, 1, 0);
    1064             :         }
    1065             : 
    1066          20 :         zval_ptr_dtor(&zparams);
    1067             : }
    1068             : 
    1069             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetUnset, 0, 0, 1)
    1070             :         ZEND_ARG_INFO(0, name)
    1071             : ZEND_END_ARG_INFO();
    1072           1 : PHP_METHOD(HttpParams, offsetUnset)
    1073             : {
    1074             :         char *name_str;
    1075             :         int name_len;
    1076             :         zval *zparams;
    1077             : 
    1078           1 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len)) {
    1079           1 :                 return;
    1080             :         }
    1081             : 
    1082           1 :         zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC));
    1083             : 
    1084           1 :         zend_symtable_del(Z_ARRVAL_P(zparams), name_str, name_len + 1);
    1085           1 :         zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC);
    1086             : 
    1087           1 :         zval_ptr_dtor(&zparams);
    1088             : }
    1089             : 
    1090             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetSet, 0, 0, 2)
    1091             :         ZEND_ARG_INFO(0, name)
    1092             :         ZEND_ARG_INFO(0, value)
    1093             : ZEND_END_ARG_INFO();
    1094           5 : PHP_METHOD(HttpParams, offsetSet)
    1095             : {
    1096             :         zval *nvalue;
    1097             :         char *name_str;
    1098             :         int name_len;
    1099             :         zval **zparam, *zparams;
    1100             : 
    1101           5 :         if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &nvalue)) {
    1102           5 :                 return;
    1103             :         }
    1104             : 
    1105           5 :         zparams = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0 TSRMLS_CC));
    1106             : 
    1107           5 :         if (name_len) {
    1108           4 :                 if (Z_TYPE_P(nvalue) == IS_ARRAY) {
    1109             :                         zval *new_zparam;
    1110             : 
    1111           2 :                         if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) {
    1112           1 :                                 new_zparam = php_http_zsep(1, IS_ARRAY, *zparam);
    1113           1 :                                 array_join(Z_ARRVAL_P(nvalue), Z_ARRVAL_P(new_zparam), 0, 0);
    1114             :                         } else {
    1115           1 :                                 new_zparam = nvalue;
    1116           1 :                                 Z_ADDREF_P(new_zparam);
    1117             :                         }
    1118           2 :                         add_assoc_zval_ex(zparams, name_str, name_len + 1, new_zparam);
    1119             :                 } else {
    1120             :                         zval *tmp;
    1121             : 
    1122           2 :                         if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(zparams), name_str, name_len + 1, (void *) &zparam)) {
    1123           1 :                                 tmp = php_http_zsep(1, IS_ARRAY, *zparam);
    1124             :                         } else {
    1125           1 :                                 MAKE_STD_ZVAL(tmp);
    1126           1 :                                 array_init(tmp);
    1127             :                         }
    1128             : 
    1129           2 :                         Z_ADDREF_P(nvalue);
    1130           2 :                         add_assoc_zval_ex(tmp, ZEND_STRS("value"), nvalue);
    1131           2 :                         add_assoc_zval_ex(zparams, name_str, name_len + 1, tmp);
    1132             :                 }
    1133             :         } else {
    1134           1 :                 zval *tmp = php_http_ztyp(IS_STRING, nvalue), *arr;
    1135             : 
    1136           1 :                 MAKE_STD_ZVAL(arr);
    1137           1 :                 array_init(arr);
    1138           1 :                 add_assoc_bool_ex(arr, ZEND_STRS("value"), 1);
    1139           1 :                 add_assoc_zval_ex(zparams, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp) + 1, arr);
    1140           1 :                 zval_ptr_dtor(&tmp);
    1141             :         }
    1142             : 
    1143           5 :         zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams TSRMLS_CC);
    1144           5 :         zval_ptr_dtor(&zparams);
    1145             : }
    1146             : 
    1147             : static zend_function_entry php_http_params_methods[] = {
    1148             :         PHP_ME(HttpParams, __construct,   ai_HttpParams___construct,   ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
    1149             : 
    1150             :         PHP_ME(HttpParams, toArray,       ai_HttpParams_toArray,       ZEND_ACC_PUBLIC)
    1151             :         PHP_ME(HttpParams, toString,      ai_HttpParams_toString,      ZEND_ACC_PUBLIC)
    1152             :         ZEND_MALIAS(HttpParams, __toString, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC)
    1153             : 
    1154             :         PHP_ME(HttpParams, offsetExists,  ai_HttpParams_offsetExists,  ZEND_ACC_PUBLIC)
    1155             :         PHP_ME(HttpParams, offsetUnset,   ai_HttpParams_offsetUnset,   ZEND_ACC_PUBLIC)
    1156             :         PHP_ME(HttpParams, offsetSet,     ai_HttpParams_offsetSet,     ZEND_ACC_PUBLIC)
    1157             :         PHP_ME(HttpParams, offsetGet,     ai_HttpParams_offsetGet,     ZEND_ACC_PUBLIC)
    1158             : 
    1159             :         EMPTY_FUNCTION_ENTRY
    1160             : };
    1161             : 
    1162             : zend_class_entry *php_http_params_class_entry;
    1163             : 
    1164         374 : PHP_MINIT_FUNCTION(http_params)
    1165             : {
    1166         374 :         zend_class_entry ce = {0};
    1167             : 
    1168         374 :         INIT_NS_CLASS_ENTRY(ce, "http", "Params", php_http_params_methods);
    1169         374 :         php_http_params_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
    1170         374 :         php_http_params_class_entry->create_object = php_http_params_object_new;
    1171         374 :         zend_class_implements(php_http_params_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess);
    1172             : 
    1173         374 :         zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(",") TSRMLS_CC);
    1174         374 :         zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";") TSRMLS_CC);
    1175         374 :         zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("=") TSRMLS_CC);
    1176         374 :         zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("") TSRMLS_CC);
    1177             : 
    1178         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW TSRMLS_CC);
    1179         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED TSRMLS_CC);
    1180         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED TSRMLS_CC);
    1181         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION TSRMLS_CC);
    1182         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987 TSRMLS_CC);
    1183         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC);
    1184         374 :         zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY TSRMLS_CC);
    1185             : 
    1186         374 :         zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC TSRMLS_CC);
    1187         374 :         zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC TSRMLS_CC);
    1188         374 :         zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC TSRMLS_CC);
    1189         374 :         zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC TSRMLS_CC);
    1190         374 :         zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC TSRMLS_CC);
    1191             : 
    1192         374 :         return SUCCESS;
    1193             : }
    1194             : 
    1195             : /*
    1196             :  * Local variables:
    1197             :  * tab-width: 4
    1198             :  * c-basic-offset: 4
    1199             :  * End:
    1200             :  * vim600: noet sw=4 ts=4 fdm=marker
    1201             :  * vim<600: noet sw=4 ts=4
    1202             :  */
    1203             : 

Generated by: LCOV version 1.11