http.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 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. /* $Id$ */
  19. #include "php_http.h"
  20. #include "php_ini.h"
  21. #include "url.h"
  22. #define URL_DEFAULT_ARG_SEP "&"
  23. /* {{{ php_url_encode_hash */
  24. PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
  25. const char *num_prefix, int num_prefix_len,
  26. const char *key_prefix, int key_prefix_len,
  27. const char *key_suffix, int key_suffix_len,
  28. zval *type, char *arg_sep, int enc_type TSRMLS_DC)
  29. {
  30. char *key = NULL;
  31. char *ekey, *newprefix, *p;
  32. int arg_sep_len, ekey_len, key_type, newprefix_len;
  33. uint key_len;
  34. ulong idx;
  35. zval **zdata = NULL, *copyzval;
  36. if (!ht) {
  37. return FAILURE;
  38. }
  39. if (ht->nApplyCount > 0) {
  40. /* Prevent recursion */
  41. return SUCCESS;
  42. }
  43. if (!arg_sep) {
  44. arg_sep = INI_STR("arg_separator.output");
  45. if (!arg_sep || !strlen(arg_sep)) {
  46. arg_sep = URL_DEFAULT_ARG_SEP;
  47. }
  48. }
  49. arg_sep_len = strlen(arg_sep);
  50. for (zend_hash_internal_pointer_reset(ht);
  51. (key_type = zend_hash_get_current_key_ex(ht, &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTENT;
  52. zend_hash_move_forward(ht)
  53. ) {
  54. if (key_type == HASH_KEY_IS_STRING && key_len && key[key_len-1] == '\0') {
  55. /* We don't want that trailing NULL */
  56. key_len -= 1;
  57. }
  58. /* handling for private & protected object properties */
  59. if (key && *key == '\0' && type != NULL) {
  60. const char *tmp;
  61. zend_object *zobj = zend_objects_get_address(type TSRMLS_CC);
  62. if (zend_check_property_access(zobj, key, key_len TSRMLS_CC) != SUCCESS) {
  63. /* private or protected property access outside of the class */
  64. continue;
  65. }
  66. zend_unmangle_property_name_ex(key, key_len, &tmp, (const char**)&key, &key_len);
  67. }
  68. if (zend_hash_get_current_data_ex(ht, (void **)&zdata, NULL) == FAILURE || !zdata || !(*zdata)) {
  69. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error traversing form data array");
  70. return FAILURE;
  71. }
  72. if (Z_TYPE_PP(zdata) == IS_ARRAY || Z_TYPE_PP(zdata) == IS_OBJECT) {
  73. if (key_type == HASH_KEY_IS_STRING) {
  74. if (enc_type == PHP_QUERY_RFC3986) {
  75. ekey = php_raw_url_encode(key, key_len, &ekey_len);
  76. } else {
  77. ekey = php_url_encode(key, key_len, &ekey_len);
  78. }
  79. newprefix_len = key_suffix_len + ekey_len + key_prefix_len + 3 /* %5B */;
  80. newprefix = emalloc(newprefix_len + 1);
  81. p = newprefix;
  82. if (key_prefix) {
  83. memcpy(p, key_prefix, key_prefix_len);
  84. p += key_prefix_len;
  85. }
  86. memcpy(p, ekey, ekey_len);
  87. p += ekey_len;
  88. efree(ekey);
  89. if (key_suffix) {
  90. memcpy(p, key_suffix, key_suffix_len);
  91. p += key_suffix_len;
  92. }
  93. *(p++) = '%';
  94. *(p++) = '5';
  95. *(p++) = 'B';
  96. *p = '\0';
  97. } else {
  98. /* Is an integer key */
  99. ekey_len = spprintf(&ekey, 0, "%ld", 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. ht->nApplyCount++;
  122. php_url_encode_hash_ex(HASH_OF(*zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_PP(zdata) == IS_OBJECT ? *zdata : NULL), arg_sep, enc_type TSRMLS_CC);
  123. ht->nApplyCount--;
  124. efree(newprefix);
  125. } else if (Z_TYPE_PP(zdata) == IS_NULL || Z_TYPE_PP(zdata) == IS_RESOURCE) {
  126. /* Skip these types */
  127. continue;
  128. } else {
  129. if (formstr->len) {
  130. smart_str_appendl(formstr, arg_sep, arg_sep_len);
  131. }
  132. /* Simple key=value */
  133. smart_str_appendl(formstr, key_prefix, key_prefix_len);
  134. if (key_type == HASH_KEY_IS_STRING) {
  135. if (enc_type == PHP_QUERY_RFC3986) {
  136. ekey = php_raw_url_encode(key, key_len, &ekey_len);
  137. } else {
  138. ekey = php_url_encode(key, key_len, &ekey_len);
  139. }
  140. smart_str_appendl(formstr, ekey, ekey_len);
  141. efree(ekey);
  142. } else {
  143. /* Numeric key */
  144. if (num_prefix) {
  145. smart_str_appendl(formstr, num_prefix, num_prefix_len);
  146. }
  147. ekey_len = spprintf(&ekey, 0, "%ld", idx);
  148. smart_str_appendl(formstr, ekey, ekey_len);
  149. efree(ekey);
  150. }
  151. smart_str_appendl(formstr, key_suffix, key_suffix_len);
  152. smart_str_appendl(formstr, "=", 1);
  153. switch (Z_TYPE_PP(zdata)) {
  154. case IS_STRING:
  155. if (enc_type == PHP_QUERY_RFC3986) {
  156. ekey = php_raw_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len);
  157. } else {
  158. ekey = php_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len);
  159. }
  160. break;
  161. case IS_LONG:
  162. case IS_BOOL:
  163. ekey_len = spprintf(&ekey, 0, "%ld", Z_LVAL_PP(zdata));
  164. break;
  165. case IS_DOUBLE:
  166. ekey_len = spprintf(&ekey, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(zdata));
  167. break;
  168. default:
  169. /* fall back on convert to string */
  170. MAKE_STD_ZVAL(copyzval);
  171. *copyzval = **zdata;
  172. zval_copy_ctor(copyzval);
  173. convert_to_string_ex(&copyzval);
  174. if (enc_type == PHP_QUERY_RFC3986) {
  175. ekey = php_raw_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len);
  176. } else {
  177. ekey = php_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len);
  178. }
  179. zval_ptr_dtor(&copyzval);
  180. }
  181. smart_str_appendl(formstr, ekey, ekey_len);
  182. efree(ekey);
  183. }
  184. }
  185. return SUCCESS;
  186. }
  187. /* }}} */
  188. /* {{{ proto string http_build_query(mixed formdata [, string prefix [, string arg_separator [, int enc_type]]])
  189. Generates a form-encoded query string from an associative array or object. */
  190. PHP_FUNCTION(http_build_query)
  191. {
  192. zval *formdata;
  193. char *prefix = NULL, *arg_sep=NULL;
  194. int arg_sep_len = 0, prefix_len = 0;
  195. smart_str formstr = {0};
  196. long enc_type = PHP_QUERY_RFC1738;
  197. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ssl", &formdata, &prefix, &prefix_len, &arg_sep, &arg_sep_len, &enc_type) != SUCCESS) {
  198. RETURN_FALSE;
  199. }
  200. if (Z_TYPE_P(formdata) != IS_ARRAY && Z_TYPE_P(formdata) != IS_OBJECT) {
  201. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter 1 expected to be Array or Object. Incorrect value given");
  202. RETURN_FALSE;
  203. }
  204. if (php_url_encode_hash_ex(HASH_OF(formdata), &formstr, prefix, prefix_len, NULL, 0, NULL, 0, (Z_TYPE_P(formdata) == IS_OBJECT ? formdata : NULL), arg_sep, enc_type TSRMLS_CC) == FAILURE) {
  205. if (formstr.c) {
  206. efree(formstr.c);
  207. }
  208. RETURN_FALSE;
  209. }
  210. if (!formstr.c) {
  211. RETURN_EMPTY_STRING();
  212. }
  213. smart_str_0(&formstr);
  214. RETURN_STRINGL(formstr.c, formstr.len, 0);
  215. }
  216. /* }}} */
  217. /*
  218. * Local variables:
  219. * tab-width: 4
  220. * c-basic-offset: 4
  221. * End:
  222. * vim600: sw=4 ts=4 fdm=marker
  223. * vim<600: sw=4 ts=4
  224. */