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: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
16 | Zeev Suraski <zeev@zend.com> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #include <stdio.h>
23 #include "php.h"
24 #include "ext/standard/php_standard.h"
25 #include "ext/standard/credits.h"
26 #include "zend_smart_str.h"
27 #include "php_variables.h"
28 #include "php_globals.h"
29 #include "php_content_types.h"
30 #include "SAPI.h"
31 #include "zend_globals.h"
32 #ifdef PHP_WIN32
33 # include "win32/php_inttypes.h"
34 #endif
35
36 /* for systems that need to override reading of environment variables */
37 void _php_import_environment_variables(zval *array_ptr);
38 PHPAPI void (*php_import_environment_variables)(zval *array_ptr) = _php_import_environment_variables;
39
php_register_variable(char * var,char * strval,zval * track_vars_array)40 PHPAPI void php_register_variable(char *var, char *strval, zval *track_vars_array)
41 {
42 php_register_variable_safe(var, strval, strlen(strval), track_vars_array);
43 }
44
45 /* binary-safe version */
php_register_variable_safe(char * var,char * strval,size_t str_len,zval * track_vars_array)46 PHPAPI void php_register_variable_safe(char *var, char *strval, size_t str_len, zval *track_vars_array)
47 {
48 zval new_entry;
49 assert(strval != NULL);
50
51 /* Prepare value */
52 if (str_len == 0) {
53 ZVAL_EMPTY_STRING(&new_entry);
54 } else if (str_len == 1) {
55 ZVAL_INTERNED_STR(&new_entry, ZSTR_CHAR((zend_uchar)*strval));
56 } else {
57 ZVAL_NEW_STR(&new_entry, zend_string_init(strval, str_len, 0));
58 }
59 php_register_variable_ex(var, &new_entry, track_vars_array);
60 }
61
php_register_variable_ex(char * var_name,zval * val,zval * track_vars_array)62 PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array)
63 {
64 char *p = NULL;
65 char *ip = NULL; /* index pointer */
66 char *index;
67 char *var, *var_orig;
68 size_t var_len, index_len;
69 zval gpc_element, *gpc_element_p;
70 zend_bool is_array = 0;
71 HashTable *symtable1 = NULL;
72 ALLOCA_FLAG(use_heap)
73
74 assert(var_name != NULL);
75
76 if (track_vars_array && Z_TYPE_P(track_vars_array) == IS_ARRAY) {
77 symtable1 = Z_ARRVAL_P(track_vars_array);
78 }
79
80 if (!symtable1) {
81 /* Nothing to do */
82 zval_dtor(val);
83 return;
84 }
85
86
87 /* ignore leading spaces in the variable name */
88 while (*var_name==' ') {
89 var_name++;
90 }
91
92 /*
93 * Prepare variable name
94 */
95 var_len = strlen(var_name);
96 var = var_orig = do_alloca(var_len + 1, use_heap);
97 memcpy(var_orig, var_name, var_len + 1);
98
99 /* ensure that we don't have spaces or dots in the variable name (not binary safe) */
100 for (p = var; *p; p++) {
101 if (*p == ' ' || *p == '.') {
102 *p='_';
103 } else if (*p == '[') {
104 is_array = 1;
105 ip = p;
106 *p = 0;
107 break;
108 }
109 }
110 var_len = p - var;
111
112 if (var_len==0) { /* empty variable name, or variable name with a space in it */
113 zval_dtor(val);
114 free_alloca(var_orig, use_heap);
115 return;
116 }
117
118 if (var_len == sizeof("this")-1 && EG(current_execute_data)) {
119 zend_execute_data *ex = EG(current_execute_data);
120
121 while (ex) {
122 if (ex->func && ZEND_USER_CODE(ex->func->common.type)) {
123 if ((ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE)
124 && ex->symbol_table == symtable1) {
125 if (memcmp(var, "this", sizeof("this")-1) == 0) {
126 zend_throw_error(NULL, "Cannot re-assign $this");
127 zval_dtor(val);
128 free_alloca(var_orig, use_heap);
129 return;
130 }
131 }
132 break;
133 }
134 ex = ex->prev_execute_data;
135 }
136 }
137
138 /* GLOBALS hijack attempt, reject parameter */
139 if (symtable1 == &EG(symbol_table) &&
140 var_len == sizeof("GLOBALS")-1 &&
141 !memcmp(var, "GLOBALS", sizeof("GLOBALS")-1)) {
142 zval_dtor(val);
143 free_alloca(var_orig, use_heap);
144 return;
145 }
146
147 index = var;
148 index_len = var_len;
149
150 if (is_array) {
151 int nest_level = 0;
152 while (1) {
153 char *index_s;
154 size_t new_idx_len = 0;
155
156 if(++nest_level > PG(max_input_nesting_level)) {
157 HashTable *ht;
158 /* too many levels of nesting */
159
160 if (track_vars_array) {
161 ht = Z_ARRVAL_P(track_vars_array);
162 zend_symtable_str_del(ht, var, var_len);
163 }
164
165 zval_dtor(val);
166
167 /* do not output the error message to the screen,
168 this helps us to to avoid "information disclosure" */
169 if (!PG(display_errors)) {
170 php_error_docref(NULL, E_WARNING, "Input variable nesting level exceeded " ZEND_LONG_FMT ". To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level));
171 }
172 free_alloca(var_orig, use_heap);
173 return;
174 }
175
176 ip++;
177 index_s = ip;
178 if (isspace(*ip)) {
179 ip++;
180 }
181 if (*ip==']') {
182 index_s = NULL;
183 } else {
184 ip = strchr(ip, ']');
185 if (!ip) {
186 /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
187 *(index_s - 1) = '_';
188
189 index_len = 0;
190 if (index) {
191 index_len = strlen(index);
192 }
193 goto plain_var;
194 return;
195 }
196 *ip = 0;
197 new_idx_len = strlen(index_s);
198 }
199
200 if (!index) {
201 array_init(&gpc_element);
202 if ((gpc_element_p = zend_hash_next_index_insert(symtable1, &gpc_element)) == NULL) {
203 zval_ptr_dtor(&gpc_element);
204 zval_dtor(val);
205 free_alloca(var_orig, use_heap);
206 return;
207 }
208 } else {
209 gpc_element_p = zend_symtable_str_find(symtable1, index, index_len);
210 if (!gpc_element_p) {
211 zval tmp;
212 array_init(&tmp);
213 gpc_element_p = zend_symtable_str_update_ind(symtable1, index, index_len, &tmp);
214 } else {
215 if (Z_TYPE_P(gpc_element_p) == IS_INDIRECT) {
216 gpc_element_p = Z_INDIRECT_P(gpc_element_p);
217 }
218 if (Z_TYPE_P(gpc_element_p) != IS_ARRAY) {
219 zval_ptr_dtor(gpc_element_p);
220 array_init(gpc_element_p);
221 } else {
222 SEPARATE_ARRAY(gpc_element_p);
223 }
224 }
225 }
226 symtable1 = Z_ARRVAL_P(gpc_element_p);
227 /* ip pointed to the '[' character, now obtain the key */
228 index = index_s;
229 index_len = new_idx_len;
230
231 ip++;
232 if (*ip == '[') {
233 is_array = 1;
234 *ip = 0;
235 } else {
236 goto plain_var;
237 }
238 }
239 } else {
240 plain_var:
241 ZVAL_COPY_VALUE(&gpc_element, val);
242 if (!index) {
243 if ((gpc_element_p = zend_hash_next_index_insert(symtable1, &gpc_element)) == NULL) {
244 zval_ptr_dtor(&gpc_element);
245 }
246 } else {
247 /*
248 * According to rfc2965, more specific paths are listed above the less specific ones.
249 * If we encounter a duplicate cookie name, we should skip it, since it is not possible
250 * to have the same (plain text) cookie name for the same path and we should not overwrite
251 * more specific cookies with the less specific ones.
252 */
253 if (Z_TYPE(PG(http_globals)[TRACK_VARS_COOKIE]) != IS_UNDEF &&
254 symtable1 == Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]) &&
255 zend_symtable_str_exists(symtable1, index, index_len)) {
256 zval_ptr_dtor(&gpc_element);
257 } else {
258 gpc_element_p = zend_symtable_str_update_ind(symtable1, index, index_len, &gpc_element);
259 }
260 }
261 }
262 free_alloca(var_orig, use_heap);
263 }
264
265 typedef struct post_var_data {
266 smart_str str;
267 char *ptr;
268 char *end;
269 uint64_t cnt;
270
271 /* Bytes in ptr that have already been scanned for '&' */
272 size_t already_scanned;
273 } post_var_data_t;
274
add_post_var(zval * arr,post_var_data_t * var,zend_bool eof)275 static zend_bool add_post_var(zval *arr, post_var_data_t *var, zend_bool eof)
276 {
277 char *start, *ksep, *vsep, *val;
278 size_t klen, vlen;
279 size_t new_vlen;
280
281 if (var->ptr >= var->end) {
282 return 0;
283 }
284
285 start = var->ptr + var->already_scanned;
286 vsep = memchr(start, '&', var->end - start);
287 if (!vsep) {
288 if (!eof) {
289 var->already_scanned = var->end - var->ptr;
290 return 0;
291 } else {
292 vsep = var->end;
293 }
294 }
295
296 ksep = memchr(var->ptr, '=', vsep - var->ptr);
297 if (ksep) {
298 *ksep = '\0';
299 /* "foo=bar&" or "foo=&" */
300 klen = ksep - var->ptr;
301 vlen = vsep - ++ksep;
302 } else {
303 ksep = "";
304 /* "foo&" */
305 klen = vsep - var->ptr;
306 vlen = 0;
307 }
308
309 php_url_decode(var->ptr, klen);
310
311 val = estrndup(ksep, vlen);
312 if (vlen) {
313 vlen = php_url_decode(val, vlen);
314 }
315
316 if (sapi_module.input_filter(PARSE_POST, var->ptr, &val, vlen, &new_vlen)) {
317 php_register_variable_safe(var->ptr, val, new_vlen, arr);
318 }
319 efree(val);
320
321 var->ptr = vsep + (vsep != var->end);
322 var->already_scanned = 0;
323 return 1;
324 }
325
add_post_vars(zval * arr,post_var_data_t * vars,zend_bool eof)326 static inline int add_post_vars(zval *arr, post_var_data_t *vars, zend_bool eof)
327 {
328 uint64_t max_vars = PG(max_input_vars);
329
330 vars->ptr = ZSTR_VAL(vars->str.s);
331 vars->end = ZSTR_VAL(vars->str.s) + ZSTR_LEN(vars->str.s);
332 while (add_post_var(arr, vars, eof)) {
333 if (++vars->cnt > max_vars) {
334 php_error_docref(NULL, E_WARNING,
335 "Input variables exceeded %" PRIu64 ". "
336 "To increase the limit change max_input_vars in php.ini.",
337 max_vars);
338 return FAILURE;
339 }
340 }
341
342 if (!eof && ZSTR_VAL(vars->str.s) != vars->ptr) {
343 memmove(ZSTR_VAL(vars->str.s), vars->ptr, ZSTR_LEN(vars->str.s) = vars->end - vars->ptr);
344 }
345 return SUCCESS;
346 }
347
348 #ifdef PHP_WIN32
349 #define SAPI_POST_HANDLER_BUFSIZ 16384
350 #else
351 # define SAPI_POST_HANDLER_BUFSIZ BUFSIZ
352 #endif
SAPI_POST_HANDLER_FUNC(php_std_post_handler)353 SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler)
354 {
355 zval *arr = (zval *) arg;
356 php_stream *s = SG(request_info).request_body;
357 post_var_data_t post_data;
358
359 if (s && SUCCESS == php_stream_rewind(s)) {
360 memset(&post_data, 0, sizeof(post_data));
361
362 while (!php_stream_eof(s)) {
363 char buf[SAPI_POST_HANDLER_BUFSIZ] = {0};
364 size_t len = php_stream_read(s, buf, SAPI_POST_HANDLER_BUFSIZ);
365
366 if (len && len != (size_t) -1) {
367 smart_str_appendl(&post_data.str, buf, len);
368
369 if (SUCCESS != add_post_vars(arr, &post_data, 0)) {
370 smart_str_free(&post_data.str);
371 return;
372 }
373 }
374
375 if (len != SAPI_POST_HANDLER_BUFSIZ){
376 break;
377 }
378 }
379
380 if (post_data.str.s) {
381 add_post_vars(arr, &post_data, 1);
382 smart_str_free(&post_data.str);
383 }
384 }
385 }
386 #undef SAPI_POST_HANDLER_BUFSIZ
387
SAPI_INPUT_FILTER_FUNC(php_default_input_filter)388 SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter)
389 {
390 /* TODO: check .ini setting here and apply user-defined input filter */
391 if(new_val_len) *new_val_len = val_len;
392 return 1;
393 }
394
SAPI_TREAT_DATA_FUNC(php_default_treat_data)395 SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
396 {
397 char *res = NULL, *var, *val, *separator = NULL;
398 const char *c_var;
399 zval array;
400 int free_buffer = 0;
401 char *strtok_buf = NULL;
402 zend_long count = 0;
403
404 ZVAL_UNDEF(&array);
405 switch (arg) {
406 case PARSE_POST:
407 case PARSE_GET:
408 case PARSE_COOKIE:
409 array_init(&array);
410 switch (arg) {
411 case PARSE_POST:
412 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]);
413 ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_POST], &array);
414 break;
415 case PARSE_GET:
416 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
417 ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_GET], &array);
418 break;
419 case PARSE_COOKIE:
420 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]);
421 ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_COOKIE], &array);
422 break;
423 }
424 break;
425 default:
426 ZVAL_COPY_VALUE(&array, destArray);
427 break;
428 }
429
430 if (arg == PARSE_POST) {
431 sapi_handle_post(&array);
432 return;
433 }
434
435 if (arg == PARSE_GET) { /* GET data */
436 c_var = SG(request_info).query_string;
437 if (c_var && *c_var) {
438 res = (char *) estrdup(c_var);
439 free_buffer = 1;
440 } else {
441 free_buffer = 0;
442 }
443 } else if (arg == PARSE_COOKIE) { /* Cookie data */
444 c_var = SG(request_info).cookie_data;
445 if (c_var && *c_var) {
446 res = (char *) estrdup(c_var);
447 free_buffer = 1;
448 } else {
449 free_buffer = 0;
450 }
451 } else if (arg == PARSE_STRING) { /* String data */
452 res = str;
453 free_buffer = 1;
454 }
455
456 if (!res) {
457 return;
458 }
459
460 switch (arg) {
461 case PARSE_GET:
462 case PARSE_STRING:
463 separator = PG(arg_separator).input;
464 break;
465 case PARSE_COOKIE:
466 separator = ";\0";
467 break;
468 }
469
470 var = php_strtok_r(res, separator, &strtok_buf);
471
472 while (var) {
473 val = strchr(var, '=');
474
475 if (arg == PARSE_COOKIE) {
476 /* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */
477 while (isspace(*var)) {
478 var++;
479 }
480 if (var == val || *var == '\0') {
481 goto next_cookie;
482 }
483 }
484
485 if (++count > PG(max_input_vars)) {
486 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));
487 break;
488 }
489
490 if (val) { /* have a value */
491 size_t val_len;
492 size_t new_val_len;
493
494 *val++ = '\0';
495 if (arg != PARSE_COOKIE) {
496 php_url_decode(var, strlen(var));
497 }
498 val_len = php_url_decode(val, strlen(val));
499 val = estrndup(val, val_len);
500 if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
501 php_register_variable_safe(var, val, new_val_len, &array);
502 }
503 efree(val);
504 } else {
505 size_t val_len;
506 size_t new_val_len;
507
508 if (arg != PARSE_COOKIE) {
509 php_url_decode(var, strlen(var));
510 }
511 val_len = 0;
512 val = estrndup("", val_len);
513 if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
514 php_register_variable_safe(var, val, new_val_len, &array);
515 }
516 efree(val);
517 }
518 next_cookie:
519 var = php_strtok_r(NULL, separator, &strtok_buf);
520 }
521
522 if (free_buffer) {
523 efree(res);
524 }
525 }
526
_php_import_environment_variables(zval * array_ptr)527 void _php_import_environment_variables(zval *array_ptr)
528 {
529 char buf[128];
530 char **env, *p, *t = buf;
531 size_t alloc_size = sizeof(buf);
532 unsigned long nlen; /* ptrdiff_t is not portable */
533
534 for (env = environ; env != NULL && *env != NULL; env++) {
535 p = strchr(*env, '=');
536 if (!p) { /* malformed entry? */
537 continue;
538 }
539 nlen = p - *env;
540 if (nlen >= alloc_size) {
541 alloc_size = nlen + 64;
542 t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
543 }
544 memcpy(t, *env, nlen);
545 t[nlen] = '\0';
546 php_register_variable(t, p + 1, array_ptr);
547 }
548 if (t != buf && t != NULL) {
549 efree(t);
550 }
551 }
552
php_std_auto_global_callback(char * name,uint32_t name_len)553 zend_bool php_std_auto_global_callback(char *name, uint32_t name_len)
554 {
555 zend_printf("%s\n", name);
556 return 0; /* don't rearm */
557 }
558
559 /* {{{ php_build_argv
560 */
php_build_argv(char * s,zval * track_vars_array)561 PHPAPI void php_build_argv(char *s, zval *track_vars_array)
562 {
563 zval arr, argc, tmp;
564 int count = 0;
565 char *ss, *space;
566
567 if (!(SG(request_info).argc || track_vars_array)) {
568 return;
569 }
570
571 array_init(&arr);
572
573 /* Prepare argv */
574 if (SG(request_info).argc) { /* are we in cli sapi? */
575 int i;
576 for (i = 0; i < SG(request_info).argc; i++) {
577 ZVAL_STRING(&tmp, SG(request_info).argv[i]);
578 if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) {
579 zend_string_free(Z_STR(tmp));
580 }
581 }
582 } else if (s && *s) {
583 ss = s;
584 while (ss) {
585 space = strchr(ss, '+');
586 if (space) {
587 *space = '\0';
588 }
589 /* auto-type */
590 ZVAL_STRING(&tmp, ss);
591 count++;
592 if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) {
593 zend_string_free(Z_STR(tmp));
594 }
595 if (space) {
596 *space = '+';
597 ss = space + 1;
598 } else {
599 ss = space;
600 }
601 }
602 }
603
604 /* prepare argc */
605 if (SG(request_info).argc) {
606 ZVAL_LONG(&argc, SG(request_info).argc);
607 } else {
608 ZVAL_LONG(&argc, count);
609 }
610
611 if (SG(request_info).argc) {
612 Z_ADDREF(arr);
613 zend_hash_str_update(&EG(symbol_table), "argv", sizeof("argv")-1, &arr);
614 zend_hash_str_add(&EG(symbol_table), "argc", sizeof("argc")-1, &argc);
615 }
616 if (track_vars_array && Z_TYPE_P(track_vars_array) == IS_ARRAY) {
617 Z_ADDREF(arr);
618 zend_hash_str_update(Z_ARRVAL_P(track_vars_array), "argv", sizeof("argv")-1, &arr);
619 zend_hash_str_update(Z_ARRVAL_P(track_vars_array), "argc", sizeof("argc")-1, &argc);
620 }
621 zval_ptr_dtor_nogc(&arr);
622 }
623 /* }}} */
624
625 /* {{{ php_register_server_variables
626 */
php_register_server_variables(void)627 static inline void php_register_server_variables(void)
628 {
629 zval request_time_float, request_time_long;
630
631 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_SERVER]);
632 array_init(&PG(http_globals)[TRACK_VARS_SERVER]);
633
634 /* Server variables */
635 if (sapi_module.register_server_variables) {
636 sapi_module.register_server_variables(&PG(http_globals)[TRACK_VARS_SERVER]);
637 }
638
639 /* PHP Authentication support */
640 if (SG(request_info).auth_user) {
641 php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, &PG(http_globals)[TRACK_VARS_SERVER]);
642 }
643 if (SG(request_info).auth_password) {
644 php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, &PG(http_globals)[TRACK_VARS_SERVER]);
645 }
646 if (SG(request_info).auth_digest) {
647 php_register_variable("PHP_AUTH_DIGEST", SG(request_info).auth_digest, &PG(http_globals)[TRACK_VARS_SERVER]);
648 }
649
650 /* store request init time */
651 ZVAL_DOUBLE(&request_time_float, sapi_get_request_time());
652 php_register_variable_ex("REQUEST_TIME_FLOAT", &request_time_float, &PG(http_globals)[TRACK_VARS_SERVER]);
653 ZVAL_LONG(&request_time_long, zend_dval_to_lval(Z_DVAL(request_time_float)));
654 php_register_variable_ex("REQUEST_TIME", &request_time_long, &PG(http_globals)[TRACK_VARS_SERVER]);
655 }
656 /* }}} */
657
658 /* {{{ php_autoglobal_merge
659 */
php_autoglobal_merge(HashTable * dest,HashTable * src)660 static void php_autoglobal_merge(HashTable *dest, HashTable *src)
661 {
662 zval *src_entry, *dest_entry;
663 zend_string *string_key;
664 zend_ulong num_key;
665 int globals_check = (dest == (&EG(symbol_table)));
666
667 ZEND_HASH_FOREACH_KEY_VAL(src, num_key, string_key, src_entry) {
668 if (Z_TYPE_P(src_entry) != IS_ARRAY
669 || (string_key && (dest_entry = zend_hash_find(dest, string_key)) == NULL)
670 || (string_key == NULL && (dest_entry = zend_hash_index_find(dest, num_key)) == NULL)
671 || Z_TYPE_P(dest_entry) != IS_ARRAY) {
672 if (Z_REFCOUNTED_P(src_entry)) {
673 Z_ADDREF_P(src_entry);
674 }
675 if (string_key) {
676 if (!globals_check || ZSTR_LEN(string_key) != sizeof("GLOBALS") - 1
677 || memcmp(ZSTR_VAL(string_key), "GLOBALS", sizeof("GLOBALS") - 1)) {
678 zend_hash_update(dest, string_key, src_entry);
679 } else if (Z_REFCOUNTED_P(src_entry)) {
680 Z_DELREF_P(src_entry);
681 }
682 } else {
683 zend_hash_index_update(dest, num_key, src_entry);
684 }
685 } else {
686 SEPARATE_ARRAY(dest_entry);
687 php_autoglobal_merge(Z_ARRVAL_P(dest_entry), Z_ARRVAL_P(src_entry));
688 }
689 } ZEND_HASH_FOREACH_END();
690 }
691 /* }}} */
692
693 /* {{{ php_hash_environment
694 */
php_hash_environment(void)695 PHPAPI int php_hash_environment(void)
696 {
697 memset(PG(http_globals), 0, sizeof(PG(http_globals)));
698 zend_activate_auto_globals();
699 if (PG(register_argc_argv)) {
700 php_build_argv(SG(request_info).query_string, &PG(http_globals)[TRACK_VARS_SERVER]);
701 }
702 return SUCCESS;
703 }
704 /* }}} */
705
php_auto_globals_create_get(zend_string * name)706 static zend_bool php_auto_globals_create_get(zend_string *name)
707 {
708 if (PG(variables_order) && (strchr(PG(variables_order),'G') || strchr(PG(variables_order),'g'))) {
709 sapi_module.treat_data(PARSE_GET, NULL, NULL);
710 } else {
711 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
712 array_init(&PG(http_globals)[TRACK_VARS_GET]);
713 }
714
715 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_GET]);
716 Z_ADDREF(PG(http_globals)[TRACK_VARS_GET]);
717
718 return 0; /* don't rearm */
719 }
720
php_auto_globals_create_post(zend_string * name)721 static zend_bool php_auto_globals_create_post(zend_string *name)
722 {
723 if (PG(variables_order) &&
724 (strchr(PG(variables_order),'P') || strchr(PG(variables_order),'p')) &&
725 !SG(headers_sent) &&
726 SG(request_info).request_method &&
727 !strcasecmp(SG(request_info).request_method, "POST")) {
728 sapi_module.treat_data(PARSE_POST, NULL, NULL);
729 } else {
730 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]);
731 array_init(&PG(http_globals)[TRACK_VARS_POST]);
732 }
733
734 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_POST]);
735 Z_ADDREF(PG(http_globals)[TRACK_VARS_POST]);
736
737 return 0; /* don't rearm */
738 }
739
php_auto_globals_create_cookie(zend_string * name)740 static zend_bool php_auto_globals_create_cookie(zend_string *name)
741 {
742 if (PG(variables_order) && (strchr(PG(variables_order),'C') || strchr(PG(variables_order),'c'))) {
743 sapi_module.treat_data(PARSE_COOKIE, NULL, NULL);
744 } else {
745 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]);
746 array_init(&PG(http_globals)[TRACK_VARS_COOKIE]);
747 }
748
749 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_COOKIE]);
750 Z_ADDREF(PG(http_globals)[TRACK_VARS_COOKIE]);
751
752 return 0; /* don't rearm */
753 }
754
php_auto_globals_create_files(zend_string * name)755 static zend_bool php_auto_globals_create_files(zend_string *name)
756 {
757 if (Z_TYPE(PG(http_globals)[TRACK_VARS_FILES]) == IS_UNDEF) {
758 array_init(&PG(http_globals)[TRACK_VARS_FILES]);
759 }
760
761 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_FILES]);
762 Z_ADDREF(PG(http_globals)[TRACK_VARS_FILES]);
763
764 return 0; /* don't rearm */
765 }
766
767 /* Upgly hack to fix HTTP_PROXY issue, see bug #72573 */
check_http_proxy(HashTable * var_table)768 static void check_http_proxy(HashTable *var_table)
769 {
770 if (zend_hash_str_exists(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1)) {
771 char *local_proxy = getenv("HTTP_PROXY");
772
773 if (!local_proxy) {
774 zend_hash_str_del(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1);
775 } else {
776 zval local_zval;
777 ZVAL_STRING(&local_zval, local_proxy);
778 zend_hash_str_update(var_table, "HTTP_PROXY", sizeof("HTTP_PROXY")-1, &local_zval);
779 }
780 }
781 }
782
php_auto_globals_create_server(zend_string * name)783 static zend_bool php_auto_globals_create_server(zend_string *name)
784 {
785 if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) {
786 php_register_server_variables();
787
788 if (PG(register_argc_argv)) {
789 if (SG(request_info).argc) {
790 zval *argc, *argv;
791
792 if ((argc = zend_hash_str_find_ind(&EG(symbol_table), "argc", sizeof("argc")-1)) != NULL &&
793 (argv = zend_hash_str_find_ind(&EG(symbol_table), "argv", sizeof("argv")-1)) != NULL) {
794 Z_ADDREF_P(argv);
795 zend_hash_str_update(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "argv", sizeof("argv")-1, argv);
796 zend_hash_str_update(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "argc", sizeof("argc")-1, argc);
797 }
798 } else {
799 php_build_argv(SG(request_info).query_string, &PG(http_globals)[TRACK_VARS_SERVER]);
800 }
801 }
802
803 } else {
804 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_SERVER]);
805 array_init(&PG(http_globals)[TRACK_VARS_SERVER]);
806 }
807
808 check_http_proxy(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]));
809 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_SERVER]);
810 Z_ADDREF(PG(http_globals)[TRACK_VARS_SERVER]);
811
812 /* TODO: TRACK_VARS_SERVER is modified in a number of places (e.g. phar) past this point,
813 * where rc>1 due to the $_SERVER global. Ideally this shouldn't happen, but for now we
814 * ignore this issue, as it would probably require larger changes. */
815 HT_ALLOW_COW_VIOLATION(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]));
816
817 return 0; /* don't rearm */
818 }
819
php_auto_globals_create_env(zend_string * name)820 static zend_bool php_auto_globals_create_env(zend_string *name)
821 {
822 zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_ENV]);
823 array_init(&PG(http_globals)[TRACK_VARS_ENV]);
824
825 if (PG(variables_order) && (strchr(PG(variables_order),'E') || strchr(PG(variables_order),'e'))) {
826 php_import_environment_variables(&PG(http_globals)[TRACK_VARS_ENV]);
827 }
828
829 check_http_proxy(Z_ARRVAL(PG(http_globals)[TRACK_VARS_ENV]));
830 zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_ENV]);
831 Z_ADDREF(PG(http_globals)[TRACK_VARS_ENV]);
832
833 return 0; /* don't rearm */
834 }
835
php_auto_globals_create_request(zend_string * name)836 static zend_bool php_auto_globals_create_request(zend_string *name)
837 {
838 zval form_variables;
839 unsigned char _gpc_flags[3] = {0, 0, 0};
840 char *p;
841
842 array_init(&form_variables);
843
844 if (PG(request_order) != NULL) {
845 p = PG(request_order);
846 } else {
847 p = PG(variables_order);
848 }
849
850 for (; p && *p; p++) {
851 switch (*p) {
852 case 'g':
853 case 'G':
854 if (!_gpc_flags[0]) {
855 php_autoglobal_merge(Z_ARRVAL(form_variables), Z_ARRVAL(PG(http_globals)[TRACK_VARS_GET]));
856 _gpc_flags[0] = 1;
857 }
858 break;
859 case 'p':
860 case 'P':
861 if (!_gpc_flags[1]) {
862 php_autoglobal_merge(Z_ARRVAL(form_variables), Z_ARRVAL(PG(http_globals)[TRACK_VARS_POST]));
863 _gpc_flags[1] = 1;
864 }
865 break;
866 case 'c':
867 case 'C':
868 if (!_gpc_flags[2]) {
869 php_autoglobal_merge(Z_ARRVAL(form_variables), Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]));
870 _gpc_flags[2] = 1;
871 }
872 break;
873 }
874 }
875
876 zend_hash_update(&EG(symbol_table), name, &form_variables);
877 return 0;
878 }
879
php_startup_auto_globals(void)880 void php_startup_auto_globals(void)
881 {
882 zend_register_auto_global(zend_string_init("_GET", sizeof("_GET")-1, 1), 0, php_auto_globals_create_get);
883 zend_register_auto_global(zend_string_init("_POST", sizeof("_POST")-1, 1), 0, php_auto_globals_create_post);
884 zend_register_auto_global(zend_string_init("_COOKIE", sizeof("_COOKIE")-1, 1), 0, php_auto_globals_create_cookie);
885 zend_register_auto_global(zend_string_init("_SERVER", sizeof("_SERVER")-1, 1), PG(auto_globals_jit), php_auto_globals_create_server);
886 zend_register_auto_global(zend_string_init("_ENV", sizeof("_ENV")-1, 1), PG(auto_globals_jit), php_auto_globals_create_env);
887 zend_register_auto_global(zend_string_init("_REQUEST", sizeof("_REQUEST")-1, 1), PG(auto_globals_jit), php_auto_globals_create_request);
888 zend_register_auto_global(zend_string_init("_FILES", sizeof("_FILES")-1, 1), 0, php_auto_globals_create_files);
889 }
890
891 /*
892 * Local variables:
893 * tab-width: 4
894 * c-basic-offset: 4
895 * End:
896 * vim600: sw=4 ts=4 fdm=marker
897 * vim<600: sw=4 ts=4
898 */
899