xref: /php-src/main/main.c (revision c3acfb1b)
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    | Authors: Andi Gutmans <andi@php.net>                                 |
14    |          Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
15    |          Zeev Suraski <zeev@php.net>                                 |
16    +----------------------------------------------------------------------+
17 */
18 
19 /* {{{ includes */
20 
21 #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
22 
23 #include "php.h"
24 #include <stdio.h>
25 #include <fcntl.h>
26 #ifdef PHP_WIN32
27 #include "win32/time.h"
28 #include "win32/signal.h"
29 #include "win32/php_win32_globals.h"
30 #include "win32/winutil.h"
31 #include <process.h>
32 #endif
33 #if HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #endif
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 
40 #include <signal.h>
41 #include <locale.h>
42 #include "zend.h"
43 #include "zend_types.h"
44 #include "zend_extensions.h"
45 #include "php_ini.h"
46 #include "php_globals.h"
47 #include "php_main.h"
48 #include "php_syslog.h"
49 #include "fopen_wrappers.h"
50 #include "ext/standard/php_standard.h"
51 #include "ext/date/php_date.h"
52 #include "php_variables.h"
53 #include "ext/standard/credits.h"
54 #ifdef PHP_WIN32
55 #include <io.h>
56 #include "win32/php_registry.h"
57 #include "ext/standard/flock_compat.h"
58 #endif
59 #include "php_syslog.h"
60 #include "Zend/zend_exceptions.h"
61 
62 #if PHP_SIGCHILD
63 #include <sys/types.h>
64 #include <sys/wait.h>
65 #endif
66 
67 #include "zend_compile.h"
68 #include "zend_execute.h"
69 #include "zend_highlight.h"
70 #include "zend_extensions.h"
71 #include "zend_ini.h"
72 #include "zend_dtrace.h"
73 #include "zend_observer.h"
74 #include "zend_system_id.h"
75 
76 #include "php_content_types.h"
77 #include "php_ticks.h"
78 #include "php_streams.h"
79 #include "php_open_temporary_file.h"
80 
81 #include "SAPI.h"
82 #include "rfc1867.h"
83 
84 #include "ext/standard/html_tables.h"
85 #include "main_arginfo.h"
86 /* }}} */
87 
88 PHPAPI int (*php_register_internal_extensions_func)(void) = php_register_internal_extensions;
89 
90 #ifndef ZTS
91 php_core_globals core_globals;
92 #else
93 PHPAPI int core_globals_id;
94 PHPAPI size_t core_globals_offset;
95 #endif
96 
97 #define SAFE_FILENAME(f) ((f)?(f):"-")
98 
php_version(void)99 PHPAPI const char *php_version(void)
100 {
101 	return PHP_VERSION;
102 }
103 
php_version_id(void)104 PHPAPI unsigned int php_version_id(void)
105 {
106 	return PHP_VERSION_ID;
107 }
108 
109 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnSetFacility)110 static PHP_INI_MH(OnSetFacility)
111 {
112 	const zend_string *facility = new_value;
113 
114 #ifdef LOG_AUTH
115 	if (zend_string_equals_literal(facility, "LOG_AUTH") || zend_string_equals_literal(facility, "auth")
116 			|| zend_string_equals_literal(facility, "security")) {
117 		PG(syslog_facility) = LOG_AUTH;
118 		return SUCCESS;
119 	}
120 #endif
121 #ifdef LOG_AUTHPRIV
122 	if (zend_string_equals_literal(facility, "LOG_AUTHPRIV") || zend_string_equals_literal(facility, "authpriv")) {
123 		PG(syslog_facility) = LOG_AUTHPRIV;
124 		return SUCCESS;
125 	}
126 #endif
127 #ifdef LOG_CRON
128 	if (zend_string_equals_literal(facility, "LOG_CRON") || zend_string_equals_literal(facility, "cron")) {
129 		PG(syslog_facility) = LOG_CRON;
130 		return SUCCESS;
131 	}
132 #endif
133 #ifdef LOG_DAEMON
134 	if (zend_string_equals_literal(facility, "LOG_DAEMON") || zend_string_equals_literal(facility, "daemon")) {
135 		PG(syslog_facility) = LOG_DAEMON;
136 		return SUCCESS;
137 	}
138 #endif
139 #ifdef LOG_FTP
140 	if (zend_string_equals_literal(facility, "LOG_FTP") || zend_string_equals_literal(facility, "ftp")) {
141 		PG(syslog_facility) = LOG_FTP;
142 		return SUCCESS;
143 	}
144 #endif
145 #ifdef LOG_KERN
146 	if (zend_string_equals_literal(facility, "LOG_KERN") || zend_string_equals_literal(facility, "kern")) {
147 		PG(syslog_facility) = LOG_KERN;
148 		return SUCCESS;
149 	}
150 #endif
151 #ifdef LOG_LPR
152 	if (zend_string_equals_literal(facility, "LOG_LPR") || zend_string_equals_literal(facility, "lpr")) {
153 		PG(syslog_facility) = LOG_LPR;
154 		return SUCCESS;
155 	}
156 #endif
157 #ifdef LOG_MAIL
158 	if (zend_string_equals_literal(facility, "LOG_MAIL") || zend_string_equals_literal(facility, "mail")) {
159 		PG(syslog_facility) = LOG_MAIL;
160 		return SUCCESS;
161 	}
162 #endif
163 #ifdef LOG_INTERNAL_MARK
164 	if (zend_string_equals_literal(facility, "LOG_INTERNAL_MARK") || zend_string_equals_literal(facility, "mark")) {
165 		PG(syslog_facility) = LOG_INTERNAL_MARK;
166 		return SUCCESS;
167 	}
168 #endif
169 #ifdef LOG_NEWS
170 	if (zend_string_equals_literal(facility, "LOG_NEWS") || zend_string_equals_literal(facility, "news")) {
171 		PG(syslog_facility) = LOG_NEWS;
172 		return SUCCESS;
173 	}
174 #endif
175 #ifdef LOG_SYSLOG
176 	if (zend_string_equals_literal(facility, "LOG_SYSLOG") || zend_string_equals_literal(facility, "syslog")) {
177 		PG(syslog_facility) = LOG_SYSLOG;
178 		return SUCCESS;
179 	}
180 #endif
181 #ifdef LOG_USER
182 	if (zend_string_equals(facility, ZSTR_KNOWN(ZEND_STR_USER)) || zend_string_equals_literal(facility, "LOG_USER")) {
183 		PG(syslog_facility) = LOG_USER;
184 		return SUCCESS;
185 	}
186 #endif
187 #ifdef LOG_UUCP
188 	if (zend_string_equals_literal(facility, "LOG_UUCP") || zend_string_equals_literal(facility, "uucp")) {
189 		PG(syslog_facility) = LOG_UUCP;
190 		return SUCCESS;
191 	}
192 #endif
193 #ifdef LOG_LOCAL0
194 	if (zend_string_equals_literal(facility, "LOG_LOCAL0") || zend_string_equals_literal(facility, "local0")) {
195 		PG(syslog_facility) = LOG_LOCAL0;
196 		return SUCCESS;
197 	}
198 #endif
199 #ifdef LOG_LOCAL1
200 	if (zend_string_equals_literal(facility, "LOG_LOCAL1") || zend_string_equals_literal(facility, "local1")) {
201 		PG(syslog_facility) = LOG_LOCAL1;
202 		return SUCCESS;
203 	}
204 #endif
205 #ifdef LOG_LOCAL2
206 	if (zend_string_equals_literal(facility, "LOG_LOCAL2") || zend_string_equals_literal(facility, "local2")) {
207 		PG(syslog_facility) = LOG_LOCAL2;
208 		return SUCCESS;
209 	}
210 #endif
211 #ifdef LOG_LOCAL3
212 	if (zend_string_equals_literal(facility, "LOG_LOCAL3") || zend_string_equals_literal(facility, "local3")) {
213 		PG(syslog_facility) = LOG_LOCAL3;
214 		return SUCCESS;
215 	}
216 #endif
217 #ifdef LOG_LOCAL4
218 	if (zend_string_equals_literal(facility, "LOG_LOCAL4") || zend_string_equals_literal(facility, "local4")) {
219 		PG(syslog_facility) = LOG_LOCAL4;
220 		return SUCCESS;
221 	}
222 #endif
223 #ifdef LOG_LOCAL5
224 	if (zend_string_equals_literal(facility, "LOG_LOCAL5") || zend_string_equals_literal(facility, "local5")) {
225 		PG(syslog_facility) = LOG_LOCAL5;
226 		return SUCCESS;
227 	}
228 #endif
229 #ifdef LOG_LOCAL6
230 	if (zend_string_equals_literal(facility, "LOG_LOCAL6") || zend_string_equals_literal(facility, "local6")) {
231 		PG(syslog_facility) = LOG_LOCAL6;
232 		return SUCCESS;
233 	}
234 #endif
235 #ifdef LOG_LOCAL7
236 	if (zend_string_equals_literal(facility, "LOG_LOCAL7") || zend_string_equals_literal(facility, "local7")) {
237 		PG(syslog_facility) = LOG_LOCAL7;
238 		return SUCCESS;
239 	}
240 #endif
241 
242 	return FAILURE;
243 }
244 /* }}} */
245 
246 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnSetPrecision)247 static PHP_INI_MH(OnSetPrecision)
248 {
249 	zend_long i = ZEND_ATOL(ZSTR_VAL(new_value));
250 	if (i >= -1) {
251 		EG(precision) = i;
252 		return SUCCESS;
253 	} else {
254 		return FAILURE;
255 	}
256 }
257 /* }}} */
258 
259 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnSetSerializePrecision)260 static PHP_INI_MH(OnSetSerializePrecision)
261 {
262 	zend_long i = ZEND_ATOL(ZSTR_VAL(new_value));
263 	if (i >= -1) {
264 		PG(serialize_precision) = i;
265 		return SUCCESS;
266 	} else {
267 		return FAILURE;
268 	}
269 }
270 /* }}} */
271 
272 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnChangeMemoryLimit)273 static PHP_INI_MH(OnChangeMemoryLimit)
274 {
275 	size_t value;
276 	if (new_value) {
277 		value = zend_ini_parse_uquantity_warn(new_value, entry->name);
278 	} else {
279 		value = Z_L(1)<<30;		/* effectively, no limit */
280 	}
281 	if (zend_set_memory_limit(value) == FAILURE) {
282 		/* When the memory limit is reset to the original level during deactivation, we may be
283 		 * using more memory than the original limit while shutdown is still in progress.
284 		 * Ignore a failure for now, and set the memory limit when the memory manager has been
285 		 * shut down and the minimal amount of memory is used. */
286 		if (stage != ZEND_INI_STAGE_DEACTIVATE) {
287 			zend_error(E_WARNING, "Failed to set memory limit to %zd bytes (Current memory usage is %zd bytes)", value, zend_memory_usage(true));
288 			return FAILURE;
289 		}
290 	}
291 	PG(memory_limit) = value;
292 	return SUCCESS;
293 }
294 /* }}} */
295 
296 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnSetLogFilter)297 static PHP_INI_MH(OnSetLogFilter)
298 {
299 	const zend_string *filter = new_value;
300 
301 	if (zend_string_equals_literal(filter, "all")) {
302 		PG(syslog_filter) = PHP_SYSLOG_FILTER_ALL;
303 		return SUCCESS;
304 	}
305 	if (zend_string_equals_literal(filter, "no-ctrl")) {
306 		PG(syslog_filter) = PHP_SYSLOG_FILTER_NO_CTRL;
307 		return SUCCESS;
308 	}
309 	if (zend_string_equals_literal(filter, "ascii")) {
310 		PG(syslog_filter) = PHP_SYSLOG_FILTER_ASCII;
311 		return SUCCESS;
312 	}
313 	if (zend_string_equals_literal(filter, "raw")) {
314 		PG(syslog_filter) = PHP_SYSLOG_FILTER_RAW;
315 		return SUCCESS;
316 	}
317 
318 	return FAILURE;
319 }
320 /* }}} */
321 
322 /* {{{ php_disable_classes */
php_disable_classes(void)323 static void php_disable_classes(void)
324 {
325 	char *s = NULL, *e;
326 
327 	if (!*(INI_STR("disable_classes"))) {
328 		return;
329 	}
330 
331 	e = PG(disable_classes) = strdup(INI_STR("disable_classes"));
332 
333 	while (*e) {
334 		switch (*e) {
335 			case ' ':
336 			case ',':
337 				if (s) {
338 					*e = '\0';
339 					zend_disable_class(s, e-s);
340 					s = NULL;
341 				}
342 				break;
343 			default:
344 				if (!s) {
345 					s = e;
346 				}
347 				break;
348 		}
349 		e++;
350 	}
351 	if (s) {
352 		zend_disable_class(s, e-s);
353 	}
354 }
355 /* }}} */
356 
357 /* {{{ php_binary_init */
php_binary_init(void)358 static void php_binary_init(void)
359 {
360 	char *binary_location = NULL;
361 #ifdef PHP_WIN32
362 	binary_location = (char *)pemalloc(MAXPATHLEN, 1);
363 	if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
364 		pefree(binary_location, 1);
365 		binary_location = NULL;
366 	}
367 #else
368 	if (sapi_module.executable_location) {
369 		binary_location = (char *)pemalloc(MAXPATHLEN, 1);
370 		if (!strchr(sapi_module.executable_location, '/')) {
371 			char *envpath, *path;
372 			bool found = false;
373 
374 			if ((envpath = getenv("PATH")) != NULL) {
375 				char *search_dir, search_path[MAXPATHLEN];
376 				char *last = NULL;
377 				zend_stat_t s = {0};
378 
379 				path = estrdup(envpath);
380 				search_dir = php_strtok_r(path, ":", &last);
381 
382 				while (search_dir) {
383 					snprintf(search_path, MAXPATHLEN, "%s/%s", search_dir, sapi_module.executable_location);
384 					if (VCWD_REALPATH(search_path, binary_location) && !VCWD_ACCESS(binary_location, X_OK) && VCWD_STAT(binary_location, &s) == 0 && S_ISREG(s.st_mode)) {
385 						found = true;
386 						break;
387 					}
388 					search_dir = php_strtok_r(NULL, ":", &last);
389 				}
390 				efree(path);
391 			}
392 			if (!found) {
393 				pefree(binary_location, 1);
394 				binary_location = NULL;
395 			}
396 		} else if (!VCWD_REALPATH(sapi_module.executable_location, binary_location) || VCWD_ACCESS(binary_location, X_OK)) {
397 			pefree(binary_location, 1);
398 			binary_location = NULL;
399 		}
400 	}
401 #endif
402 	PG(php_binary) = binary_location;
403 }
404 /* }}} */
405 
406 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateTimeout)407 static PHP_INI_MH(OnUpdateTimeout)
408 {
409 	if (stage==PHP_INI_STAGE_STARTUP) {
410 		/* Don't set a timeout on startup, only per-request */
411 		EG(timeout_seconds) = ZEND_ATOL(ZSTR_VAL(new_value));
412 		return SUCCESS;
413 	}
414 	zend_unset_timeout();
415 	EG(timeout_seconds) = ZEND_ATOL(ZSTR_VAL(new_value));
416 	if (stage != PHP_INI_STAGE_DEACTIVATE) {
417 		/*
418 		 * If we're restoring INI values, we shouldn't reset the timer.
419 		 * Otherwise, the timer is active when PHP is idle, such as the
420 		 * CLI web server or CGI. Running a script will re-activate
421 		 * the timeout, so it's not needed to do so at script end.
422 		 */
423 		zend_set_timeout(EG(timeout_seconds), 0);
424 	}
425 	return SUCCESS;
426 }
427 /* }}} */
428 
429 /* {{{ php_get_display_errors_mode() helper function */
php_get_display_errors_mode(zend_string * value)430 static uint8_t php_get_display_errors_mode(zend_string *value)
431 {
432 	if (!value) {
433 		return PHP_DISPLAY_ERRORS_STDOUT;
434 	}
435 
436 	if (zend_string_equals_literal_ci(value, "on")) {
437 		return PHP_DISPLAY_ERRORS_STDOUT;
438 	}
439 	if (zend_string_equals_literal_ci(value, "yes")) {
440 		return PHP_DISPLAY_ERRORS_STDOUT;
441 	}
442 
443 	if (zend_string_equals_literal_ci(value, "true")) {
444 		return PHP_DISPLAY_ERRORS_STDOUT;
445 	}
446 	if (zend_string_equals_literal_ci(value, "stderr")) {
447 		return PHP_DISPLAY_ERRORS_STDERR;
448 	}
449 	if (zend_string_equals_literal_ci(value, "stdout")) {
450 		return PHP_DISPLAY_ERRORS_STDOUT;
451 	}
452 
453 	uint8_t mode = ZEND_ATOL(ZSTR_VAL(value));
454 	if (mode && mode != PHP_DISPLAY_ERRORS_STDOUT && mode != PHP_DISPLAY_ERRORS_STDERR) {
455 		return PHP_DISPLAY_ERRORS_STDOUT;
456 	}
457 
458 	return mode;
459 }
460 /* }}} */
461 
462 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateDisplayErrors)463 static PHP_INI_MH(OnUpdateDisplayErrors)
464 {
465 	PG(display_errors) = php_get_display_errors_mode(new_value);
466 
467 	return SUCCESS;
468 }
469 /* }}} */
470 
471 /* {{{ PHP_INI_DISP */
PHP_INI_DISP(display_errors_mode)472 static PHP_INI_DISP(display_errors_mode)
473 {
474 	uint8_t mode;
475 	bool cgi_or_cli;
476 	zend_string *temporary_value;
477 
478 	if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
479 		temporary_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL );
480 	} else if (ini_entry->value) {
481 		temporary_value = ini_entry->value;
482 	} else {
483 		temporary_value = NULL;
484 	}
485 
486 	mode = php_get_display_errors_mode(temporary_value);
487 
488 	/* Display 'On' for other SAPIs instead of STDOUT or STDERR */
489 	cgi_or_cli = (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "cgi") || !strcmp(sapi_module.name, "phpdbg"));
490 
491 	switch (mode) {
492 		case PHP_DISPLAY_ERRORS_STDERR:
493 			if (cgi_or_cli ) {
494 				PUTS("STDERR");
495 			} else {
496 				PUTS("On");
497 			}
498 			break;
499 
500 		case PHP_DISPLAY_ERRORS_STDOUT:
501 			if (cgi_or_cli ) {
502 				PUTS("STDOUT");
503 			} else {
504 				PUTS("On");
505 			}
506 			break;
507 
508 		default:
509 			PUTS("Off");
510 			break;
511 	}
512 }
513 /* }}} */
514 
php_get_internal_encoding(void)515 PHPAPI const char *php_get_internal_encoding(void) {
516 	if (PG(internal_encoding) && PG(internal_encoding)[0]) {
517 		return PG(internal_encoding);
518 	} else if (SG(default_charset) && SG(default_charset)[0]) {
519 		return SG(default_charset);
520 	}
521 	return "UTF-8";
522 }
523 
php_get_input_encoding(void)524 PHPAPI const char *php_get_input_encoding(void) {
525 	if (PG(input_encoding) && PG(input_encoding)[0]) {
526 		return PG(input_encoding);
527 	} else if (SG(default_charset) && SG(default_charset)[0]) {
528 		return SG(default_charset);
529 	}
530 	return "UTF-8";
531 }
532 
php_get_output_encoding(void)533 PHPAPI const char *php_get_output_encoding(void) {
534 	if (PG(output_encoding) && PG(output_encoding)[0]) {
535 		return PG(output_encoding);
536 	} else if (SG(default_charset) && SG(default_charset)[0]) {
537 		return SG(default_charset);
538 	}
539 	return "UTF-8";
540 }
541 
542 PHPAPI void (*php_internal_encoding_changed)(void) = NULL;
543 
544 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateDefaultCharset)545 static PHP_INI_MH(OnUpdateDefaultCharset)
546 {
547 	if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value))
548 		|| strpbrk(ZSTR_VAL(new_value), "\r\n")) {
549 		return FAILURE;
550 	}
551 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
552 	if (php_internal_encoding_changed) {
553 		php_internal_encoding_changed();
554 	}
555 	if (new_value) {
556 #ifdef PHP_WIN32
557 		php_win32_cp_do_update(ZSTR_VAL(new_value));
558 #endif
559 	}
560 	return SUCCESS;
561 }
562 /* }}} */
563 
564 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateDefaultMimeTye)565 static PHP_INI_MH(OnUpdateDefaultMimeTye)
566 {
567 	if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value))
568 		|| strpbrk(ZSTR_VAL(new_value), "\r\n")) {
569 		return FAILURE;
570 	}
571 	return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
572 }
573 /* }}} */
574 
575 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateInternalEncoding)576 static PHP_INI_MH(OnUpdateInternalEncoding)
577 {
578 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
579 	if (php_internal_encoding_changed) {
580 		php_internal_encoding_changed();
581 	}
582 	if (new_value) {
583 #ifdef PHP_WIN32
584 		php_win32_cp_do_update(ZSTR_VAL(new_value));
585 #endif
586 	}
587 	return SUCCESS;
588 }
589 /* }}} */
590 
591 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateInputEncoding)592 static PHP_INI_MH(OnUpdateInputEncoding)
593 {
594 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
595 	if (php_internal_encoding_changed) {
596 		php_internal_encoding_changed();
597 	}
598 	if (new_value) {
599 #ifdef PHP_WIN32
600 		php_win32_cp_do_update(NULL);
601 #endif
602 	}
603 	return SUCCESS;
604 }
605 /* }}} */
606 
607 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateOutputEncoding)608 static PHP_INI_MH(OnUpdateOutputEncoding)
609 {
610 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
611 	if (php_internal_encoding_changed) {
612 		php_internal_encoding_changed();
613 	}
614 	if (new_value) {
615 #ifdef PHP_WIN32
616 		php_win32_cp_do_update(NULL);
617 #endif
618 	}
619 	return SUCCESS;
620 }
621 /* }}} */
622 
623 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateErrorLog)624 static PHP_INI_MH(OnUpdateErrorLog)
625 {
626 	/* Only do the safemode/open_basedir check at runtime */
627 	if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) &&
628 			new_value && zend_string_equals_literal(new_value, "syslog")) {
629 		if (PG(open_basedir) && php_check_open_basedir(ZSTR_VAL(new_value))) {
630 			return FAILURE;
631 		}
632 	}
633 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
634 	return SUCCESS;
635 }
636 /* }}} */
637 
638 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnUpdateMailLog)639 static PHP_INI_MH(OnUpdateMailLog)
640 {
641 	/* Only do the safemode/open_basedir check at runtime */
642 	if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value) {
643 		if (PG(open_basedir) && php_check_open_basedir(ZSTR_VAL(new_value))) {
644 			return FAILURE;
645 		}
646 	}
647 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
648 	return SUCCESS;
649 }
650 /* }}} */
651 
652 /* {{{ PHP_INI_MH */
PHP_INI_MH(OnChangeMailForceExtra)653 static PHP_INI_MH(OnChangeMailForceExtra)
654 {
655 	/* Don't allow changing it in htaccess */
656 	if (stage == PHP_INI_STAGE_HTACCESS) {
657 			return FAILURE;
658 	}
659 	return SUCCESS;
660 }
661 /* }}} */
662 
663 /* defined in browscap.c */
664 PHP_INI_MH(OnChangeBrowscap);
665 
666 
667 /* Need to be read from the environment (?):
668  * PHP_AUTO_PREPEND_FILE
669  * PHP_AUTO_APPEND_FILE
670  * PHP_DOCUMENT_ROOT
671  * PHP_USER_DIR
672  * PHP_INCLUDE_PATH
673  */
674 
675  /* Windows use the internal mail */
676 #if defined(PHP_WIN32)
677 # define DEFAULT_SENDMAIL_PATH NULL
678 #else
679 # define DEFAULT_SENDMAIL_PATH PHP_PROG_SENDMAIL " -t -i"
680 #endif
681 
682 /* {{{ PHP_INI */
683 PHP_INI_BEGIN()
684 	PHP_INI_ENTRY_EX("highlight.comment",		HL_COMMENT_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
685 	PHP_INI_ENTRY_EX("highlight.default",		HL_DEFAULT_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
686 	PHP_INI_ENTRY_EX("highlight.html",			HL_HTML_COLOR,		PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
687 	PHP_INI_ENTRY_EX("highlight.keyword",		HL_KEYWORD_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
688 	PHP_INI_ENTRY_EX("highlight.string",		HL_STRING_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
689 
690 	STD_PHP_INI_ENTRY_EX("display_errors",		"1",		PHP_INI_ALL,		OnUpdateDisplayErrors,	display_errors,			php_core_globals,	core_globals, display_errors_mode)
691 	STD_PHP_INI_BOOLEAN("display_startup_errors",	"1",	PHP_INI_ALL,		OnUpdateBool,			display_startup_errors,	php_core_globals,	core_globals)
692 	STD_PHP_INI_BOOLEAN("enable_dl",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			enable_dl,				php_core_globals,	core_globals)
693 	STD_PHP_INI_BOOLEAN("expose_php",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			expose_php,				php_core_globals,	core_globals)
694 	STD_PHP_INI_ENTRY("docref_root", 			"", 		PHP_INI_ALL,		OnUpdateString,			docref_root,			php_core_globals,	core_globals)
695 	STD_PHP_INI_ENTRY("docref_ext",				"",			PHP_INI_ALL,		OnUpdateString,			docref_ext,				php_core_globals,	core_globals)
696 	STD_PHP_INI_BOOLEAN("html_errors",			"1",		PHP_INI_ALL,		OnUpdateBool,			html_errors,			php_core_globals,	core_globals)
697 	STD_PHP_INI_BOOLEAN("xmlrpc_errors",		"0",		PHP_INI_SYSTEM,		OnUpdateBool,			xmlrpc_errors,			php_core_globals,	core_globals)
698 	STD_PHP_INI_ENTRY("xmlrpc_error_number",	"0",		PHP_INI_ALL,		OnUpdateLong,			xmlrpc_error_number,	php_core_globals,	core_globals)
699 	STD_PHP_INI_ENTRY("max_input_time",			"-1",	PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			max_input_time,	php_core_globals,	core_globals)
700 	STD_PHP_INI_BOOLEAN("ignore_user_abort",	"0",		PHP_INI_ALL,		OnUpdateBool,			ignore_user_abort,		php_core_globals,	core_globals)
701 	STD_PHP_INI_BOOLEAN("implicit_flush",		"0",		PHP_INI_ALL,		OnUpdateBool,			implicit_flush,			php_core_globals,	core_globals)
702 	STD_PHP_INI_BOOLEAN("log_errors",			"0",		PHP_INI_ALL,		OnUpdateBool,			log_errors,				php_core_globals,	core_globals)
703 	STD_PHP_INI_BOOLEAN("ignore_repeated_errors",	"0",	PHP_INI_ALL,		OnUpdateBool,			ignore_repeated_errors,	php_core_globals,	core_globals)
704 	STD_PHP_INI_BOOLEAN("ignore_repeated_source",	"0",	PHP_INI_ALL,		OnUpdateBool,			ignore_repeated_source,	php_core_globals,	core_globals)
705 	STD_PHP_INI_BOOLEAN("report_memleaks",		"1",		PHP_INI_ALL,		OnUpdateBool,			report_memleaks,		php_core_globals,	core_globals)
706 	STD_PHP_INI_BOOLEAN("report_zend_debug",	"0",		PHP_INI_ALL,		OnUpdateBool,			report_zend_debug,		php_core_globals,	core_globals)
707 	STD_PHP_INI_ENTRY("output_buffering",		"0",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateLong,	output_buffering,		php_core_globals,	core_globals)
708 	STD_PHP_INI_ENTRY("output_handler",			NULL,		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateString,	output_handler,		php_core_globals,	core_globals)
709 	STD_PHP_INI_BOOLEAN("register_argc_argv",	"1",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateBool,	register_argc_argv,		php_core_globals,	core_globals)
710 	STD_PHP_INI_BOOLEAN("auto_globals_jit",		"1",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateBool,	auto_globals_jit,	php_core_globals,	core_globals)
711 	STD_PHP_INI_BOOLEAN("short_open_tag",	DEFAULT_SHORT_OPEN_TAG,	PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateBool,			short_tags,				zend_compiler_globals,	compiler_globals)
712 
713 	STD_PHP_INI_ENTRY("unserialize_callback_func",	NULL,	PHP_INI_ALL,		OnUpdateString,			unserialize_callback_func,	php_core_globals,	core_globals)
714 	STD_PHP_INI_ENTRY("serialize_precision",	"-1",	PHP_INI_ALL,		OnSetSerializePrecision,			serialize_precision,	php_core_globals,	core_globals)
715 	STD_PHP_INI_ENTRY("arg_separator.output",	"&",		PHP_INI_ALL,		OnUpdateStringUnempty,	arg_separator.output,	php_core_globals,	core_globals)
716 	STD_PHP_INI_ENTRY("arg_separator.input",	"&",		PHP_INI_SYSTEM|PHP_INI_PERDIR,	OnUpdateStringUnempty,	arg_separator.input,	php_core_globals,	core_globals)
717 
718 	STD_PHP_INI_ENTRY("auto_append_file",		NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,			auto_append_file,		php_core_globals,	core_globals)
719 	STD_PHP_INI_ENTRY("auto_prepend_file",		NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,			auto_prepend_file,		php_core_globals,	core_globals)
720 	STD_PHP_INI_ENTRY("doc_root",				NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	doc_root,				php_core_globals,	core_globals)
721 	STD_PHP_INI_ENTRY("default_charset",		PHP_DEFAULT_CHARSET,	PHP_INI_ALL,	OnUpdateDefaultCharset,			default_charset,		sapi_globals_struct, sapi_globals)
722 	STD_PHP_INI_ENTRY("default_mimetype",		SAPI_DEFAULT_MIMETYPE,	PHP_INI_ALL,	OnUpdateDefaultMimeTye,			default_mimetype,		sapi_globals_struct, sapi_globals)
723 	STD_PHP_INI_ENTRY("internal_encoding",		NULL,			PHP_INI_ALL,	OnUpdateInternalEncoding,	internal_encoding,	php_core_globals, core_globals)
724 	STD_PHP_INI_ENTRY("input_encoding",			NULL,			PHP_INI_ALL,	OnUpdateInputEncoding,				input_encoding,		php_core_globals, core_globals)
725 	STD_PHP_INI_ENTRY("output_encoding",		NULL,			PHP_INI_ALL,	OnUpdateOutputEncoding,				output_encoding,	php_core_globals, core_globals)
726 	STD_PHP_INI_ENTRY("error_log",				NULL,			PHP_INI_ALL,		OnUpdateErrorLog,				error_log,				php_core_globals,	core_globals)
727 	STD_PHP_INI_ENTRY("error_log_mode",			"0644",			PHP_INI_ALL,		OnUpdateLong,					error_log_mode,			php_core_globals,	core_globals)
728 	STD_PHP_INI_ENTRY("extension_dir",			PHP_EXTENSION_DIR,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	extension_dir,			php_core_globals,	core_globals)
729 	STD_PHP_INI_ENTRY("sys_temp_dir",			NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	sys_temp_dir,			php_core_globals,	core_globals)
730 	STD_PHP_INI_ENTRY("include_path",			PHP_INCLUDE_PATH,		PHP_INI_ALL,		OnUpdateStringUnempty,	include_path,			php_core_globals,	core_globals)
731 	PHP_INI_ENTRY("max_execution_time",			"30",		PHP_INI_ALL,			OnUpdateTimeout)
732 	STD_PHP_INI_ENTRY("open_basedir",			NULL,		PHP_INI_ALL,		OnUpdateBaseDir,			open_basedir,			php_core_globals,	core_globals)
733 
734 	STD_PHP_INI_BOOLEAN("file_uploads",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			file_uploads,			php_core_globals,	core_globals)
735 	STD_PHP_INI_ENTRY("upload_max_filesize",	"2M",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			upload_max_filesize,	php_core_globals,	core_globals)
736 	STD_PHP_INI_ENTRY("post_max_size",			"8M",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			post_max_size,			sapi_globals_struct,sapi_globals)
737 	STD_PHP_INI_ENTRY("upload_tmp_dir",			NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	upload_tmp_dir,			php_core_globals,	core_globals)
738 	STD_PHP_INI_ENTRY("max_input_nesting_level", "64",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLongGEZero,	max_input_nesting_level,			php_core_globals,	core_globals)
739 	STD_PHP_INI_ENTRY("max_input_vars",			"1000",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLongGEZero,	max_input_vars,						php_core_globals,	core_globals)
740 
741 	STD_PHP_INI_ENTRY("user_dir",				NULL,		PHP_INI_SYSTEM,		OnUpdateString,			user_dir,				php_core_globals,	core_globals)
742 	STD_PHP_INI_ENTRY("variables_order",		"EGPCS",	PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateStringUnempty,	variables_order,		php_core_globals,	core_globals)
743 	STD_PHP_INI_ENTRY("request_order",			NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,	request_order,		php_core_globals,	core_globals)
744 
745 	STD_PHP_INI_ENTRY("error_append_string",	NULL,		PHP_INI_ALL,		OnUpdateString,			error_append_string,	php_core_globals,	core_globals)
746 	STD_PHP_INI_ENTRY("error_prepend_string",	NULL,		PHP_INI_ALL,		OnUpdateString,			error_prepend_string,	php_core_globals,	core_globals)
747 
748 	PHP_INI_ENTRY("SMTP",						"localhost",PHP_INI_ALL,		NULL)
749 	PHP_INI_ENTRY("smtp_port",					"25",		PHP_INI_ALL,		NULL)
750 	STD_PHP_INI_BOOLEAN("mail.add_x_header",			"0",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateBool,			mail_x_header,			php_core_globals,	core_globals)
751 	STD_PHP_INI_BOOLEAN("mail.mixed_lf_and_crlf",			"0",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateBool,			mail_mixed_lf_and_crlf,			php_core_globals,	core_globals)
752 	STD_PHP_INI_ENTRY("mail.log",					NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateMailLog,			mail_log,			php_core_globals,	core_globals)
753 	PHP_INI_ENTRY("browscap",					NULL,		PHP_INI_SYSTEM,		OnChangeBrowscap)
754 	PHP_INI_ENTRY("memory_limit",				"128M",		PHP_INI_ALL,		OnChangeMemoryLimit)
755 	PHP_INI_ENTRY("precision",					"14",		PHP_INI_ALL,		OnSetPrecision)
756 	PHP_INI_ENTRY("sendmail_from",				NULL,		PHP_INI_ALL,		NULL)
757 	PHP_INI_ENTRY("sendmail_path",	DEFAULT_SENDMAIL_PATH,	PHP_INI_SYSTEM,		NULL)
758 	PHP_INI_ENTRY("mail.force_extra_parameters",NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnChangeMailForceExtra)
759 	PHP_INI_ENTRY("disable_functions",			"",			PHP_INI_SYSTEM,		NULL)
760 	PHP_INI_ENTRY("disable_classes",			"",			PHP_INI_SYSTEM,		NULL)
761 	PHP_INI_ENTRY("max_file_uploads",			"20",			PHP_INI_SYSTEM|PHP_INI_PERDIR,		NULL)
762 	PHP_INI_ENTRY("max_multipart_body_parts",	"-1",			PHP_INI_SYSTEM|PHP_INI_PERDIR,		NULL)
763 
764 	STD_PHP_INI_BOOLEAN("allow_url_fopen",		"1",		PHP_INI_SYSTEM,		OnUpdateBool,		allow_url_fopen,		php_core_globals,		core_globals)
765 	STD_PHP_INI_BOOLEAN("allow_url_include",	"0",		PHP_INI_SYSTEM,		OnUpdateBool,		allow_url_include,		php_core_globals,		core_globals)
766 	STD_PHP_INI_BOOLEAN("enable_post_data_reading",	"1",	PHP_INI_SYSTEM|PHP_INI_PERDIR,	OnUpdateBool,	enable_post_data_reading,	php_core_globals,	core_globals)
767 
768 	STD_PHP_INI_ENTRY("realpath_cache_size",	"4096K",	PHP_INI_SYSTEM,		OnUpdateLong,	realpath_cache_size_limit,	virtual_cwd_globals,	cwd_globals)
769 	STD_PHP_INI_ENTRY("realpath_cache_ttl",		"120",		PHP_INI_SYSTEM,		OnUpdateLong,	realpath_cache_ttl,			virtual_cwd_globals,	cwd_globals)
770 
771 	STD_PHP_INI_ENTRY("user_ini.filename",		".user.ini",	PHP_INI_SYSTEM,		OnUpdateString,		user_ini_filename,	php_core_globals,		core_globals)
772 	STD_PHP_INI_ENTRY("user_ini.cache_ttl",		"300",			PHP_INI_SYSTEM,		OnUpdateLong,		user_ini_cache_ttl,	php_core_globals,		core_globals)
773 	STD_PHP_INI_ENTRY("hard_timeout",			"2",			PHP_INI_SYSTEM,		OnUpdateLong,		hard_timeout,		zend_executor_globals,	executor_globals)
774 #ifdef PHP_WIN32
775 	STD_PHP_INI_BOOLEAN("windows.show_crt_warning",		"0",		PHP_INI_ALL,		OnUpdateBool,			windows_show_crt_warning,			php_core_globals,	core_globals)
776 #endif
777 	STD_PHP_INI_ENTRY("syslog.facility",		"LOG_USER",		PHP_INI_SYSTEM,		OnSetFacility,		syslog_facility,	php_core_globals,		core_globals)
778 	STD_PHP_INI_ENTRY("syslog.ident",		"php",			PHP_INI_SYSTEM,		OnUpdateString,		syslog_ident,		php_core_globals,		core_globals)
779 	STD_PHP_INI_ENTRY("syslog.filter",		"no-ctrl",		PHP_INI_ALL,		OnSetLogFilter,		syslog_filter,		php_core_globals, 		core_globals)
780 PHP_INI_END()
781 /* }}} */
782 
783 /* True globals (no need for thread safety */
784 /* But don't make them a single int bitfield */
785 static bool module_initialized = false;
786 static bool module_startup = true;
787 static bool module_shutdown = false;
788 
789 /* {{{ php_during_module_startup */
php_during_module_startup(void)790 PHPAPI bool php_during_module_startup(void)
791 {
792 	return module_startup;
793 }
794 /* }}} */
795 
796 /* {{{ php_during_module_shutdown */
php_during_module_shutdown(void)797 PHPAPI bool php_during_module_shutdown(void)
798 {
799 	return module_shutdown;
800 }
801 /* }}} */
802 
803 /* {{{ php_get_module_initialized */
php_get_module_initialized(void)804 PHPAPI bool php_get_module_initialized(void)
805 {
806 	return module_initialized;
807 }
808 /* }}} */
809 
810 /* {{{ php_log_err_with_severity */
php_log_err_with_severity(const char * log_message,int syslog_type_int)811 PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int syslog_type_int)
812 {
813 	int fd = -1;
814 	time_t error_time;
815 
816 	if (PG(in_error_log)) {
817 		/* prevent recursive invocation */
818 		return;
819 	}
820 	PG(in_error_log) = 1;
821 
822 	/* Try to use the specified logging location. */
823 	if (PG(error_log) != NULL) {
824 		int error_log_mode;
825 
826 #ifdef HAVE_SYSLOG_H
827 		if (!strcmp(PG(error_log), "syslog")) {
828 			php_syslog(syslog_type_int, "%s", log_message);
829 			PG(in_error_log) = 0;
830 			return;
831 		}
832 #endif
833 
834 		error_log_mode = 0644;
835 
836 		if (PG(error_log_mode) > 0 && PG(error_log_mode) <= 0777) {
837 			error_log_mode = PG(error_log_mode);
838 		}
839 
840 		fd = VCWD_OPEN_MODE(PG(error_log), O_CREAT | O_APPEND | O_WRONLY, error_log_mode);
841 		if (fd != -1) {
842 			char *tmp;
843 			size_t len;
844 			zend_string *error_time_str;
845 
846 			time(&error_time);
847 #ifdef ZTS
848 			if (!php_during_module_startup()) {
849 				error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1);
850 			} else {
851 				error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 0);
852 			}
853 #else
854 			error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1);
855 #endif
856 			len = spprintf(&tmp, 0, "[%s] %s%s", ZSTR_VAL(error_time_str), log_message, PHP_EOL);
857 #ifdef PHP_WIN32
858 			php_flock(fd, LOCK_EX);
859 			/* XXX should eventually write in a loop if len > UINT_MAX */
860 			php_ignore_value(write(fd, tmp, (unsigned)len));
861 			php_flock(fd, LOCK_UN);
862 #else
863 			php_ignore_value(write(fd, tmp, len));
864 #endif
865 			efree(tmp);
866 			zend_string_free(error_time_str);
867 			close(fd);
868 			PG(in_error_log) = 0;
869 			return;
870 		}
871 	}
872 
873 	/* Otherwise fall back to the default logging location, if we have one */
874 
875 	if (sapi_module.log_message) {
876 		sapi_module.log_message(log_message, syslog_type_int);
877 	}
878 	PG(in_error_log) = 0;
879 }
880 /* }}} */
881 
882 /* {{{ php_write
883    wrapper for modules to use PHPWRITE */
php_write(void * buf,size_t size)884 PHPAPI size_t php_write(void *buf, size_t size)
885 {
886 	return PHPWRITE(buf, size);
887 }
888 /* }}} */
889 
890 /* {{{ php_printf */
php_printf(const char * format,...)891 PHPAPI size_t php_printf(const char *format, ...)
892 {
893 	va_list args;
894 	size_t ret;
895 	char *buffer;
896 	size_t size;
897 
898 	va_start(args, format);
899 	size = vspprintf(&buffer, 0, format, args);
900 	ret = PHPWRITE(buffer, size);
901 	efree(buffer);
902 	va_end(args);
903 
904 	return ret;
905 }
906 /* }}} */
907 
908 /* {{{ php_printf_unchecked */
php_printf_unchecked(const char * format,...)909 PHPAPI size_t php_printf_unchecked(const char *format, ...)
910 {
911 	va_list args;
912 	size_t ret;
913 	char *buffer;
914 	size_t size;
915 
916 	va_start(args, format);
917 	size = vspprintf(&buffer, 0, format, args);
918 	ret = PHPWRITE(buffer, size);
919 	efree(buffer);
920 	va_end(args);
921 
922 	return ret;
923 }
924 /* }}} */
925 
escape_html(const char * buffer,size_t buffer_len)926 static zend_string *escape_html(const char *buffer, size_t buffer_len) {
927 	zend_string *result = php_escape_html_entities_ex(
928 		(const unsigned char *) buffer, buffer_len, 0, ENT_COMPAT,
929 		/* charset_hint */ NULL, /* double_encode */ 1, /* quiet */ 1);
930 	if (!result || ZSTR_LEN(result) == 0) {
931 		/* Retry with substituting invalid chars on fail. */
932 		result = php_escape_html_entities_ex(
933 			(const unsigned char *) buffer, buffer_len, 0, ENT_COMPAT | ENT_HTML_SUBSTITUTE_ERRORS,
934 			/* charset_hint */ NULL, /* double_encode */ 1, /* quiet */ 1);
935 	}
936 	return result;
937 }
938 
939 /* {{{ php_verror */
940 /* php_verror is called from php_error_docref<n> functions.
941  * Its purpose is to unify error messages and automatically generate clickable
942  * html error messages if corresponding ini setting (html_errors) is activated.
943  * See: CODING_STANDARDS.md for details.
944  */
php_verror(const char * docref,const char * params,int type,const char * format,va_list args)945 PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int type, const char *format, va_list args)
946 {
947 	zend_string *replace_origin = NULL;
948 	char *docref_buf = NULL, *target = NULL;
949 	char *docref_target = "", *docref_root = "";
950 	char *p;
951 	const char *space = "";
952 	const char *class_name = "";
953 	const char *function;
954 	int origin_len;
955 	char *origin;
956 	zend_string *message;
957 	int is_function = 0;
958 
959 	/* get error text into buffer and escape for html if necessary */
960 	zend_string *buffer = vstrpprintf(0, format, args);
961 
962 	if (PG(html_errors)) {
963 		zend_string *replace_buffer = escape_html(ZSTR_VAL(buffer), ZSTR_LEN(buffer));
964 		zend_string_free(buffer);
965 
966 		if (replace_buffer) {
967 			buffer = replace_buffer;
968 		} else {
969 			buffer = zend_empty_string;
970 		}
971 	}
972 
973 	/* which function caused the problem if any at all */
974 	if (php_during_module_startup()) {
975 		function = "PHP Startup";
976 	} else if (php_during_module_shutdown()) {
977 		function = "PHP Shutdown";
978 	} else if (PG(during_request_startup)) {
979 		function = "PHP Request Startup";
980 	} else if (EG(current_execute_data) &&
981 				EG(current_execute_data)->func &&
982 				ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
983 				EG(current_execute_data)->opline &&
984 				EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL
985 	) {
986 		switch (EG(current_execute_data)->opline->extended_value) {
987 			case ZEND_EVAL:
988 				function = "eval";
989 				is_function = 1;
990 				break;
991 			case ZEND_INCLUDE:
992 				function = "include";
993 				is_function = 1;
994 				break;
995 			case ZEND_INCLUDE_ONCE:
996 				function = "include_once";
997 				is_function = 1;
998 				break;
999 			case ZEND_REQUIRE:
1000 				function = "require";
1001 				is_function = 1;
1002 				break;
1003 			case ZEND_REQUIRE_ONCE:
1004 				function = "require_once";
1005 				is_function = 1;
1006 				break;
1007 			default:
1008 				function = "Unknown";
1009 		}
1010 	} else if ((function = get_active_function_name()) && strlen(function)) {
1011 		is_function = 1;
1012 		class_name = get_active_class_name(&space);
1013 	} else if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
1014 		function = "PHP Request Shutdown";
1015 	} else {
1016 		function = "Unknown";
1017 	}
1018 
1019 	/* if we still have memory then format the origin */
1020 	if (is_function) {
1021 		origin_len = (int)spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, params);
1022 	} else {
1023 		origin_len = (int)spprintf(&origin, 0, "%s", function);
1024 	}
1025 
1026 	if (PG(html_errors)) {
1027 		replace_origin = escape_html(origin, origin_len);
1028 		efree(origin);
1029 		origin = ZSTR_VAL(replace_origin);
1030 	}
1031 
1032 	/* origin and buffer available, so let's come up with the error message */
1033 	if (docref && docref[0] == '#') {
1034 		docref_target = strchr(docref, '#');
1035 		docref = NULL;
1036 	}
1037 
1038 	/* no docref given but function is known (the default) */
1039 	if (!docref && is_function) {
1040 		int doclen;
1041 		while (*function == '_') {
1042 			function++;
1043 		}
1044 		if (space[0] == '\0') {
1045 			doclen = (int)spprintf(&docref_buf, 0, "function.%s", function);
1046 		} else {
1047 			doclen = (int)spprintf(&docref_buf, 0, "%s.%s", class_name, function);
1048 		}
1049 		while((p = strchr(docref_buf, '_')) != NULL) {
1050 			*p = '-';
1051 		}
1052 		zend_str_tolower(docref_buf, doclen);
1053 		docref = docref_buf;
1054 	}
1055 
1056 	/* we have a docref for a function AND
1057 	 * - we show errors in html mode AND
1058 	 * - the user wants to see the links
1059 	 */
1060 	if (docref && is_function && PG(html_errors) && strlen(PG(docref_root))) {
1061 		if (strncmp(docref, "http://", 7)) {
1062 			/* We don't have 'http://' so we use docref_root */
1063 
1064 			char *ref;  /* temp copy for duplicated docref */
1065 
1066 			docref_root = PG(docref_root);
1067 
1068 			ref = estrdup(docref);
1069 			if (docref_buf) {
1070 				efree(docref_buf);
1071 			}
1072 			docref_buf = ref;
1073 			/* strip of the target if any */
1074 			p = strrchr(ref, '#');
1075 			if (p) {
1076 				target = estrdup(p);
1077 				if (target) {
1078 					docref_target = target;
1079 					*p = '\0';
1080 				}
1081 			}
1082 			/* add the extension if it is set in ini */
1083 			if (PG(docref_ext) && strlen(PG(docref_ext))) {
1084 				spprintf(&docref_buf, 0, "%s%s", ref, PG(docref_ext));
1085 				efree(ref);
1086 			}
1087 			docref = docref_buf;
1088 		}
1089 		/* display html formatted or only show the additional links */
1090 		if (PG(html_errors)) {
1091 			message = zend_strpprintf_unchecked(0, "%s [<a href='%s%s%s'>%s</a>]: %S", origin, docref_root, docref, docref_target, docref, buffer);
1092 		} else {
1093 			message = zend_strpprintf_unchecked(0, "%s [%s%s%s]: %S", origin, docref_root, docref, docref_target, buffer);
1094 		}
1095 		if (target) {
1096 			efree(target);
1097 		}
1098 	} else {
1099 		message = zend_strpprintf_unchecked(0, "%s: %S", origin, buffer);
1100 	}
1101 	if (replace_origin) {
1102 		zend_string_free(replace_origin);
1103 	} else {
1104 		efree(origin);
1105 	}
1106 	if (docref_buf) {
1107 		efree(docref_buf);
1108 	}
1109 
1110 	zend_string_free(buffer);
1111 
1112 	zend_error_zstr(type, message);
1113 	zend_string_release(message);
1114 }
1115 /* }}} */
1116 
1117 /* {{{ php_error_docref */
1118 /* Generate an error which links to docref or the php.net documentation if docref is NULL */
1119 #define php_error_docref_impl(docref, type, format) do {\
1120 		va_list args; \
1121 		va_start(args, format); \
1122 		php_verror(docref, "", type, format, args); \
1123 		va_end(args); \
1124 	} while (0)
1125 
php_error_docref(const char * docref,int type,const char * format,...)1126 PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format, ...)
1127 {
1128 	php_error_docref_impl(docref, type, format);
1129 }
1130 
php_error_docref_unchecked(const char * docref,int type,const char * format,...)1131 PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format, ...)
1132 {
1133 	php_error_docref_impl(docref, type, format);
1134 }
1135 /* }}} */
1136 
1137 /* {{{ php_error_docref1 */
1138 /* See: CODING_STANDARDS.md for details. */
php_error_docref1(const char * docref,const char * param1,int type,const char * format,...)1139 PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, int type, const char *format, ...)
1140 {
1141 	va_list args;
1142 
1143 	va_start(args, format);
1144 	php_verror(docref, param1, type, format, args);
1145 	va_end(args);
1146 }
1147 /* }}} */
1148 
1149 /* {{{ php_error_docref2 */
1150 /* See: CODING_STANDARDS.md for details. */
php_error_docref2(const char * docref,const char * param1,const char * param2,int type,const char * format,...)1151 PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format, ...)
1152 {
1153 	char *params;
1154 	va_list args;
1155 
1156 	spprintf(&params, 0, "%s,%s", param1, param2);
1157 	va_start(args, format);
1158 	php_verror(docref, params ? params : "...", type, format, args);
1159 	va_end(args);
1160 	if (params) {
1161 		efree(params);
1162 	}
1163 }
1164 /* }}} */
1165 
1166 #ifdef PHP_WIN32
php_win32_docref1_from_error(DWORD error,const char * param1)1167 PHPAPI ZEND_COLD void php_win32_docref1_from_error(DWORD error, const char *param1) {
1168 	char *buf = php_win32_error_to_msg(error);
1169 	size_t buf_len;
1170 
1171 	buf_len = strlen(buf);
1172 	if (buf_len >= 2) {
1173 		buf[buf_len - 1] = '\0';
1174 		buf[buf_len - 2] = '\0';
1175 	}
1176 	php_error_docref1(NULL, param1, E_WARNING, "%s (code: %lu)", buf, error);
1177 	php_win32_error_msg_free(buf);
1178 }
1179 
php_win32_docref2_from_error(DWORD error,const char * param1,const char * param2)1180 PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2) {
1181 	char *buf = php_win32_error_to_msg(error);
1182 	php_error_docref2(NULL, param1, param2, E_WARNING, "%s (code: %lu)", buf, error);
1183 	php_win32_error_msg_free(buf);
1184 }
1185 #endif
1186 
1187 /* {{{ php_html_puts */
php_html_puts(const char * str,size_t size)1188 PHPAPI void php_html_puts(const char *str, size_t size)
1189 {
1190 	zend_html_puts(str, size);
1191 }
1192 /* }}} */
1193 
clear_last_error(void)1194 static void clear_last_error(void) {
1195 	if (PG(last_error_message)) {
1196 		zend_string_release(PG(last_error_message));
1197 		PG(last_error_message) = NULL;
1198 	}
1199 	if (PG(last_error_file)) {
1200 		zend_string_release(PG(last_error_file));
1201 		PG(last_error_file) = NULL;
1202 	}
1203 }
1204 
1205 #if ZEND_DEBUG
1206 /* {{{ report_zend_debug_error_notify_cb */
report_zend_debug_error_notify_cb(int type,zend_string * error_filename,uint32_t error_lineno,zend_string * message)1207 static void report_zend_debug_error_notify_cb(int type, zend_string *error_filename, uint32_t error_lineno, zend_string *message)
1208 {
1209 	if (PG(report_zend_debug)) {
1210 		bool trigger_break;
1211 
1212 		switch (type) {
1213 			case E_ERROR:
1214 			case E_CORE_ERROR:
1215 			case E_COMPILE_ERROR:
1216 			case E_USER_ERROR:
1217 				trigger_break=1;
1218 				break;
1219 			default:
1220 				trigger_break=0;
1221 				break;
1222 		}
1223 
1224 		zend_output_debug_string(trigger_break, "%s(%" PRIu32 ") : %s", ZSTR_VAL(error_filename), error_lineno, ZSTR_VAL(message));
1225 	}
1226 }
1227 /* }}} */
1228 #endif
1229 
1230 /* {{{ php_error_cb
1231  extended error handling function */
php_error_cb(int orig_type,zend_string * error_filename,const uint32_t error_lineno,zend_string * message)1232 static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
1233 {
1234 	bool display;
1235 	int type = orig_type & E_ALL;
1236 
1237 	/* check for repeated errors to be ignored */
1238 	if (PG(ignore_repeated_errors) && PG(last_error_message)) {
1239 		/* no check for PG(last_error_file) is needed since it cannot
1240 		 * be NULL if PG(last_error_message) is not NULL */
1241 		if (!zend_string_equals(PG(last_error_message), message)
1242 			|| (!PG(ignore_repeated_source)
1243 				&& ((PG(last_error_lineno) != (int)error_lineno)
1244 					|| !zend_string_equals(PG(last_error_file), error_filename)))) {
1245 			display = 1;
1246 		} else {
1247 			display = 0;
1248 		}
1249 	} else {
1250 		display = 1;
1251 	}
1252 
1253 	/* according to error handling mode, throw exception or show it */
1254 	if (EG(error_handling) == EH_THROW) {
1255 		switch (type) {
1256 			case E_WARNING:
1257 			case E_CORE_WARNING:
1258 			case E_COMPILE_WARNING:
1259 			case E_USER_WARNING:
1260 				/* throw an exception if we are in EH_THROW mode and the type is warning.
1261 				 * fatal errors are real errors and cannot be made exceptions.
1262 				 * exclude deprecated for the sake of BC to old damaged code.
1263 				 * notices are no errors and are not treated as such like E_WARNINGS.
1264 				 * DO NOT overwrite a pending exception.
1265 				 */
1266 				if (!EG(exception)) {
1267 					zend_throw_error_exception(EG(exception_class), message, 0, type);
1268 				}
1269 				return;
1270 			default:
1271 				break;
1272 		}
1273 	}
1274 
1275 	/* store the error if it has changed */
1276 	if (display) {
1277 		clear_last_error();
1278 		if (!error_filename) {
1279 			error_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
1280 		}
1281 		PG(last_error_type) = type;
1282 		PG(last_error_message) = zend_string_copy(message);
1283 		PG(last_error_file) = zend_string_copy(error_filename);
1284 		PG(last_error_lineno) = error_lineno;
1285 	}
1286 
1287 	if (zend_alloc_in_memory_limit_error_reporting()) {
1288 		php_output_discard_all();
1289 	}
1290 
1291 	/* display/log the error if necessary */
1292 	if (display && ((EG(error_reporting) & type) || (type & E_CORE))
1293 		&& (PG(log_errors) || PG(display_errors) || (!module_initialized))) {
1294 		char *error_type_str;
1295 		int syslog_type_int = LOG_NOTICE;
1296 
1297 		switch (type) {
1298 			case E_ERROR:
1299 			case E_CORE_ERROR:
1300 			case E_COMPILE_ERROR:
1301 			case E_USER_ERROR:
1302 				error_type_str = "Fatal error";
1303 				syslog_type_int = LOG_ERR;
1304 				break;
1305 			case E_RECOVERABLE_ERROR:
1306 				error_type_str = "Recoverable fatal error";
1307 				syslog_type_int = LOG_ERR;
1308 				break;
1309 			case E_WARNING:
1310 			case E_CORE_WARNING:
1311 			case E_COMPILE_WARNING:
1312 			case E_USER_WARNING:
1313 				error_type_str = "Warning";
1314 				syslog_type_int = LOG_WARNING;
1315 				break;
1316 			case E_PARSE:
1317 				error_type_str = "Parse error";
1318 				syslog_type_int = LOG_ERR;
1319 				break;
1320 			case E_NOTICE:
1321 			case E_USER_NOTICE:
1322 				error_type_str = "Notice";
1323 				syslog_type_int = LOG_NOTICE;
1324 				break;
1325 			case E_STRICT:
1326 				error_type_str = "Strict Standards";
1327 				syslog_type_int = LOG_INFO;
1328 				break;
1329 			case E_DEPRECATED:
1330 			case E_USER_DEPRECATED:
1331 				error_type_str = "Deprecated";
1332 				syslog_type_int = LOG_INFO;
1333 				break;
1334 			default:
1335 				error_type_str = "Unknown error";
1336 				break;
1337 		}
1338 
1339 		if (PG(log_errors)
1340 				|| (!module_initialized && (!PG(display_startup_errors) || !PG(display_errors)))) {
1341 			char *log_buffer;
1342 #ifdef PHP_WIN32
1343 			if (type == E_CORE_ERROR || type == E_CORE_WARNING) {
1344 				syslog(LOG_ALERT, "PHP %s: %s (%s)", error_type_str, ZSTR_VAL(message), GetCommandLine());
1345 			}
1346 #endif
1347 			spprintf(&log_buffer, 0, "PHP %s:  %s in %s on line %" PRIu32, error_type_str, ZSTR_VAL(message), ZSTR_VAL(error_filename), error_lineno);
1348 			php_log_err_with_severity(log_buffer, syslog_type_int);
1349 			efree(log_buffer);
1350 		}
1351 
1352 		if (PG(display_errors) && ((module_initialized && !PG(during_request_startup)) || (PG(display_startup_errors)))) {
1353 			if (PG(xmlrpc_errors)) {
1354 				php_printf("<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>" ZEND_LONG_FMT "</int></value></member><member><name>faultString</name><value><string>%s:%s in %s on line %" PRIu32 "</string></value></member></struct></value></fault></methodResponse>", PG(xmlrpc_error_number), error_type_str, ZSTR_VAL(message), ZSTR_VAL(error_filename), error_lineno);
1355 			} else {
1356 				char *prepend_string = INI_STR("error_prepend_string");
1357 				char *append_string = INI_STR("error_append_string");
1358 
1359 				if (PG(html_errors)) {
1360 					if (type == E_ERROR || type == E_PARSE) {
1361 						zend_string *buf = escape_html(ZSTR_VAL(message), ZSTR_LEN(message));
1362 						php_printf("%s<br />\n<b>%s</b>:  %s in <b>%s</b> on line <b>%" PRIu32 "</b><br />\n%s", STR_PRINT(prepend_string), error_type_str, ZSTR_VAL(buf), ZSTR_VAL(error_filename), error_lineno, STR_PRINT(append_string));
1363 						zend_string_free(buf);
1364 					} else {
1365 						php_printf_unchecked("%s<br />\n<b>%s</b>:  %S in <b>%s</b> on line <b>%" PRIu32 "</b><br />\n%s", STR_PRINT(prepend_string), error_type_str, message, ZSTR_VAL(error_filename), error_lineno, STR_PRINT(append_string));
1366 					}
1367 				} else {
1368 					/* Write CLI/CGI errors to stderr if display_errors = "stderr" */
1369 					if ((!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "cgi") || !strcmp(sapi_module.name, "phpdbg")) &&
1370 						PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR
1371 					) {
1372 						fprintf(stderr, "%s: ", error_type_str);
1373 						fwrite(ZSTR_VAL(message), sizeof(char), ZSTR_LEN(message), stderr);
1374 						fprintf(stderr, " in %s on line %" PRIu32 "\n", ZSTR_VAL(error_filename), error_lineno);
1375 #ifdef PHP_WIN32
1376 						fflush(stderr);
1377 #endif
1378 					} else {
1379 						php_printf_unchecked("%s\n%s: %S in %s on line %" PRIu32 "\n%s", STR_PRINT(prepend_string), error_type_str, message, ZSTR_VAL(error_filename), error_lineno, STR_PRINT(append_string));
1380 					}
1381 				}
1382 			}
1383 		}
1384 	}
1385 
1386 	/* Bail out if we can't recover */
1387 	switch (type) {
1388 		case E_CORE_ERROR:
1389 			if(!module_initialized) {
1390 				/* bad error in module startup - no way we can live with this */
1391 				exit(-2);
1392 			}
1393 		ZEND_FALLTHROUGH;
1394 		case E_ERROR:
1395 		case E_RECOVERABLE_ERROR:
1396 		case E_PARSE:
1397 		case E_COMPILE_ERROR:
1398 		case E_USER_ERROR:
1399 			EG(exit_status) = 255;
1400 			if (module_initialized) {
1401 				if (!PG(display_errors) &&
1402 				    !SG(headers_sent) &&
1403 					SG(sapi_headers).http_response_code == 200
1404 				) {
1405 					sapi_header_line ctr = {0};
1406 
1407 					ctr.line = "HTTP/1.0 500 Internal Server Error";
1408 					ctr.line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
1409 					sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
1410 				}
1411 				/* the parser would return 1 (failure), we can bail out nicely */
1412 				if (!(orig_type & E_DONT_BAIL)) {
1413 					/* restore memory limit */
1414 					zend_set_memory_limit(PG(memory_limit));
1415 					zend_objects_store_mark_destructed(&EG(objects_store));
1416 					if (CG(in_compilation) && (type == E_COMPILE_ERROR || type == E_PARSE)) {
1417 						/* We bailout during compilation which may for example leave stale entries in CG(loop_var_stack).
1418 						 * If code is compiled during shutdown, we need to make sure the compiler is reset to a clean state,
1419 						 * otherwise this will lead to incorrect compilation during shutdown.
1420 						 * We don't do a full re-initialization via init_compiler() because that will also reset streams and resources. */
1421 						shutdown_compiler();
1422 						zend_init_compiler_data_structures();
1423 					}
1424 					zend_bailout();
1425 					return;
1426 				}
1427 			}
1428 			break;
1429 	}
1430 }
1431 /* }}} */
1432 
1433 /* {{{ php_get_current_user */
php_get_current_user(void)1434 PHPAPI char *php_get_current_user(void)
1435 {
1436 	zend_stat_t *pstat = NULL;
1437 
1438 	if (SG(request_info).current_user) {
1439 		return SG(request_info).current_user;
1440 	}
1441 
1442 	/* FIXME: I need to have this somehow handled if
1443 	USE_SAPI is defined, because cgi will also be
1444 	interfaced in USE_SAPI */
1445 
1446 	pstat = sapi_get_stat();
1447 
1448 	if (!pstat) {
1449 		return "";
1450 	} else {
1451 #ifdef PHP_WIN32
1452 		char *name = php_win32_get_username();
1453 		int len;
1454 
1455 		if (!name) {
1456 			return "";
1457 		}
1458 		len = (int)strlen(name);
1459 		name[len] = '\0';
1460 		SG(request_info).current_user_length = len;
1461 		SG(request_info).current_user = estrndup(name, len);
1462 		free(name);
1463 		return SG(request_info).current_user;
1464 #else
1465 		struct passwd *pwd;
1466 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
1467 		struct passwd _pw;
1468 		struct passwd *retpwptr = NULL;
1469 		int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
1470 		char *pwbuf;
1471 
1472 		if (pwbuflen < 1) {
1473 			return "";
1474 		}
1475 		pwbuf = emalloc(pwbuflen);
1476 		if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
1477 			efree(pwbuf);
1478 			return "";
1479 		}
1480 		if (retpwptr == NULL) {
1481 			efree(pwbuf);
1482 			return "";
1483 		}
1484 		pwd = &_pw;
1485 #else
1486 		if ((pwd=getpwuid(pstat->st_uid))==NULL) {
1487 			return "";
1488 		}
1489 #endif
1490 		SG(request_info).current_user_length = strlen(pwd->pw_name);
1491 		SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
1492 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
1493 		efree(pwbuf);
1494 #endif
1495 		return SG(request_info).current_user;
1496 #endif
1497 	}
1498 }
1499 /* }}} */
1500 
1501 /* {{{ Sets the maximum time a script can run */
PHP_FUNCTION(set_time_limit)1502 PHP_FUNCTION(set_time_limit)
1503 {
1504 	zend_long new_timeout;
1505 	char *new_timeout_str;
1506 	size_t new_timeout_strlen;
1507 	zend_string *key;
1508 
1509 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &new_timeout) == FAILURE) {
1510 		RETURN_THROWS();
1511 	}
1512 
1513 	new_timeout_strlen = zend_spprintf(&new_timeout_str, 0, ZEND_LONG_FMT, new_timeout);
1514 
1515 	key = ZSTR_INIT_LITERAL("max_execution_time", 0);
1516 	if (zend_alter_ini_entry_chars_ex(key, new_timeout_str, new_timeout_strlen, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == SUCCESS) {
1517 		RETVAL_TRUE;
1518 	} else {
1519 		RETVAL_FALSE;
1520 	}
1521 	zend_string_release_ex(key, 0);
1522 	efree(new_timeout_str);
1523 }
1524 /* }}} */
1525 
1526 /* {{{ php_fopen_wrapper_for_zend */
php_fopen_wrapper_for_zend(zend_string * filename,zend_string ** opened_path)1527 static FILE *php_fopen_wrapper_for_zend(zend_string *filename, zend_string **opened_path)
1528 {
1529 	*opened_path = filename;
1530 	return php_stream_open_wrapper_as_file(ZSTR_VAL(filename), "rb", USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE|STREAM_OPEN_FOR_ZEND_STREAM, opened_path);
1531 }
1532 /* }}} */
1533 
php_zend_stream_closer(void * handle)1534 static void php_zend_stream_closer(void *handle) /* {{{ */
1535 {
1536 	php_stream_close((php_stream*)handle);
1537 }
1538 /* }}} */
1539 
php_zend_stream_fsizer(void * handle)1540 static size_t php_zend_stream_fsizer(void *handle) /* {{{ */
1541 {
1542 	php_stream *stream = handle;
1543 	php_stream_statbuf ssb;
1544 
1545 	/* File size reported by stat() may be inaccurate if stream filters are used.
1546 	 * TODO: Should stat() be generally disabled if filters are used? */
1547 	if (stream->readfilters.head) {
1548 		return 0;
1549 	}
1550 
1551 	if (php_stream_stat(stream, &ssb) == 0) {
1552 		return ssb.sb.st_size;
1553 	}
1554 	return 0;
1555 }
1556 /* }}} */
1557 
php_stream_open_for_zend(zend_file_handle * handle)1558 static zend_result php_stream_open_for_zend(zend_file_handle *handle) /* {{{ */
1559 {
1560 	return php_stream_open_for_zend_ex(handle, USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE);
1561 }
1562 /* }}} */
1563 
php_stream_open_for_zend_ex(zend_file_handle * handle,int mode)1564 PHPAPI zend_result php_stream_open_for_zend_ex(zend_file_handle *handle, int mode) /* {{{ */
1565 {
1566 	zend_string *opened_path;
1567 	zend_string *filename;
1568 	php_stream *stream;
1569 
1570 	ZEND_ASSERT(handle->type == ZEND_HANDLE_FILENAME);
1571 	opened_path = filename = handle->filename;
1572 	stream = php_stream_open_wrapper((char *)ZSTR_VAL(filename), "rb", mode | STREAM_OPEN_FOR_ZEND_STREAM, &opened_path);
1573 	if (stream) {
1574 		memset(handle, 0, sizeof(zend_file_handle));
1575 		handle->type = ZEND_HANDLE_STREAM;
1576 		handle->filename = filename;
1577 		handle->opened_path = opened_path;
1578 		handle->handle.stream.handle  = stream;
1579 		handle->handle.stream.reader  = (zend_stream_reader_t)_php_stream_read;
1580 		handle->handle.stream.fsizer  = php_zend_stream_fsizer;
1581 		handle->handle.stream.isatty  = 0;
1582 		handle->handle.stream.closer = php_zend_stream_closer;
1583 		/* suppress warning if this stream is not explicitly closed */
1584 		php_stream_auto_cleanup(stream);
1585 		/* Disable buffering to avoid double buffering between PHP and Zend streams. */
1586 		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
1587 
1588 		return SUCCESS;
1589 	}
1590 	return FAILURE;
1591 }
1592 /* }}} */
1593 
php_resolve_path_for_zend(zend_string * filename)1594 static zend_string *php_resolve_path_for_zend(zend_string *filename) /* {{{ */
1595 {
1596 	return php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), PG(include_path));
1597 }
1598 /* }}} */
1599 
1600 /* {{{ php_get_configuration_directive_for_zend */
php_get_configuration_directive_for_zend(zend_string * name)1601 static zval *php_get_configuration_directive_for_zend(zend_string *name)
1602 {
1603 	return cfg_get_entry_ex(name);
1604 }
1605 /* }}} */
1606 
1607 /* {{{ php_free_request_globals */
php_free_request_globals(void)1608 static void php_free_request_globals(void)
1609 {
1610 	clear_last_error();
1611 	if (PG(php_sys_temp_dir)) {
1612 		efree(PG(php_sys_temp_dir));
1613 		PG(php_sys_temp_dir) = NULL;
1614 	}
1615 
1616 	EG(filename_override) = NULL;
1617 	EG(lineno_override) = -1;
1618 }
1619 /* }}} */
1620 
1621 /* {{{ php_message_handler_for_zend */
php_message_handler_for_zend(zend_long message,const void * data)1622 static ZEND_COLD void php_message_handler_for_zend(zend_long message, const void *data)
1623 {
1624 	switch (message) {
1625 		case ZMSG_FAILED_INCLUDE_FOPEN: {
1626 			char *tmp = estrdup((char *) data);
1627 			php_error_docref("function.include", E_WARNING, "Failed opening '%s' for inclusion (include_path='%s')", php_strip_url_passwd(tmp), STR_PRINT(PG(include_path)));
1628 			efree(tmp);
1629 			break;
1630 		}
1631 		case ZMSG_FAILED_REQUIRE_FOPEN: {
1632 			char *tmp = estrdup((char *) data);
1633 			zend_throw_error(NULL, "Failed opening required '%s' (include_path='%s')", php_strip_url_passwd(tmp), STR_PRINT(PG(include_path)));
1634 			efree(tmp);
1635 			break;
1636 		}
1637 		case ZMSG_FAILED_HIGHLIGHT_FOPEN: {
1638 			char *tmp = estrdup((char *) data);
1639 			php_error_docref(NULL, E_WARNING, "Failed opening '%s' for highlighting", php_strip_url_passwd(tmp));
1640 			efree(tmp);
1641 			break;
1642 		}
1643 		case ZMSG_MEMORY_LEAK_DETECTED:
1644 		case ZMSG_MEMORY_LEAK_REPEATED:
1645 #if ZEND_DEBUG
1646 			if (EG(error_reporting) & E_WARNING) {
1647 				char memory_leak_buf[1024];
1648 
1649 				if (message==ZMSG_MEMORY_LEAK_DETECTED) {
1650 					zend_leak_info *t = (zend_leak_info *) data;
1651 
1652 					snprintf(memory_leak_buf, 512, "%s(%" PRIu32 ") :  Freeing " ZEND_ADDR_FMT " (%zu bytes), script=%s\n", t->filename, t->lineno, (size_t)t->addr, t->size, SAFE_FILENAME(SG(request_info).path_translated));
1653 					if (t->orig_filename) {
1654 						char relay_buf[512];
1655 
1656 						snprintf(relay_buf, 512, "%s(%" PRIu32 ") : Actual location (location was relayed)\n", t->orig_filename, t->orig_lineno);
1657 						strlcat(memory_leak_buf, relay_buf, sizeof(memory_leak_buf));
1658 					}
1659 				} else {
1660 					unsigned long leak_count = (uintptr_t) data;
1661 
1662 					snprintf(memory_leak_buf, 512, "Last leak repeated %lu time%s\n", leak_count, (leak_count>1?"s":""));
1663 				}
1664 #	if defined(PHP_WIN32)
1665 				if (IsDebuggerPresent()) {
1666 					OutputDebugString(memory_leak_buf);
1667 				} else {
1668 					fprintf(stderr, "%s", memory_leak_buf);
1669 				}
1670 #	else
1671 				fprintf(stderr, "%s", memory_leak_buf);
1672 #	endif
1673 			}
1674 #endif
1675 			break;
1676 		case ZMSG_MEMORY_LEAKS_GRAND_TOTAL:
1677 #if ZEND_DEBUG
1678 			if (EG(error_reporting) & E_WARNING) {
1679 				char memory_leak_buf[512];
1680 
1681 				snprintf(memory_leak_buf, 512, "=== Total %d memory leaks detected ===\n", *((uint32_t *) data));
1682 #	if defined(PHP_WIN32)
1683 				if (IsDebuggerPresent()) {
1684 					OutputDebugString(memory_leak_buf);
1685 				} else {
1686 					fprintf(stderr, "%s", memory_leak_buf);
1687 				}
1688 #	else
1689 				fprintf(stderr, "%s", memory_leak_buf);
1690 #	endif
1691 			}
1692 #endif
1693 			break;
1694 		case ZMSG_LOG_SCRIPT_NAME: {
1695 				struct tm *ta, tmbuf;
1696 				time_t curtime;
1697 				char *datetime_str, asctimebuf[52];
1698 				char memory_leak_buf[4096];
1699 
1700 				time(&curtime);
1701 				ta = php_localtime_r(&curtime, &tmbuf);
1702 				datetime_str = php_asctime_r(ta, asctimebuf);
1703 				if (datetime_str) {
1704 					datetime_str[strlen(datetime_str)-1]=0;	/* get rid of the trailing newline */
1705 					snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[%s]  Script:  '%s'\n", datetime_str, SAFE_FILENAME(SG(request_info).path_translated));
1706 				} else {
1707 					snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[null]  Script:  '%s'\n", SAFE_FILENAME(SG(request_info).path_translated));
1708 				}
1709 #	if defined(PHP_WIN32)
1710 				if (IsDebuggerPresent()) {
1711 					OutputDebugString(memory_leak_buf);
1712 				} else {
1713 					fprintf(stderr, "%s", memory_leak_buf);
1714 				}
1715 #	else
1716 				fprintf(stderr, "%s", memory_leak_buf);
1717 #	endif
1718 			}
1719 			break;
1720 	}
1721 }
1722 /* }}} */
1723 
1724 
php_on_timeout(int seconds)1725 void php_on_timeout(int seconds)
1726 {
1727 	PG(connection_status) |= PHP_CONNECTION_TIMEOUT;
1728 }
1729 
1730 #if PHP_SIGCHILD
1731 /* {{{ sigchld_handler */
sigchld_handler(int apar)1732 static void sigchld_handler(int apar)
1733 {
1734 	int errno_save = errno;
1735 
1736 	while (waitpid(-1, NULL, WNOHANG) > 0);
1737 	signal(SIGCHLD, sigchld_handler);
1738 
1739 	errno = errno_save;
1740 }
1741 /* }}} */
1742 #endif
1743 
1744 /* {{{ php_request_startup */
php_request_startup(void)1745 zend_result php_request_startup(void)
1746 {
1747 	zend_result retval = SUCCESS;
1748 
1749 	zend_interned_strings_activate();
1750 
1751 #ifdef HAVE_DTRACE
1752 	DTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method));
1753 #endif /* HAVE_DTRACE */
1754 
1755 #ifdef PHP_WIN32
1756 # if defined(ZTS)
1757 	_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
1758 # endif
1759 	PG(com_initialized) = 0;
1760 #endif
1761 
1762 #if PHP_SIGCHILD
1763 	signal(SIGCHLD, sigchld_handler);
1764 #endif
1765 
1766 	zend_try {
1767 		PG(in_error_log) = 0;
1768 		PG(during_request_startup) = 1;
1769 
1770 		php_output_activate();
1771 
1772 		/* initialize global variables */
1773 		PG(modules_activated) = 0;
1774 		PG(header_is_being_sent) = 0;
1775 		PG(connection_status) = PHP_CONNECTION_NORMAL;
1776 		PG(in_user_include) = 0;
1777 
1778 		zend_activate();
1779 		sapi_activate();
1780 
1781 #ifdef ZEND_SIGNALS
1782 		zend_signal_activate();
1783 #endif
1784 
1785 		if (PG(max_input_time) == -1) {
1786 			zend_set_timeout(EG(timeout_seconds), 1);
1787 		} else {
1788 			zend_set_timeout(PG(max_input_time), 1);
1789 		}
1790 
1791 		/* Disable realpath cache if an open_basedir is set */
1792 		if (PG(open_basedir) && *PG(open_basedir)) {
1793 			CWDG(realpath_cache_size_limit) = 0;
1794 		}
1795 
1796 		if (PG(expose_php) && !SG(headers_sent)) {
1797 			sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
1798 		}
1799 
1800 		if (PG(output_handler) && PG(output_handler)[0]) {
1801 			zval oh;
1802 
1803 			ZVAL_STRING(&oh, PG(output_handler));
1804 			php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
1805 			zval_ptr_dtor(&oh);
1806 		} else if (PG(output_buffering)) {
1807 			php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS);
1808 		} else if (PG(implicit_flush)) {
1809 			php_output_set_implicit_flush(1);
1810 		}
1811 
1812 		/* We turn this off in php_execute_script() */
1813 		/* PG(during_request_startup) = 0; */
1814 
1815 		php_hash_environment();
1816 		zend_activate_modules();
1817 		PG(modules_activated)=1;
1818 	} zend_catch {
1819 		retval = FAILURE;
1820 	} zend_end_try();
1821 
1822 	SG(sapi_started) = 1;
1823 
1824 	return retval;
1825 }
1826 /* }}} */
1827 
1828 /* {{{ php_request_shutdown */
php_request_shutdown(void * dummy)1829 void php_request_shutdown(void *dummy)
1830 {
1831 	bool report_memleaks;
1832 
1833 	EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
1834 
1835 	report_memleaks = PG(report_memleaks);
1836 
1837 	/* EG(current_execute_data) points into nirvana and therefore cannot be safely accessed
1838 	 * inside zend_executor callback functions.
1839 	 */
1840 	EG(current_execute_data) = NULL;
1841 
1842 	php_deactivate_ticks();
1843 
1844 	/* 0. Call any open observer end handlers that are still open after a zend_bailout */
1845 	if (ZEND_OBSERVER_ENABLED) {
1846 		zend_observer_fcall_end_all();
1847 	}
1848 
1849 	/* 1. Call all possible shutdown functions registered with register_shutdown_function() */
1850 	if (PG(modules_activated)) {
1851 		php_call_shutdown_functions();
1852 	}
1853 
1854 	/* 2. Call all possible __destruct() functions */
1855 	zend_try {
1856 		zend_call_destructors();
1857 	} zend_end_try();
1858 
1859 	/* 3. Flush all output buffers */
1860 	zend_try {
1861 		php_output_end_all();
1862 	} zend_end_try();
1863 
1864 	/* 4. Reset max_execution_time (no longer executing php code after response sent) */
1865 	zend_try {
1866 		zend_unset_timeout();
1867 	} zend_end_try();
1868 
1869 	/* 5. Call all extensions RSHUTDOWN functions */
1870 	if (PG(modules_activated)) {
1871 		zend_deactivate_modules();
1872 	}
1873 
1874 	/* 6. Shutdown output layer (send the set HTTP headers, cleanup output handlers, etc.) */
1875 	zend_try {
1876 		php_output_deactivate();
1877 	} zend_end_try();
1878 
1879 	/* 7. Free shutdown functions */
1880 	if (PG(modules_activated)) {
1881 		php_free_shutdown_functions();
1882 	}
1883 
1884 	/* 8. Destroy super-globals */
1885 	zend_try {
1886 		int i;
1887 
1888 		for (i=0; i<NUM_TRACK_VARS; i++) {
1889 			zval_ptr_dtor(&PG(http_globals)[i]);
1890 		}
1891 	} zend_end_try();
1892 
1893 	/* 9. Shutdown scanner/executor/compiler and restore ini entries */
1894 	zend_deactivate();
1895 
1896 	/* 10. free request-bound globals */
1897 	php_free_request_globals();
1898 
1899 	/* 11. Call all extensions post-RSHUTDOWN functions */
1900 	zend_try {
1901 		zend_post_deactivate_modules();
1902 	} zend_end_try();
1903 
1904 	/* 12. SAPI related shutdown*/
1905 	zend_try {
1906 		sapi_deactivate_module();
1907 	} zend_end_try();
1908 	/* free SAPI stuff */
1909 	sapi_deactivate_destroy();
1910 
1911 	/* 13. free virtual CWD memory */
1912 	virtual_cwd_deactivate();
1913 
1914 	/* 14. Destroy stream hashes */
1915 	zend_try {
1916 		php_shutdown_stream_hashes();
1917 	} zend_end_try();
1918 
1919 	/* 15. Free Willy (here be crashes) */
1920 	zend_arena_destroy(CG(arena));
1921 	zend_interned_strings_deactivate();
1922 	zend_try {
1923 		shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0);
1924 	} zend_end_try();
1925 
1926 	/* Reset memory limit, as the reset during INI_STAGE_DEACTIVATE may have failed.
1927 	 * At this point, no memory beyond a single chunk should be in use. */
1928 	zend_set_memory_limit(PG(memory_limit));
1929 
1930 	/* 16. Deactivate Zend signals */
1931 #ifdef ZEND_SIGNALS
1932 	zend_signal_deactivate();
1933 #endif
1934 
1935 #ifdef PHP_WIN32
1936 	if (PG(com_initialized)) {
1937 		CoUninitialize();
1938 		PG(com_initialized) = 0;
1939 	}
1940 #endif
1941 
1942 #ifdef HAVE_DTRACE
1943 	DTRACE_REQUEST_SHUTDOWN(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method));
1944 #endif /* HAVE_DTRACE */
1945 }
1946 /* }}} */
1947 
1948 /* {{{ php_com_initialize */
php_com_initialize(void)1949 PHPAPI void php_com_initialize(void)
1950 {
1951 #ifdef PHP_WIN32
1952 	if (!PG(com_initialized)) {
1953 		if (CoInitialize(NULL) == S_OK) {
1954 			PG(com_initialized) = 1;
1955 		}
1956 	}
1957 #endif
1958 }
1959 /* }}} */
1960 
1961 #ifdef ZTS
1962 /* {{{ core_globals_ctor */
core_globals_ctor(php_core_globals * core_globals)1963 static void core_globals_ctor(php_core_globals *core_globals)
1964 {
1965 	memset(core_globals, 0, sizeof(*core_globals));
1966 	php_startup_ticks();
1967 }
1968 /* }}} */
1969 #endif
1970 
1971 /* {{{ core_globals_dtor */
core_globals_dtor(php_core_globals * core_globals)1972 static void core_globals_dtor(php_core_globals *core_globals)
1973 {
1974 	/* These should have been freed earlier. */
1975 	ZEND_ASSERT(!core_globals->last_error_message);
1976 	ZEND_ASSERT(!core_globals->last_error_file);
1977 
1978 	if (core_globals->disable_classes) {
1979 		free(core_globals->disable_classes);
1980 	}
1981 	if (core_globals->php_binary) {
1982 		free(core_globals->php_binary);
1983 	}
1984 
1985 	php_shutdown_ticks(core_globals);
1986 }
1987 /* }}} */
1988 
PHP_MINFO_FUNCTION(php_core)1989 PHP_MINFO_FUNCTION(php_core) { /* {{{ */
1990 	php_info_print_table_start();
1991 	php_info_print_table_row(2, "PHP Version", PHP_VERSION);
1992 	php_info_print_table_end();
1993 	DISPLAY_INI_ENTRIES();
1994 }
1995 /* }}} */
1996 
1997 /* {{{ php_register_extensions */
php_register_extensions(zend_module_entry * const * ptr,int count)1998 zend_result php_register_extensions(zend_module_entry * const * ptr, int count)
1999 {
2000 	zend_module_entry * const * end = ptr + count;
2001 
2002 	while (ptr < end) {
2003 		if (*ptr) {
2004 			if (zend_register_internal_module(*ptr)==NULL) {
2005 				return FAILURE;
2006 			}
2007 		}
2008 		ptr++;
2009 	}
2010 	return SUCCESS;
2011 }
2012 
2013 #ifdef PHP_WIN32
2014 static _invalid_parameter_handler old_invalid_parameter_handler;
2015 
dummy_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)2016 void dummy_invalid_parameter_handler(
2017 		const wchar_t *expression,
2018 		const wchar_t *function,
2019 		const wchar_t *file,
2020 		unsigned int   line,
2021 		uintptr_t      pReserved)
2022 {
2023 	static int called = 0;
2024 	char buf[1024];
2025 	int len;
2026 
2027 	if (!called) {
2028 			if(PG(windows_show_crt_warning)) {
2029 			called = 1;
2030 			if (function) {
2031 				if (file) {
2032 					len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws' (%ws:%u)", function, file, line);
2033 				} else {
2034 					len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws'", function);
2035 				}
2036 			} else {
2037 				len = _snprintf(buf, sizeof(buf)-1, "Invalid CRT parameter detected (function not known)");
2038 			}
2039 			zend_error(E_WARNING, "%s", buf);
2040 			called = 0;
2041 		}
2042 	}
2043 }
2044 #endif
2045 
2046 /* {{{ php_module_startup */
php_module_startup(sapi_module_struct * sf,zend_module_entry * additional_module)2047 zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_module)
2048 {
2049 	zend_utility_functions zuf;
2050 	zend_utility_values zuv;
2051 	zend_result retval = SUCCESS;
2052 	int module_number = 0;
2053 	zend_module_entry *module;
2054 
2055 #ifdef PHP_WIN32
2056 	WORD wVersionRequested = MAKEWORD(2, 0);
2057 	WSADATA wsaData;
2058 
2059 	old_invalid_parameter_handler =
2060 		_set_invalid_parameter_handler(dummy_invalid_parameter_handler);
2061 	if (old_invalid_parameter_handler != NULL) {
2062 		_set_invalid_parameter_handler(old_invalid_parameter_handler);
2063 	}
2064 
2065 	/* Disable the message box for assertions.*/
2066 	_CrtSetReportMode(_CRT_ASSERT, 0);
2067 #endif
2068 
2069 #ifdef ZTS
2070 	(void)ts_resource(0);
2071 #endif
2072 
2073 #ifdef PHP_WIN32
2074 	if (!php_win32_init_random_bytes()) {
2075 		fprintf(stderr, "\ncrypt algorithm provider initialization failed\n");
2076 		return FAILURE;
2077 	}
2078 #endif
2079 
2080 	module_shutdown = false;
2081 	module_startup = true;
2082 	sapi_initialize_empty_request();
2083 	sapi_activate();
2084 
2085 	if (module_initialized) {
2086 		return SUCCESS;
2087 	}
2088 
2089 	sapi_module = *sf;
2090 
2091 	php_output_startup();
2092 
2093 #ifdef ZTS
2094 	ts_allocate_fast_id(&core_globals_id, &core_globals_offset, sizeof(php_core_globals), (ts_allocate_ctor) core_globals_ctor, (ts_allocate_dtor) core_globals_dtor);
2095 #ifdef PHP_WIN32
2096 	ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
2097 #endif
2098 #else
2099 	memset(&core_globals, 0, sizeof(core_globals));
2100 	php_startup_ticks();
2101 #endif
2102 	gc_globals_ctor();
2103 
2104 	zuf.error_function = php_error_cb;
2105 	zuf.printf_function = php_printf;
2106 	zuf.write_function = php_output_write;
2107 	zuf.fopen_function = php_fopen_wrapper_for_zend;
2108 	zuf.message_handler = php_message_handler_for_zend;
2109 	zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
2110 	zuf.ticks_function = php_run_ticks;
2111 	zuf.on_timeout = php_on_timeout;
2112 	zuf.stream_open_function = php_stream_open_for_zend;
2113 	zuf.printf_to_smart_string_function = php_printf_to_smart_string;
2114 	zuf.printf_to_smart_str_function = php_printf_to_smart_str;
2115 	zuf.getenv_function = sapi_getenv;
2116 	zuf.resolve_path_function = php_resolve_path_for_zend;
2117 	zend_startup(&zuf);
2118 	zend_reset_lc_ctype_locale();
2119 	zend_update_current_locale();
2120 
2121 	zend_observer_startup();
2122 #if ZEND_DEBUG
2123 	zend_observer_error_register(report_zend_debug_error_notify_cb);
2124 #endif
2125 
2126 #if HAVE_TZSET
2127 	tzset();
2128 #endif
2129 
2130 #ifdef PHP_WIN32
2131 	char *img_err;
2132 	if (!php_win32_crt_compatible(&img_err)) {
2133 		php_error(E_CORE_WARNING, img_err);
2134 		efree(img_err);
2135 		return FAILURE;
2136 	}
2137 
2138 	/* start up winsock services */
2139 	if (WSAStartup(wVersionRequested, &wsaData) != 0) {
2140 		fprintf(stderr, "\nwinsock.dll unusable. %d\n", WSAGetLastError());
2141 		return FAILURE;
2142 	}
2143 	php_win32_signal_ctrl_handler_init();
2144 #endif
2145 
2146 	le_index_ptr = zend_register_list_destructors_ex(NULL, NULL, "index pointer", 0);
2147 
2148 	php_binary_init();
2149 	register_main_symbols(module_number);
2150 
2151 	/* this will read in php.ini, set up the configuration parameters,
2152 	   load zend extensions and register php function extensions
2153 	   to be loaded later */
2154 	zend_stream_init();
2155 	if (php_init_config() == FAILURE) {
2156 		return FAILURE;
2157 	}
2158 	zend_stream_shutdown();
2159 
2160 	/* Register PHP core ini entries */
2161 	zend_register_ini_entries_ex(ini_entries, module_number, MODULE_PERSISTENT);
2162 
2163 	/* Register Zend ini entries */
2164 	zend_register_standard_ini_entries();
2165 
2166 #ifdef ZEND_WIN32
2167 	/* Until the current ini values was setup, the current cp is 65001.
2168 		If the actual ini values are different, some stuff needs to be updated.
2169 		It concerns at least main_cwd_state and there might be more. As we're
2170 		still in the startup phase, lets use the chance and reinit the relevant
2171 		item according to the current codepage. Still, if ini_set() is used
2172 		later on, a more intelligent way to update such stuff is needed.
2173 		Startup/shutdown routines could involve touching globals and thus
2174 		can't always be used on demand. */
2175 	if (!php_win32_cp_use_unicode()) {
2176 		virtual_cwd_main_cwd_init(1);
2177 	}
2178 #endif
2179 
2180 	/* Disable realpath cache if an open_basedir is set */
2181 	if (PG(open_basedir) && *PG(open_basedir)) {
2182 		CWDG(realpath_cache_size_limit) = 0;
2183 	}
2184 
2185 	PG(have_called_openlog) = 0;
2186 
2187 	/* initialize stream wrappers registry
2188 	 * (this uses configuration parameters from php.ini)
2189 	 */
2190 	if (php_init_stream_wrappers(module_number) == FAILURE)	{
2191 		fprintf(stderr, "PHP:  Unable to initialize stream url wrappers.\n");
2192 		return FAILURE;
2193 	}
2194 
2195 	zuv.html_errors = 1;
2196 	php_startup_auto_globals();
2197 	zend_set_utility_values(&zuv);
2198 	php_startup_sapi_content_types();
2199 
2200 	/* Begin to fingerprint the process state */
2201 	zend_startup_system_id();
2202 
2203 	/* startup extensions statically compiled in */
2204 	if (php_register_internal_extensions_func() == FAILURE) {
2205 		fprintf(stderr, "Unable to start builtin modules\n");
2206 		return FAILURE;
2207 	}
2208 
2209 	/* start additional PHP extensions */
2210 	if (additional_module && (zend_register_internal_module(additional_module) == NULL)) {
2211 		return FAILURE;
2212 	}
2213 
2214 	/* load and startup extensions compiled as shared objects (aka DLLs)
2215 	   as requested by php.ini entries
2216 	   these are loaded after initialization of internal extensions
2217 	   as extensions *might* rely on things from ext/standard
2218 	   which is always an internal extension and to be initialized
2219 	   ahead of all other internals
2220 	 */
2221 	php_ini_register_extensions();
2222 	zend_startup_modules();
2223 
2224 	/* start Zend extensions */
2225 	zend_startup_extensions();
2226 
2227 	zend_collect_module_handlers();
2228 
2229 	/* register additional functions */
2230 	if (sapi_module.additional_functions) {
2231 		if ((module = zend_hash_str_find_ptr(&module_registry, "standard", sizeof("standard")-1)) != NULL) {
2232 			EG(current_module) = module;
2233 			zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT);
2234 			EG(current_module) = NULL;
2235 		}
2236 	}
2237 
2238 	/* disable certain classes and functions as requested by php.ini */
2239 	zend_disable_functions(INI_STR("disable_functions"));
2240 	php_disable_classes();
2241 
2242 	/* make core report what it should */
2243 	if ((module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core")-1)) != NULL) {
2244 		module->version = PHP_VERSION;
2245 		module->info_func = PHP_MINFO(php_core);
2246 	}
2247 
2248 	/* freeze the list of observer fcall_init handlers */
2249 	zend_observer_post_startup();
2250 
2251 	/* Extensions that add engine hooks after this point do so at their own peril */
2252 	zend_finalize_system_id();
2253 
2254 	module_initialized = true;
2255 
2256 	if (zend_post_startup() != SUCCESS) {
2257 		return FAILURE;
2258 	}
2259 
2260 	/* Check for deprecated directives */
2261 	/* NOTE: If you add anything here, remember to add it to build/Makefile.global! */
2262 	{
2263 		struct {
2264 			const long error_level;
2265 			const char *phrase;
2266 			const char *directives[18]; /* Remember to change this if the number of directives change */
2267 		} directives[2] = {
2268 			{
2269 				E_DEPRECATED,
2270 				"Directive '%s' is deprecated",
2271 				{
2272 					"allow_url_include",
2273 					NULL
2274 				}
2275 			},
2276 			{
2277 				E_CORE_ERROR,
2278 				"Directive '%s' is no longer available in PHP",
2279 				{
2280 					"allow_call_time_pass_reference",
2281 					"asp_tags",
2282 					"define_syslog_variables",
2283 					"highlight.bg",
2284 					"magic_quotes_gpc",
2285 					"magic_quotes_runtime",
2286 					"magic_quotes_sybase",
2287 					"register_globals",
2288 					"register_long_arrays",
2289 					"safe_mode",
2290 					"safe_mode_gid",
2291 					"safe_mode_include_dir",
2292 					"safe_mode_exec_dir",
2293 					"safe_mode_allowed_env_vars",
2294 					"safe_mode_protected_env_vars",
2295 					"zend.ze1_compatibility_mode",
2296 					"track_errors",
2297 					NULL
2298 				}
2299 			}
2300 		};
2301 
2302 		unsigned int i;
2303 
2304 		zend_try {
2305 			/* 2 = Count of deprecation structs */
2306 			for (i = 0; i < 2; i++) {
2307 				const char **p = directives[i].directives;
2308 
2309 				while(*p) {
2310 					zend_long value;
2311 
2312 					if (cfg_get_long((char*)*p, &value) == SUCCESS && value) {
2313 						zend_error(directives[i].error_level, directives[i].phrase, *p);
2314 					}
2315 
2316 					++p;
2317 				}
2318 			}
2319 		} zend_catch {
2320 			retval = FAILURE;
2321 		} zend_end_try();
2322 	}
2323 
2324 	virtual_cwd_deactivate();
2325 
2326 	sapi_deactivate();
2327 	module_startup = false;
2328 
2329 	/* Don't leak errors from startup into the per-request phase. */
2330 	clear_last_error();
2331 	shutdown_memory_manager(1, 0);
2332 	virtual_cwd_activate();
2333 
2334 	zend_interned_strings_switch_storage(1);
2335 
2336 #if ZEND_RC_DEBUG
2337 	if (retval == SUCCESS) {
2338 		zend_rc_debug = 1;
2339 	}
2340 #endif
2341 
2342 	/* we're done */
2343 	return retval;
2344 }
2345 /* }}} */
2346 
2347 /* {{{ php_module_shutdown_wrapper */
php_module_shutdown_wrapper(sapi_module_struct * sapi_globals)2348 int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals)
2349 {
2350 	php_module_shutdown();
2351 	return SUCCESS;
2352 }
2353 /* }}} */
2354 
2355 /* {{{ php_module_shutdown */
php_module_shutdown(void)2356 void php_module_shutdown(void)
2357 {
2358 	int module_number=0;
2359 
2360 	module_shutdown = true;
2361 
2362 	if (!module_initialized) {
2363 		return;
2364 	}
2365 
2366 	zend_interned_strings_switch_storage(0);
2367 
2368 #if ZEND_RC_DEBUG
2369 	zend_rc_debug = 0;
2370 #endif
2371 
2372 #ifdef PHP_WIN32
2373 	(void)php_win32_shutdown_random_bytes();
2374 	php_win32_signal_ctrl_handler_shutdown();
2375 #endif
2376 
2377 	sapi_flush();
2378 
2379 	zend_shutdown();
2380 
2381 #ifdef PHP_WIN32
2382 	/*close winsock */
2383 	WSACleanup();
2384 #endif
2385 
2386 	/* Destroys filter & transport registries too */
2387 	php_shutdown_stream_wrappers(module_number);
2388 
2389 	zend_unregister_ini_entries_ex(module_number, MODULE_PERSISTENT);
2390 
2391 	/* close down the ini config */
2392 	php_shutdown_config();
2393 	clear_last_error();
2394 
2395 #ifndef ZTS
2396 	zend_ini_shutdown();
2397 	shutdown_memory_manager(CG(unclean_shutdown), 1);
2398 #else
2399 	zend_ini_global_shutdown();
2400 #endif
2401 
2402 	php_output_shutdown();
2403 
2404 #ifndef ZTS
2405 	zend_interned_strings_dtor();
2406 #endif
2407 
2408 	if (zend_post_shutdown_cb) {
2409 		void (*cb)(void) = zend_post_shutdown_cb;
2410 
2411 		zend_post_shutdown_cb = NULL;
2412 		cb();
2413 	}
2414 
2415 	module_initialized = false;
2416 
2417 #ifndef ZTS
2418 	core_globals_dtor(&core_globals);
2419 	gc_globals_dtor();
2420 #else
2421 	ts_free_id(core_globals_id);
2422 #endif
2423 
2424 #ifdef PHP_WIN32
2425 	if (old_invalid_parameter_handler == NULL) {
2426 		_set_invalid_parameter_handler(old_invalid_parameter_handler);
2427 	}
2428 #endif
2429 
2430 	zend_observer_shutdown();
2431 }
2432 /* }}} */
2433 
php_execute_script_ex(zend_file_handle * primary_file,zval * retval)2434 PHPAPI bool php_execute_script_ex(zend_file_handle *primary_file, zval *retval)
2435 {
2436 	zend_file_handle *prepend_file_p = NULL, *append_file_p = NULL;
2437 	zend_file_handle prepend_file, append_file;
2438 #ifdef HAVE_BROKEN_GETCWD
2439 	volatile int old_cwd_fd = -1;
2440 #else
2441 	char *old_cwd;
2442 	ALLOCA_FLAG(use_heap)
2443 #endif
2444 	bool result = true;
2445 
2446 #ifndef HAVE_BROKEN_GETCWD
2447 # define OLD_CWD_SIZE 4096
2448 	old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
2449 	old_cwd[0] = '\0';
2450 #endif
2451 
2452 	zend_try {
2453 		char realfile[MAXPATHLEN];
2454 
2455 #ifdef PHP_WIN32
2456 		if(primary_file->filename) {
2457 			UpdateIniFromRegistry(ZSTR_VAL(primary_file->filename));
2458 		}
2459 #endif
2460 
2461 		PG(during_request_startup) = 0;
2462 
2463 		if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
2464 #ifdef HAVE_BROKEN_GETCWD
2465 			/* this looks nasty to me */
2466 			old_cwd_fd = open(".", 0);
2467 #else
2468 			php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
2469 #endif
2470 			VCWD_CHDIR_FILE(ZSTR_VAL(primary_file->filename));
2471 		}
2472 
2473 		/* Only lookup the real file path and add it to the included_files list if already opened
2474 		 *   otherwise it will get opened and added to the included_files list in zend_execute_scripts
2475 		 */
2476 		if (primary_file->filename &&
2477 			!zend_string_equals_literal(primary_file->filename, "Standard input code") &&
2478 			primary_file->opened_path == NULL &&
2479 			primary_file->type != ZEND_HANDLE_FILENAME
2480 		) {
2481 			if (expand_filepath(ZSTR_VAL(primary_file->filename), realfile)) {
2482 				primary_file->opened_path = zend_string_init(realfile, strlen(realfile), 0);
2483 				zend_hash_add_empty_element(&EG(included_files), primary_file->opened_path);
2484 			}
2485 		}
2486 
2487 		if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
2488 			zend_stream_init_filename(&prepend_file, PG(auto_prepend_file));
2489 			prepend_file_p = &prepend_file;
2490 		}
2491 
2492 		if (PG(auto_append_file) && PG(auto_append_file)[0]) {
2493 			zend_stream_init_filename(&append_file, PG(auto_append_file));
2494 			append_file_p = &append_file;
2495 		}
2496 		if (PG(max_input_time) != -1) {
2497 #ifdef PHP_WIN32
2498 			zend_unset_timeout();
2499 #endif
2500 			zend_set_timeout(INI_INT("max_execution_time"), 0);
2501 		}
2502 
2503 		if (prepend_file_p && result) {
2504 			result = zend_execute_script(ZEND_REQUIRE, NULL, prepend_file_p) == SUCCESS;
2505 		}
2506 		if (result) {
2507 			result = zend_execute_script(ZEND_REQUIRE, retval, primary_file) == SUCCESS;
2508 		}
2509 		if (append_file_p && result) {
2510 			result = zend_execute_script(ZEND_REQUIRE, NULL, append_file_p) == SUCCESS;
2511 		}
2512 	} zend_catch {
2513 		result = false;
2514 	} zend_end_try();
2515 
2516 	if (prepend_file_p) {
2517 		zend_destroy_file_handle(prepend_file_p);
2518 	}
2519 
2520 	if (append_file_p) {
2521 		zend_destroy_file_handle(append_file_p);
2522 	}
2523 
2524 	if (EG(exception)) {
2525 		zend_try {
2526 			zend_exception_error(EG(exception), E_ERROR);
2527 		} zend_end_try();
2528 	}
2529 
2530 #ifdef HAVE_BROKEN_GETCWD
2531 	if (old_cwd_fd != -1) {
2532 		fchdir(old_cwd_fd);
2533 		close(old_cwd_fd);
2534 	}
2535 #else
2536 	if (old_cwd[0] != '\0') {
2537 		php_ignore_value(VCWD_CHDIR(old_cwd));
2538 	}
2539 	free_alloca(old_cwd, use_heap);
2540 #endif
2541 	return result;
2542 }
2543 
2544 /* {{{ php_execute_script */
php_execute_script(zend_file_handle * primary_file)2545 PHPAPI bool php_execute_script(zend_file_handle *primary_file)
2546 {
2547 	return php_execute_script_ex(primary_file, NULL);
2548 }
2549 /* }}} */
2550 
2551 /* {{{ php_execute_simple_script */
php_execute_simple_script(zend_file_handle * primary_file,zval * ret)2552 PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval *ret)
2553 {
2554 	char *old_cwd;
2555 	ALLOCA_FLAG(use_heap)
2556 
2557 	EG(exit_status) = 0;
2558 #define OLD_CWD_SIZE 4096
2559 	old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
2560 	old_cwd[0] = '\0';
2561 
2562 	zend_try {
2563 #ifdef PHP_WIN32
2564 		if(primary_file->filename) {
2565 			UpdateIniFromRegistry(ZSTR_VAL(primary_file->filename));
2566 		}
2567 #endif
2568 
2569 		PG(during_request_startup) = 0;
2570 
2571 		if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
2572 			php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
2573 			VCWD_CHDIR_FILE(ZSTR_VAL(primary_file->filename));
2574 		}
2575 		zend_execute_scripts(ZEND_REQUIRE, ret, 1, primary_file);
2576 	} zend_end_try();
2577 
2578 	if (old_cwd[0] != '\0') {
2579 		php_ignore_value(VCWD_CHDIR(old_cwd));
2580 	}
2581 
2582 	free_alloca(old_cwd, use_heap);
2583 	return EG(exit_status);
2584 }
2585 /* }}} */
2586 
2587 /* {{{ php_handle_aborted_connection */
php_handle_aborted_connection(void)2588 PHPAPI void php_handle_aborted_connection(void)
2589 {
2590 
2591 	PG(connection_status) = PHP_CONNECTION_ABORTED;
2592 	php_output_set_status(PHP_OUTPUT_DISABLED);
2593 
2594 	if (!PG(ignore_user_abort)) {
2595 		zend_bailout();
2596 	}
2597 }
2598 /* }}} */
2599 
2600 /* {{{ php_handle_auth_data */
php_handle_auth_data(const char * auth)2601 PHPAPI int php_handle_auth_data(const char *auth)
2602 {
2603 	int ret = -1;
2604 	size_t auth_len = auth != NULL ? strlen(auth) : 0;
2605 
2606 	if (auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Basic ", sizeof("Basic ")-1, sizeof("Basic ")-1) == 0) {
2607 		char *pass;
2608 		zend_string *user;
2609 
2610 		user = php_base64_decode((const unsigned char*)auth + 6, auth_len - 6);
2611 		if (user) {
2612 			pass = strchr(ZSTR_VAL(user), ':');
2613 			if (pass) {
2614 				*pass++ = '\0';
2615 				SG(request_info).auth_user = estrndup(ZSTR_VAL(user), ZSTR_LEN(user));
2616 				SG(request_info).auth_password = estrdup(pass);
2617 				ret = 0;
2618 			}
2619 			zend_string_free(user);
2620 		}
2621 	}
2622 
2623 	if (ret == -1) {
2624 		SG(request_info).auth_user = SG(request_info).auth_password = NULL;
2625 	} else {
2626 		SG(request_info).auth_digest = NULL;
2627 	}
2628 
2629 	if (ret == -1 && auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Digest ", sizeof("Digest ")-1, sizeof("Digest ")-1) == 0) {
2630 		SG(request_info).auth_digest = estrdup(auth + 7);
2631 		ret = 0;
2632 	}
2633 
2634 	if (ret == -1) {
2635 		SG(request_info).auth_digest = NULL;
2636 	}
2637 
2638 	return ret;
2639 }
2640 /* }}} */
2641 
2642 /* {{{ php_lint_script */
php_lint_script(zend_file_handle * file)2643 PHPAPI zend_result php_lint_script(zend_file_handle *file)
2644 {
2645 	zend_op_array *op_array;
2646 	zend_result retval = FAILURE;
2647 
2648 	zend_try {
2649 		op_array = zend_compile_file(file, ZEND_INCLUDE);
2650 
2651 		if (op_array) {
2652 			destroy_op_array(op_array);
2653 			efree(op_array);
2654 			retval = SUCCESS;
2655 		}
2656 	} zend_end_try();
2657 	if (EG(exception)) {
2658 		zend_exception_error(EG(exception), E_ERROR);
2659 	}
2660 
2661 	return retval;
2662 }
2663 /* }}} */
2664 
2665 #ifdef ZTS
2666 /* {{{ php_reserve_tsrm_memory */
php_reserve_tsrm_memory(void)2667 PHPAPI void php_reserve_tsrm_memory(void)
2668 {
2669 	tsrm_reserve(
2670 		TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
2671 		TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)) +
2672 		TSRM_ALIGNED_SIZE(sizeof(zend_php_scanner_globals)) +
2673 		TSRM_ALIGNED_SIZE(sizeof(zend_ini_scanner_globals)) +
2674 		TSRM_ALIGNED_SIZE(sizeof(virtual_cwd_globals)) +
2675 #ifdef ZEND_SIGNALS
2676 		TSRM_ALIGNED_SIZE(sizeof(zend_signal_globals_t)) +
2677 #endif
2678 		TSRM_ALIGNED_SIZE(zend_mm_globals_size()) +
2679 		TSRM_ALIGNED_SIZE(zend_gc_globals_size()) +
2680 		TSRM_ALIGNED_SIZE(sizeof(php_core_globals)) +
2681 		TSRM_ALIGNED_SIZE(sizeof(sapi_globals_struct))
2682 	);
2683 }
2684 /* }}} */
2685 
php_tsrm_startup_ex(int expected_threads)2686 PHPAPI bool php_tsrm_startup_ex(int expected_threads)
2687 {
2688 	bool ret = tsrm_startup(expected_threads, 1, 0, NULL);
2689 	php_reserve_tsrm_memory();
2690 	(void)ts_resource(0);
2691 	return ret;
2692 }
2693 
2694 /* {{{ php_tsrm_startup */
php_tsrm_startup(void)2695 PHPAPI bool php_tsrm_startup(void)
2696 {
2697 	return php_tsrm_startup_ex(1);
2698 }
2699 /* }}} */
2700 #endif
2701