http.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Sara Golemon <pollita@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php_http.h"
  17. #include "php_ini.h"
  18. #include "url.h"
  19. #define URL_DEFAULT_ARG_SEP "&"
  20. /* {{{ php_url_encode_hash */
  21. PHPAPI void php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
  22. const char *num_prefix, size_t num_prefix_len,
  23. const char *key_prefix, size_t key_prefix_len,
  24. const char *key_suffix, size_t key_suffix_len,
  25. zval *type, const char *arg_sep, int enc_type)
  26. {
  27. zend_string *key = NULL;
  28. char *newprefix, *p;
  29. const char *prop_name;
  30. size_t arg_sep_len, newprefix_len, prop_len;
  31. zend_ulong idx;
  32. zval *zdata = NULL;
  33. ZEND_ASSERT(ht);
  34. if (GC_IS_RECURSIVE(ht)) {
  35. /* Prevent recursion */
  36. return;
  37. }
  38. if (!arg_sep) {
  39. arg_sep = INI_STR("arg_separator.output");
  40. if (!arg_sep || !strlen(arg_sep)) {
  41. arg_sep = URL_DEFAULT_ARG_SEP;
  42. }
  43. }
  44. arg_sep_len = strlen(arg_sep);
  45. ZEND_HASH_FOREACH_KEY_VAL(ht, idx, key, zdata) {
  46. bool is_dynamic = 1;
  47. if (Z_TYPE_P(zdata) == IS_INDIRECT) {
  48. zdata = Z_INDIRECT_P(zdata);
  49. if (Z_ISUNDEF_P(zdata)) {
  50. continue;
  51. }
  52. is_dynamic = 0;
  53. }
  54. /* handling for private & protected object properties */
  55. if (key) {
  56. prop_name = ZSTR_VAL(key);
  57. prop_len = ZSTR_LEN(key);
  58. if (type != NULL && zend_check_property_access(Z_OBJ_P(type), key, is_dynamic) != SUCCESS) {
  59. /* property not visible in this scope */
  60. continue;
  61. }
  62. if (ZSTR_VAL(key)[0] == '\0' && type != NULL) {
  63. const char *tmp;
  64. zend_unmangle_property_name_ex(key, &tmp, &prop_name, &prop_len);
  65. } else {
  66. prop_name = ZSTR_VAL(key);
  67. prop_len = ZSTR_LEN(key);
  68. }
  69. } else {
  70. prop_name = NULL;
  71. prop_len = 0;
  72. }
  73. ZVAL_DEREF(zdata);
  74. if (Z_TYPE_P(zdata) == IS_ARRAY || Z_TYPE_P(zdata) == IS_OBJECT) {
  75. if (key) {
  76. zend_string *ekey;
  77. if (enc_type == PHP_QUERY_RFC3986) {
  78. ekey = php_raw_url_encode(prop_name, prop_len);
  79. } else {
  80. ekey = php_url_encode(prop_name, prop_len);
  81. }
  82. newprefix_len = key_suffix_len + ZSTR_LEN(ekey) + key_prefix_len + 3 /* %5B */;
  83. newprefix = emalloc(newprefix_len + 1);
  84. p = newprefix;
  85. if (key_prefix) {
  86. memcpy(p, key_prefix, key_prefix_len);
  87. p += key_prefix_len;
  88. }
  89. memcpy(p, ZSTR_VAL(ekey), ZSTR_LEN(ekey));
  90. p += ZSTR_LEN(ekey);
  91. zend_string_free(ekey);
  92. if (key_suffix) {
  93. memcpy(p, key_suffix, key_suffix_len);
  94. p += key_suffix_len;
  95. }
  96. *(p++) = '%';
  97. *(p++) = '5';
  98. *(p++) = 'B';
  99. *p = '\0';
  100. } else {
  101. char *ekey;
  102. size_t ekey_len;
  103. /* Is an integer key */
  104. ekey_len = spprintf(&ekey, 0, ZEND_LONG_FMT, idx);
  105. newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 3 /* %5B */;
  106. newprefix = emalloc(newprefix_len + 1);
  107. p = newprefix;
  108. if (key_prefix) {
  109. memcpy(p, key_prefix, key_prefix_len);
  110. p += key_prefix_len;
  111. }
  112. if (num_prefix) {
  113. memcpy(p, num_prefix, num_prefix_len);
  114. p += num_prefix_len;
  115. }
  116. memcpy(p, ekey, ekey_len);
  117. p += ekey_len;
  118. efree(ekey);
  119. if (key_suffix) {
  120. memcpy(p, key_suffix, key_suffix_len);
  121. p += key_suffix_len;
  122. }
  123. *(p++) = '%';
  124. *(p++) = '5';
  125. *(p++) = 'B';
  126. *p = '\0';
  127. }
  128. GC_TRY_PROTECT_RECURSION(ht);
  129. php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type);
  130. GC_TRY_UNPROTECT_RECURSION(ht);
  131. efree(newprefix);
  132. } else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) {
  133. /* Skip these types */
  134. continue;
  135. } else {
  136. if (formstr->s) {
  137. smart_str_appendl(formstr, arg_sep, arg_sep_len);
  138. }
  139. /* Simple key=value */
  140. if (key_prefix) {
  141. smart_str_appendl(formstr, key_prefix, key_prefix_len);
  142. }
  143. if (key) {
  144. zend_string *ekey;
  145. if (enc_type == PHP_QUERY_RFC3986) {
  146. ekey = php_raw_url_encode(prop_name, prop_len);
  147. } else {
  148. ekey = php_url_encode(prop_name, prop_len);
  149. }
  150. smart_str_append(formstr, ekey);
  151. zend_string_free(ekey);
  152. } else {
  153. /* Numeric key */
  154. if (num_prefix) {
  155. smart_str_appendl(formstr, num_prefix, num_prefix_len);
  156. }
  157. smart_str_append_long(formstr, idx);
  158. }
  159. if (key_suffix) {
  160. smart_str_appendl(formstr, key_suffix, key_suffix_len);
  161. }
  162. smart_str_appendl(formstr, "=", 1);
  163. switch (Z_TYPE_P(zdata)) {
  164. case IS_STRING: {
  165. zend_string *ekey;
  166. if (enc_type == PHP_QUERY_RFC3986) {
  167. ekey = php_raw_url_encode(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
  168. } else {
  169. ekey = php_url_encode(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata));
  170. }
  171. smart_str_append(formstr, ekey);
  172. zend_string_free(ekey);
  173. }
  174. break;
  175. case IS_LONG:
  176. smart_str_append_long(formstr, Z_LVAL_P(zdata));
  177. break;
  178. case IS_FALSE:
  179. smart_str_appendl(formstr, "0", sizeof("0")-1);
  180. break;
  181. case IS_TRUE:
  182. smart_str_appendl(formstr, "1", sizeof("1")-1);
  183. break;
  184. default:
  185. {
  186. zend_string *ekey;
  187. zend_string *tmp;
  188. zend_string *str= zval_get_tmp_string(zdata, &tmp);
  189. if (enc_type == PHP_QUERY_RFC3986) {
  190. ekey = php_raw_url_encode(ZSTR_VAL(str), ZSTR_LEN(str));
  191. } else {
  192. ekey = php_url_encode(ZSTR_VAL(str), ZSTR_LEN(str));
  193. }
  194. smart_str_append(formstr, ekey);
  195. zend_tmp_string_release(tmp);
  196. zend_string_free(ekey);
  197. }
  198. }
  199. }
  200. } ZEND_HASH_FOREACH_END();
  201. }
  202. /* }}} */
  203. /* {{{ Generates a form-encoded query string from an associative array or object. */
  204. PHP_FUNCTION(http_build_query)
  205. {
  206. zval *formdata;
  207. char *prefix = NULL, *arg_sep=NULL;
  208. size_t arg_sep_len = 0, prefix_len = 0;
  209. smart_str formstr = {0};
  210. zend_long enc_type = PHP_QUERY_RFC1738;
  211. ZEND_PARSE_PARAMETERS_START(1, 4)
  212. Z_PARAM_ARRAY_OR_OBJECT(formdata)
  213. Z_PARAM_OPTIONAL
  214. Z_PARAM_STRING(prefix, prefix_len)
  215. Z_PARAM_STRING_OR_NULL(arg_sep, arg_sep_len)
  216. Z_PARAM_LONG(enc_type)
  217. ZEND_PARSE_PARAMETERS_END();
  218. php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, (int)enc_type);
  219. if (!formstr.s) {
  220. RETURN_EMPTY_STRING();
  221. }
  222. smart_str_0(&formstr);
  223. RETURN_NEW_STR(formstr.s);
  224. }
  225. /* }}} */