mb_gpc.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. | Author: Rui Hirokawa <hirokawa@php.net> |
  14. | Moriyoshi Koizumi <moriyoshi@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. /* {{{ includes */
  18. #include "php.h"
  19. #include "php_ini.h"
  20. #include "php_variables.h"
  21. #include "libmbfl/mbfl/mbfilter_pass.h"
  22. #include "mbstring.h"
  23. #include "ext/standard/php_string.h"
  24. #include "ext/standard/php_mail.h"
  25. #include "ext/standard/url.h"
  26. #include "main/php_output.h"
  27. #include "ext/standard/info.h"
  28. #include "php_variables.h"
  29. #include "php_globals.h"
  30. #include "rfc1867.h"
  31. #include "php_content_types.h"
  32. #include "SAPI.h"
  33. #include "TSRM.h"
  34. #include "mb_gpc.h"
  35. /* }}} */
  36. ZEND_EXTERN_MODULE_GLOBALS(mbstring)
  37. /* {{{ MBSTRING_API SAPI_TREAT_DATA_FUNC(mbstr_treat_data)
  38. * http input processing */
  39. MBSTRING_API SAPI_TREAT_DATA_FUNC(mbstr_treat_data)
  40. {
  41. char *res = NULL, *separator=NULL;
  42. const char *c_var;
  43. zval v_array;
  44. int free_buffer=0;
  45. const mbfl_encoding *detected;
  46. php_mb_encoding_handler_info_t info;
  47. if (!MBSTRG(encoding_translation)) {
  48. php_default_treat_data(arg, str, destArray);
  49. return;
  50. }
  51. switch (arg) {
  52. case PARSE_POST:
  53. case PARSE_GET:
  54. case PARSE_COOKIE:
  55. array_init(&v_array);
  56. switch (arg) {
  57. case PARSE_POST:
  58. ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_POST], &v_array);
  59. break;
  60. case PARSE_GET:
  61. ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_GET], &v_array);
  62. break;
  63. case PARSE_COOKIE:
  64. ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_COOKIE], &v_array);
  65. break;
  66. }
  67. break;
  68. default:
  69. ZVAL_COPY_VALUE(&v_array, destArray);
  70. break;
  71. }
  72. switch (arg) {
  73. case PARSE_POST:
  74. sapi_handle_post(&v_array);
  75. return;
  76. case PARSE_GET: /* GET data */
  77. c_var = SG(request_info).query_string;
  78. if (c_var && *c_var) {
  79. res = (char *) estrdup(c_var);
  80. free_buffer = 1;
  81. }
  82. break;
  83. case PARSE_COOKIE: /* Cookie data */
  84. c_var = SG(request_info).cookie_data;
  85. if (c_var && *c_var) {
  86. res = (char *) estrdup(c_var);
  87. free_buffer = 1;
  88. }
  89. break;
  90. case PARSE_STRING: /* String data */
  91. res = str;
  92. free_buffer = 1;
  93. break;
  94. }
  95. if (!res) {
  96. return;
  97. }
  98. switch (arg) {
  99. case PARSE_POST:
  100. case PARSE_GET:
  101. case PARSE_STRING:
  102. separator = (char *) estrdup(PG(arg_separator).input);
  103. break;
  104. case PARSE_COOKIE:
  105. separator = ";\0";
  106. break;
  107. }
  108. switch (arg) {
  109. case PARSE_POST:
  110. MBSTRG(http_input_identify_post) = NULL;
  111. break;
  112. case PARSE_GET:
  113. MBSTRG(http_input_identify_get) = NULL;
  114. break;
  115. case PARSE_COOKIE:
  116. MBSTRG(http_input_identify_cookie) = NULL;
  117. break;
  118. case PARSE_STRING:
  119. MBSTRG(http_input_identify_string) = NULL;
  120. break;
  121. }
  122. info.data_type = arg;
  123. info.separator = separator;
  124. info.report_errors = 0;
  125. info.to_encoding = MBSTRG(internal_encoding);
  126. info.to_language = MBSTRG(language);
  127. info.from_encodings = MBSTRG(http_input_list);
  128. info.num_from_encodings = MBSTRG(http_input_list_size);
  129. info.from_language = MBSTRG(language);
  130. MBSTRG(illegalchars) = 0;
  131. detected = _php_mb_encoding_handler_ex(&info, &v_array, res);
  132. MBSTRG(http_input_identify) = detected;
  133. if (detected) {
  134. switch(arg){
  135. case PARSE_POST:
  136. MBSTRG(http_input_identify_post) = detected;
  137. break;
  138. case PARSE_GET:
  139. MBSTRG(http_input_identify_get) = detected;
  140. break;
  141. case PARSE_COOKIE:
  142. MBSTRG(http_input_identify_cookie) = detected;
  143. break;
  144. case PARSE_STRING:
  145. MBSTRG(http_input_identify_string) = detected;
  146. break;
  147. }
  148. }
  149. if (arg != PARSE_COOKIE) {
  150. efree(separator);
  151. }
  152. if (free_buffer) {
  153. efree(res);
  154. }
  155. }
  156. /* }}} */
  157. /* {{{ mbfl_no_encoding _php_mb_encoding_handler_ex() */
  158. const mbfl_encoding *_php_mb_encoding_handler_ex(const php_mb_encoding_handler_info_t *info, zval *arg, char *res)
  159. {
  160. char *var, *val;
  161. const char *s1, *s2;
  162. char *strtok_buf = NULL, **val_list = NULL;
  163. zval *array_ptr = (zval *) arg;
  164. size_t n, num, *len_list = NULL;
  165. size_t val_len, new_val_len;
  166. mbfl_string string, resvar, resval;
  167. const mbfl_encoding *from_encoding = NULL;
  168. mbfl_encoding_detector *identd = NULL;
  169. mbfl_buffer_converter *convd = NULL;
  170. mbfl_string_init_set(&string, info->to_encoding);
  171. mbfl_string_init_set(&resvar, info->to_encoding);
  172. mbfl_string_init_set(&resval, info->to_encoding);
  173. if (!res || *res == '\0') {
  174. goto out;
  175. }
  176. /* count the variables(separators) contained in the "res".
  177. * separator may contain multiple separator chars.
  178. */
  179. num = 1;
  180. for (s1=res; *s1 != '\0'; s1++) {
  181. for (s2=info->separator; *s2 != '\0'; s2++) {
  182. if (*s1 == *s2) {
  183. num++;
  184. }
  185. }
  186. }
  187. num *= 2; /* need space for variable name and value */
  188. val_list = (char **)ecalloc(num, sizeof(char *));
  189. len_list = (size_t *)ecalloc(num, sizeof(size_t));
  190. /* split and decode the query */
  191. n = 0;
  192. strtok_buf = NULL;
  193. var = php_strtok_r(res, info->separator, &strtok_buf);
  194. while (var) {
  195. val = strchr(var, '=');
  196. if (val) { /* have a value */
  197. len_list[n] = php_url_decode(var, val-var);
  198. val_list[n] = var;
  199. n++;
  200. *val++ = '\0';
  201. val_list[n] = val;
  202. len_list[n] = php_url_decode(val, strlen(val));
  203. } else {
  204. len_list[n] = php_url_decode(var, strlen(var));
  205. val_list[n] = var;
  206. n++;
  207. val_list[n] = "";
  208. len_list[n] = 0;
  209. }
  210. n++;
  211. var = php_strtok_r(NULL, info->separator, &strtok_buf);
  212. }
  213. if (ZEND_SIZE_T_GT_ZEND_LONG(n, (PG(max_input_vars) * 2))) {
  214. php_error_docref(NULL, E_WARNING, "Input variables exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
  215. goto out;
  216. }
  217. num = n; /* make sure to process initialized vars only */
  218. /* initialize converter */
  219. if (info->num_from_encodings == 0) {
  220. from_encoding = &mbfl_encoding_pass;
  221. } else if (info->num_from_encodings == 1) {
  222. from_encoding = info->from_encodings[0];
  223. } else {
  224. /* auto detect */
  225. from_encoding = NULL;
  226. identd = mbfl_encoding_detector_new(info->from_encodings, info->num_from_encodings, MBSTRG(strict_detection));
  227. if (identd != NULL) {
  228. n = 0;
  229. while (n < num) {
  230. string.val = (unsigned char *)val_list[n];
  231. string.len = len_list[n];
  232. if (mbfl_encoding_detector_feed(identd, &string)) {
  233. break;
  234. }
  235. n++;
  236. }
  237. from_encoding = mbfl_encoding_detector_judge(identd);
  238. mbfl_encoding_detector_delete(identd);
  239. }
  240. if (!from_encoding) {
  241. if (info->report_errors) {
  242. php_error_docref(NULL, E_WARNING, "Unable to detect encoding");
  243. }
  244. from_encoding = &mbfl_encoding_pass;
  245. }
  246. }
  247. convd = NULL;
  248. if (from_encoding != &mbfl_encoding_pass) {
  249. convd = mbfl_buffer_converter_new(from_encoding, info->to_encoding, 0);
  250. if (convd != NULL) {
  251. mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
  252. mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
  253. } else {
  254. if (info->report_errors) {
  255. php_error_docref(NULL, E_WARNING, "Unable to create converter");
  256. }
  257. goto out;
  258. }
  259. }
  260. /* convert encoding */
  261. string.encoding = from_encoding;
  262. n = 0;
  263. while (n < num) {
  264. string.val = (unsigned char *)val_list[n];
  265. string.len = len_list[n];
  266. if (convd != NULL && mbfl_buffer_converter_feed_result(convd, &string, &resvar) != NULL) {
  267. var = (char *)resvar.val;
  268. } else {
  269. var = val_list[n];
  270. }
  271. n++;
  272. string.val = (unsigned char *)val_list[n];
  273. string.len = len_list[n];
  274. if (convd != NULL && mbfl_buffer_converter_feed_result(convd, &string, &resval) != NULL) {
  275. val = (char *)resval.val;
  276. val_len = resval.len;
  277. } else {
  278. val = val_list[n];
  279. val_len = len_list[n];
  280. }
  281. n++;
  282. /* we need val to be emalloc()ed */
  283. val = estrndup(val, val_len);
  284. if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len)) {
  285. /* add variable to symbol table */
  286. php_register_variable_safe(var, val, new_val_len, array_ptr);
  287. }
  288. efree(val);
  289. if (convd != NULL){
  290. mbfl_string_clear(&resvar);
  291. mbfl_string_clear(&resval);
  292. }
  293. }
  294. out:
  295. if (convd != NULL) {
  296. MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
  297. mbfl_buffer_converter_delete(convd);
  298. }
  299. if (val_list != NULL) {
  300. efree((void *)val_list);
  301. }
  302. if (len_list != NULL) {
  303. efree((void *)len_list);
  304. }
  305. return from_encoding;
  306. }
  307. /* }}} */
  308. /* {{{ SAPI_POST_HANDLER_FUNC(php_mb_post_handler) */
  309. SAPI_POST_HANDLER_FUNC(php_mb_post_handler)
  310. {
  311. const mbfl_encoding *detected;
  312. php_mb_encoding_handler_info_t info;
  313. zend_string *post_data_str = NULL;
  314. MBSTRG(http_input_identify_post) = NULL;
  315. info.data_type = PARSE_POST;
  316. info.separator = "&";
  317. info.report_errors = 0;
  318. info.to_encoding = MBSTRG(internal_encoding);
  319. info.to_language = MBSTRG(language);
  320. info.from_encodings = MBSTRG(http_input_list);
  321. info.num_from_encodings = MBSTRG(http_input_list_size);
  322. info.from_language = MBSTRG(language);
  323. php_stream_rewind(SG(request_info).request_body);
  324. post_data_str = php_stream_copy_to_mem(SG(request_info).request_body, PHP_STREAM_COPY_ALL, 0);
  325. detected = _php_mb_encoding_handler_ex(&info, arg, post_data_str ? ZSTR_VAL(post_data_str) : NULL);
  326. if (post_data_str) {
  327. zend_string_release_ex(post_data_str, 0);
  328. }
  329. MBSTRG(http_input_identify) = detected;
  330. if (detected) {
  331. MBSTRG(http_input_identify_post) = detected;
  332. }
  333. }
  334. /* }}} */