http.c 7.5 KB

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