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