mb_gpc.c 11 KB

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