xref: /php-src/main/main.c (revision 48d5ae98)
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 	/* Check that INI setting does not have any nul bytes */
656 	if (new_value && ZSTR_LEN(new_value) != strlen(ZSTR_VAL(new_value))) {
657 		/* TODO Emit warning? */
658 		return FAILURE;
659 	}
660 	/* Don't allow changing it in htaccess */
661 	if (stage == PHP_INI_STAGE_HTACCESS) {
662 			return FAILURE;
663 	}
664 	return SUCCESS;
665 }
666 /* }}} */
667 
668 /* defined in browscap.c */
669 PHP_INI_MH(OnChangeBrowscap);
670 
671 
672 /* Need to be read from the environment (?):
673  * PHP_AUTO_PREPEND_FILE
674  * PHP_AUTO_APPEND_FILE
675  * PHP_DOCUMENT_ROOT
676  * PHP_USER_DIR
677  * PHP_INCLUDE_PATH
678  */
679 
680  /* Windows use the internal mail */
681 #if defined(PHP_WIN32)
682 # define DEFAULT_SENDMAIL_PATH NULL
683 #else
684 # define DEFAULT_SENDMAIL_PATH PHP_PROG_SENDMAIL " -t -i"
685 #endif
686 
687 /* {{{ PHP_INI */
688 PHP_INI_BEGIN()
689 	PHP_INI_ENTRY_EX("highlight.comment",		HL_COMMENT_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
690 	PHP_INI_ENTRY_EX("highlight.default",		HL_DEFAULT_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
691 	PHP_INI_ENTRY_EX("highlight.html",			HL_HTML_COLOR,		PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
692 	PHP_INI_ENTRY_EX("highlight.keyword",		HL_KEYWORD_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
693 	PHP_INI_ENTRY_EX("highlight.string",		HL_STRING_COLOR,	PHP_INI_ALL,	NULL,			php_ini_color_displayer_cb)
694 
695 	STD_PHP_INI_ENTRY_EX("display_errors",		"1",		PHP_INI_ALL,		OnUpdateDisplayErrors,	display_errors,			php_core_globals,	core_globals, display_errors_mode)
696 	STD_PHP_INI_BOOLEAN("display_startup_errors",	"1",	PHP_INI_ALL,		OnUpdateBool,			display_startup_errors,	php_core_globals,	core_globals)
697 	STD_PHP_INI_BOOLEAN("enable_dl",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			enable_dl,				php_core_globals,	core_globals)
698 	STD_PHP_INI_BOOLEAN("expose_php",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			expose_php,				php_core_globals,	core_globals)
699 	STD_PHP_INI_ENTRY("docref_root", 			"", 		PHP_INI_ALL,		OnUpdateString,			docref_root,			php_core_globals,	core_globals)
700 	STD_PHP_INI_ENTRY("docref_ext",				"",			PHP_INI_ALL,		OnUpdateString,			docref_ext,				php_core_globals,	core_globals)
701 	STD_PHP_INI_BOOLEAN("html_errors",			"1",		PHP_INI_ALL,		OnUpdateBool,			html_errors,			php_core_globals,	core_globals)
702 	STD_PHP_INI_BOOLEAN("xmlrpc_errors",		"0",		PHP_INI_SYSTEM,		OnUpdateBool,			xmlrpc_errors,			php_core_globals,	core_globals)
703 	STD_PHP_INI_ENTRY("xmlrpc_error_number",	"0",		PHP_INI_ALL,		OnUpdateLong,			xmlrpc_error_number,	php_core_globals,	core_globals)
704 	STD_PHP_INI_ENTRY("max_input_time",			"-1",	PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			max_input_time,	php_core_globals,	core_globals)
705 	STD_PHP_INI_BOOLEAN("ignore_user_abort",	"0",		PHP_INI_ALL,		OnUpdateBool,			ignore_user_abort,		php_core_globals,	core_globals)
706 	STD_PHP_INI_BOOLEAN("implicit_flush",		"0",		PHP_INI_ALL,		OnUpdateBool,			implicit_flush,			php_core_globals,	core_globals)
707 	STD_PHP_INI_BOOLEAN("log_errors",			"0",		PHP_INI_ALL,		OnUpdateBool,			log_errors,				php_core_globals,	core_globals)
708 	STD_PHP_INI_BOOLEAN("ignore_repeated_errors",	"0",	PHP_INI_ALL,		OnUpdateBool,			ignore_repeated_errors,	php_core_globals,	core_globals)
709 	STD_PHP_INI_BOOLEAN("ignore_repeated_source",	"0",	PHP_INI_ALL,		OnUpdateBool,			ignore_repeated_source,	php_core_globals,	core_globals)
710 	STD_PHP_INI_BOOLEAN("report_memleaks",		"1",		PHP_INI_ALL,		OnUpdateBool,			report_memleaks,		php_core_globals,	core_globals)
711 	STD_PHP_INI_BOOLEAN("report_zend_debug",	"0",		PHP_INI_ALL,		OnUpdateBool,			report_zend_debug,		php_core_globals,	core_globals)
712 	STD_PHP_INI_ENTRY("output_buffering",		"0",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateLong,	output_buffering,		php_core_globals,	core_globals)
713 	STD_PHP_INI_ENTRY("output_handler",			NULL,		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateString,	output_handler,		php_core_globals,	core_globals)
714 	STD_PHP_INI_BOOLEAN("register_argc_argv",	"1",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateBool,	register_argc_argv,		php_core_globals,	core_globals)
715 	STD_PHP_INI_BOOLEAN("auto_globals_jit",		"1",		PHP_INI_PERDIR|PHP_INI_SYSTEM,	OnUpdateBool,	auto_globals_jit,	php_core_globals,	core_globals)
716 	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)
717 
718 	STD_PHP_INI_ENTRY("unserialize_callback_func",	NULL,	PHP_INI_ALL,		OnUpdateString,			unserialize_callback_func,	php_core_globals,	core_globals)
719 	STD_PHP_INI_ENTRY("serialize_precision",	"-1",	PHP_INI_ALL,		OnSetSerializePrecision,			serialize_precision,	php_core_globals,	core_globals)
720 	STD_PHP_INI_ENTRY("arg_separator.output",	"&",		PHP_INI_ALL,		OnUpdateStringUnempty,	arg_separator.output,	php_core_globals,	core_globals)
721 	STD_PHP_INI_ENTRY("arg_separator.input",	"&",		PHP_INI_SYSTEM|PHP_INI_PERDIR,	OnUpdateStringUnempty,	arg_separator.input,	php_core_globals,	core_globals)
722 
723 	STD_PHP_INI_ENTRY("auto_append_file",		NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,			auto_append_file,		php_core_globals,	core_globals)
724 	STD_PHP_INI_ENTRY("auto_prepend_file",		NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,			auto_prepend_file,		php_core_globals,	core_globals)
725 	STD_PHP_INI_ENTRY("doc_root",				NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	doc_root,				php_core_globals,	core_globals)
726 	STD_PHP_INI_ENTRY("default_charset",		PHP_DEFAULT_CHARSET,	PHP_INI_ALL,	OnUpdateDefaultCharset,			default_charset,		sapi_globals_struct, sapi_globals)
727 	STD_PHP_INI_ENTRY("default_mimetype",		SAPI_DEFAULT_MIMETYPE,	PHP_INI_ALL,	OnUpdateDefaultMimeTye,			default_mimetype,		sapi_globals_struct, sapi_globals)
728 	STD_PHP_INI_ENTRY("internal_encoding",		NULL,			PHP_INI_ALL,	OnUpdateInternalEncoding,	internal_encoding,	php_core_globals, core_globals)
729 	STD_PHP_INI_ENTRY("input_encoding",			NULL,			PHP_INI_ALL,	OnUpdateInputEncoding,				input_encoding,		php_core_globals, core_globals)
730 	STD_PHP_INI_ENTRY("output_encoding",		NULL,			PHP_INI_ALL,	OnUpdateOutputEncoding,				output_encoding,	php_core_globals, core_globals)
731 	STD_PHP_INI_ENTRY("error_log",				NULL,			PHP_INI_ALL,		OnUpdateErrorLog,				error_log,				php_core_globals,	core_globals)
732 	STD_PHP_INI_ENTRY("error_log_mode",			"0644",			PHP_INI_ALL,		OnUpdateLong,					error_log_mode,			php_core_globals,	core_globals)
733 	STD_PHP_INI_ENTRY("extension_dir",			PHP_EXTENSION_DIR,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	extension_dir,			php_core_globals,	core_globals)
734 	STD_PHP_INI_ENTRY("sys_temp_dir",			NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	sys_temp_dir,			php_core_globals,	core_globals)
735 	STD_PHP_INI_ENTRY("include_path",			PHP_INCLUDE_PATH,		PHP_INI_ALL,		OnUpdateStringUnempty,	include_path,			php_core_globals,	core_globals)
736 	PHP_INI_ENTRY("max_execution_time",			"30",		PHP_INI_ALL,			OnUpdateTimeout)
737 	STD_PHP_INI_ENTRY("open_basedir",			NULL,		PHP_INI_ALL,		OnUpdateBaseDir,			open_basedir,			php_core_globals,	core_globals)
738 
739 	STD_PHP_INI_BOOLEAN("file_uploads",			"1",		PHP_INI_SYSTEM,		OnUpdateBool,			file_uploads,			php_core_globals,	core_globals)
740 	STD_PHP_INI_ENTRY("upload_max_filesize",	"2M",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			upload_max_filesize,	php_core_globals,	core_globals)
741 	STD_PHP_INI_ENTRY("post_max_size",			"8M",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLong,			post_max_size,			sapi_globals_struct,sapi_globals)
742 	STD_PHP_INI_ENTRY("upload_tmp_dir",			NULL,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	upload_tmp_dir,			php_core_globals,	core_globals)
743 	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)
744 	STD_PHP_INI_ENTRY("max_input_vars",			"1000",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateLongGEZero,	max_input_vars,						php_core_globals,	core_globals)
745 
746 	STD_PHP_INI_ENTRY("user_dir",				NULL,		PHP_INI_SYSTEM,		OnUpdateString,			user_dir,				php_core_globals,	core_globals)
747 	STD_PHP_INI_ENTRY("variables_order",		"EGPCS",	PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateStringUnempty,	variables_order,		php_core_globals,	core_globals)
748 	STD_PHP_INI_ENTRY("request_order",			NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateString,	request_order,		php_core_globals,	core_globals)
749 
750 	STD_PHP_INI_ENTRY("error_append_string",	NULL,		PHP_INI_ALL,		OnUpdateString,			error_append_string,	php_core_globals,	core_globals)
751 	STD_PHP_INI_ENTRY("error_prepend_string",	NULL,		PHP_INI_ALL,		OnUpdateString,			error_prepend_string,	php_core_globals,	core_globals)
752 
753 	PHP_INI_ENTRY("SMTP",						"localhost",PHP_INI_ALL,		NULL)
754 	PHP_INI_ENTRY("smtp_port",					"25",		PHP_INI_ALL,		NULL)
755 	STD_PHP_INI_BOOLEAN("mail.add_x_header",			"0",		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateBool,			mail_x_header,			php_core_globals,	core_globals)
756 	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)
757 	STD_PHP_INI_ENTRY("mail.log",					NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnUpdateMailLog,			mail_log,			php_core_globals,	core_globals)
758 	PHP_INI_ENTRY("browscap",					NULL,		PHP_INI_SYSTEM,		OnChangeBrowscap)
759 	PHP_INI_ENTRY("memory_limit",				"128M",		PHP_INI_ALL,		OnChangeMemoryLimit)
760 	PHP_INI_ENTRY("precision",					"14",		PHP_INI_ALL,		OnSetPrecision)
761 	PHP_INI_ENTRY("sendmail_from",				NULL,		PHP_INI_ALL,		NULL)
762 	PHP_INI_ENTRY("sendmail_path",	DEFAULT_SENDMAIL_PATH,	PHP_INI_SYSTEM,		NULL)
763 	PHP_INI_ENTRY("mail.force_extra_parameters",NULL,		PHP_INI_SYSTEM|PHP_INI_PERDIR,		OnChangeMailForceExtra)
764 	PHP_INI_ENTRY("disable_functions",			"",			PHP_INI_SYSTEM,		NULL)
765 	PHP_INI_ENTRY("disable_classes",			"",			PHP_INI_SYSTEM,		NULL)
766 	PHP_INI_ENTRY("max_file_uploads",			"20",			PHP_INI_SYSTEM|PHP_INI_PERDIR,		NULL)
767 	PHP_INI_ENTRY("max_multipart_body_parts",	"-1",			PHP_INI_SYSTEM|PHP_INI_PERDIR,		NULL)
768 
769 	STD_PHP_INI_BOOLEAN("allow_url_fopen",		"1",		PHP_INI_SYSTEM,		OnUpdateBool,		allow_url_fopen,		php_core_globals,		core_globals)
770 	STD_PHP_INI_BOOLEAN("allow_url_include",	"0",		PHP_INI_SYSTEM,		OnUpdateBool,		allow_url_include,		php_core_globals,		core_globals)
771 	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)
772 
773 	STD_PHP_INI_ENTRY("realpath_cache_size",	"4096K",	PHP_INI_SYSTEM,		OnUpdateLong,	realpath_cache_size_limit,	virtual_cwd_globals,	cwd_globals)
774 	STD_PHP_INI_ENTRY("realpath_cache_ttl",		"120",		PHP_INI_SYSTEM,		OnUpdateLong,	realpath_cache_ttl,			virtual_cwd_globals,	cwd_globals)
775 
776 	STD_PHP_INI_ENTRY("user_ini.filename",		".user.ini",	PHP_INI_SYSTEM,		OnUpdateString,		user_ini_filename,	php_core_globals,		core_globals)
777 	STD_PHP_INI_ENTRY("user_ini.cache_ttl",		"300",			PHP_INI_SYSTEM,		OnUpdateLong,		user_ini_cache_ttl,	php_core_globals,		core_globals)
778 	STD_PHP_INI_ENTRY("hard_timeout",			"2",			PHP_INI_SYSTEM,		OnUpdateLong,		hard_timeout,		zend_executor_globals,	executor_globals)
779 #ifdef PHP_WIN32
780 	STD_PHP_INI_BOOLEAN("windows.show_crt_warning",		"0",		PHP_INI_ALL,		OnUpdateBool,			windows_show_crt_warning,			php_core_globals,	core_globals)
781 #endif
782 	STD_PHP_INI_ENTRY("syslog.facility",		"LOG_USER",		PHP_INI_SYSTEM,		OnSetFacility,		syslog_facility,	php_core_globals,		core_globals)
783 	STD_PHP_INI_ENTRY("syslog.ident",		"php",			PHP_INI_SYSTEM,		OnUpdateString,		syslog_ident,		php_core_globals,		core_globals)
784 	STD_PHP_INI_ENTRY("syslog.filter",		"no-ctrl",		PHP_INI_ALL,		OnSetLogFilter,		syslog_filter,		php_core_globals, 		core_globals)
785 PHP_INI_END()
786 /* }}} */
787 
788 /* True globals (no need for thread safety */
789 /* But don't make them a single int bitfield */
790 static bool module_initialized = false;
791 static bool module_startup = true;
792 static bool module_shutdown = false;
793 
794 /* {{{ php_during_module_startup */
php_during_module_startup(void)795 PHPAPI bool php_during_module_startup(void)
796 {
797 	return module_startup;
798 }
799 /* }}} */
800 
801 /* {{{ php_during_module_shutdown */
php_during_module_shutdown(void)802 PHPAPI bool php_during_module_shutdown(void)
803 {
804 	return module_shutdown;
805 }
806 /* }}} */
807 
808 /* {{{ php_get_module_initialized */
php_get_module_initialized(void)809 PHPAPI bool php_get_module_initialized(void)
810 {
811 	return module_initialized;
812 }
813 /* }}} */
814 
815 /* {{{ php_log_err_with_severity */
php_log_err_with_severity(const char * log_message,int syslog_type_int)816 PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int syslog_type_int)
817 {
818 	int fd = -1;
819 	time_t error_time;
820 
821 	if (PG(in_error_log)) {
822 		/* prevent recursive invocation */
823 		return;
824 	}
825 	PG(in_error_log) = 1;
826 
827 	/* Try to use the specified logging location. */
828 	if (PG(error_log) != NULL) {
829 		int error_log_mode;
830 
831 #ifdef HAVE_SYSLOG_H
832 		if (!strcmp(PG(error_log), "syslog")) {
833 			php_syslog(syslog_type_int, "%s", log_message);
834 			PG(in_error_log) = 0;
835 			return;
836 		}
837 #endif
838 
839 		error_log_mode = 0644;
840 
841 		if (PG(error_log_mode) > 0 && PG(error_log_mode) <= 0777) {
842 			error_log_mode = PG(error_log_mode);
843 		}
844 
845 		fd = VCWD_OPEN_MODE(PG(error_log), O_CREAT | O_APPEND | O_WRONLY, error_log_mode);
846 		if (fd != -1) {
847 			char *tmp;
848 			size_t len;
849 			zend_string *error_time_str;
850 
851 			time(&error_time);
852 #ifdef ZTS
853 			if (!php_during_module_startup()) {
854 				error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1);
855 			} else {
856 				error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 0);
857 			}
858 #else
859 			error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1);
860 #endif
861 			len = spprintf(&tmp, 0, "[%s] %s%s", ZSTR_VAL(error_time_str), log_message, PHP_EOL);
862 #ifdef PHP_WIN32
863 			php_flock(fd, LOCK_EX);
864 			/* XXX should eventually write in a loop if len > UINT_MAX */
865 			php_ignore_value(write(fd, tmp, (unsigned)len));
866 			php_flock(fd, LOCK_UN);
867 #else
868 			php_ignore_value(write(fd, tmp, len));
869 #endif
870 			efree(tmp);
871 			zend_string_free(error_time_str);
872 			close(fd);
873 			PG(in_error_log) = 0;
874 			return;
875 		}
876 	}
877 
878 	/* Otherwise fall back to the default logging location, if we have one */
879 
880 	if (sapi_module.log_message) {
881 		sapi_module.log_message(log_message, syslog_type_int);
882 	}
883 	PG(in_error_log) = 0;
884 }
885 /* }}} */
886 
887 /* {{{ php_write
888    wrapper for modules to use PHPWRITE */
php_write(void * buf,size_t size)889 PHPAPI size_t php_write(void *buf, size_t size)
890 {
891 	return PHPWRITE(buf, size);
892 }
893 /* }}} */
894 
895 /* {{{ php_printf */
php_printf(const char * format,...)896 PHPAPI size_t php_printf(const char *format, ...)
897 {
898 	va_list args;
899 	size_t ret;
900 	char *buffer;
901 	size_t size;
902 
903 	va_start(args, format);
904 	size = vspprintf(&buffer, 0, format, args);
905 	ret = PHPWRITE(buffer, size);
906 	efree(buffer);
907 	va_end(args);
908 
909 	return ret;
910 }
911 /* }}} */
912 
913 /* {{{ php_printf_unchecked */
php_printf_unchecked(const char * format,...)914 PHPAPI size_t php_printf_unchecked(const char *format, ...)
915 {
916 	va_list args;
917 	size_t ret;
918 	char *buffer;
919 	size_t size;
920 
921 	va_start(args, format);
922 	size = vspprintf(&buffer, 0, format, args);
923 	ret = PHPWRITE(buffer, size);
924 	efree(buffer);
925 	va_end(args);
926 
927 	return ret;
928 }
929 /* }}} */
930 
escape_html(const char * buffer,size_t buffer_len)931 static zend_string *escape_html(const char *buffer, size_t buffer_len) {
932 	zend_string *result = php_escape_html_entities_ex(
933 		(const unsigned char *) buffer, buffer_len, 0, ENT_COMPAT,
934 		/* charset_hint */ NULL, /* double_encode */ 1, /* quiet */ 1);
935 	if (!result || ZSTR_LEN(result) == 0) {
936 		/* Retry with substituting invalid chars on fail. */
937 		result = php_escape_html_entities_ex(
938 			(const unsigned char *) buffer, buffer_len, 0, ENT_COMPAT | ENT_HTML_SUBSTITUTE_ERRORS,
939 			/* charset_hint */ NULL, /* double_encode */ 1, /* quiet */ 1);
940 	}
941 	return result;
942 }
943 
944 /* {{{ php_verror */
945 /* php_verror is called from php_error_docref<n> functions.
946  * Its purpose is to unify error messages and automatically generate clickable
947  * html error messages if corresponding ini setting (html_errors) is activated.
948  * See: CODING_STANDARDS.md for details.
949  */
php_verror(const char * docref,const char * params,int type,const char * format,va_list args)950 PHPAPI ZEND_COLD void php_verror(const char *docref, const char *params, int type, const char *format, va_list args)
951 {
952 	zend_string *replace_origin = NULL;
953 	char *docref_buf = NULL, *target = NULL;
954 	char *docref_target = "", *docref_root = "";
955 	char *p;
956 	const char *space = "";
957 	const char *class_name = "";
958 	const char *function;
959 	int origin_len;
960 	char *origin;
961 	zend_string *message;
962 	int is_function = 0;
963 
964 	/* get error text into buffer and escape for html if necessary */
965 	zend_string *buffer = vstrpprintf(0, format, args);
966 
967 	if (PG(html_errors)) {
968 		zend_string *replace_buffer = escape_html(ZSTR_VAL(buffer), ZSTR_LEN(buffer));
969 		zend_string_free(buffer);
970 
971 		if (replace_buffer) {
972 			buffer = replace_buffer;
973 		} else {
974 			buffer = zend_empty_string;
975 		}
976 	}
977 
978 	/* which function caused the problem if any at all */
979 	if (php_during_module_startup()) {
980 		function = "PHP Startup";
981 	} else if (php_during_module_shutdown()) {
982 		function = "PHP Shutdown";
983 	} else if (PG(during_request_startup)) {
984 		function = "PHP Request Startup";
985 	} else if (EG(current_execute_data) &&
986 				EG(current_execute_data)->func &&
987 				ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
988 				EG(current_execute_data)->opline &&
989 				EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL
990 	) {
991 		switch (EG(current_execute_data)->opline->extended_value) {
992 			case ZEND_EVAL:
993 				function = "eval";
994 				is_function = 1;
995 				break;
996 			case ZEND_INCLUDE:
997 				function = "include";
998 				is_function = 1;
999 				break;
1000 			case ZEND_INCLUDE_ONCE:
1001 				function = "include_once";
1002 				is_function = 1;
1003 				break;
1004 			case ZEND_REQUIRE:
1005 				function = "require";
1006 				is_function = 1;
1007 				break;
1008 			case ZEND_REQUIRE_ONCE:
1009 				function = "require_once";
1010 				is_function = 1;
1011 				break;
1012 			default:
1013 				function = "Unknown";
1014 		}
1015 	} else if ((function = get_active_function_name()) && strlen(function)) {
1016 		is_function = 1;
1017 		class_name = get_active_class_name(&space);
1018 	} else if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
1019 		function = "PHP Request Shutdown";
1020 	} else {
1021 		function = "Unknown";
1022 	}
1023 
1024 	/* if we still have memory then format the origin */
1025 	if (is_function) {
1026 		origin_len = (int)spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, params);
1027 	} else {
1028 		origin_len = (int)spprintf(&origin, 0, "%s", function);
1029 	}
1030 
1031 	if (PG(html_errors)) {
1032 		replace_origin = escape_html(origin, origin_len);
1033 		efree(origin);
1034 		origin = ZSTR_VAL(replace_origin);
1035 	}
1036 
1037 	/* origin and buffer available, so let's come up with the error message */
1038 	if (docref && docref[0] == '#') {
1039 		docref_target = strchr(docref, '#');
1040 		docref = NULL;
1041 	}
1042 
1043 	/* no docref given but function is known (the default) */
1044 	if (!docref && is_function) {
1045 		int doclen;
1046 		while (*function == '_') {
1047 			function++;
1048 		}
1049 		if (space[0] == '\0') {
1050 			doclen = (int)spprintf(&docref_buf, 0, "function.%s", function);
1051 		} else {
1052 			doclen = (int)spprintf(&docref_buf, 0, "%s.%s", class_name, function);
1053 		}
1054 		while((p = strchr(docref_buf, '_')) != NULL) {
1055 			*p = '-';
1056 		}
1057 		zend_str_tolower(docref_buf, doclen);
1058 		docref = docref_buf;
1059 	}
1060 
1061 	/* we have a docref for a function AND
1062 	 * - we show errors in html mode AND
1063 	 * - the user wants to see the links
1064 	 */
1065 	if (docref && is_function && PG(html_errors) && strlen(PG(docref_root))) {
1066 		if (strncmp(docref, "http://", 7)) {
1067 			/* We don't have 'http://' so we use docref_root */
1068 
1069 			char *ref;  /* temp copy for duplicated docref */
1070 
1071 			docref_root = PG(docref_root);
1072 
1073 			ref = estrdup(docref);
1074 			if (docref_buf) {
1075 				efree(docref_buf);
1076 			}
1077 			docref_buf = ref;
1078 			/* strip of the target if any */
1079 			p = strrchr(ref, '#');
1080 			if (p) {
1081 				target = estrdup(p);
1082 				if (target) {
1083 					docref_target = target;
1084 					*p = '\0';
1085 				}
1086 			}
1087 			/* add the extension if it is set in ini */
1088 			if (PG(docref_ext) && strlen(PG(docref_ext))) {
1089 				spprintf(&docref_buf, 0, "%s%s", ref, PG(docref_ext));
1090 				efree(ref);
1091 			}
1092 			docref = docref_buf;
1093 		}
1094 		/* display html formatted or only show the additional links */
1095 		if (PG(html_errors)) {
1096 			message = zend_strpprintf_unchecked(0, "%s [<a href='%s%s%s'>%s</a>]: %S", origin, docref_root, docref, docref_target, docref, buffer);
1097 		} else {
1098 			message = zend_strpprintf_unchecked(0, "%s [%s%s%s]: %S", origin, docref_root, docref, docref_target, buffer);
1099 		}
1100 		if (target) {
1101 			efree(target);
1102 		}
1103 	} else {
1104 		message = zend_strpprintf_unchecked(0, "%s: %S", origin, buffer);
1105 	}
1106 	if (replace_origin) {
1107 		zend_string_free(replace_origin);
1108 	} else {
1109 		efree(origin);
1110 	}
1111 	if (docref_buf) {
1112 		efree(docref_buf);
1113 	}
1114 
1115 	zend_string_free(buffer);
1116 
1117 	zend_error_zstr(type, message);
1118 	zend_string_release(message);
1119 }
1120 /* }}} */
1121 
1122 /* {{{ php_error_docref */
1123 /* Generate an error which links to docref or the php.net documentation if docref is NULL */
1124 #define php_error_docref_impl(docref, type, format) do {\
1125 		va_list args; \
1126 		va_start(args, format); \
1127 		php_verror(docref, "", type, format, args); \
1128 		va_end(args); \
1129 	} while (0)
1130 
php_error_docref(const char * docref,int type,const char * format,...)1131 PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format, ...)
1132 {
1133 	php_error_docref_impl(docref, type, format);
1134 }
1135 
php_error_docref_unchecked(const char * docref,int type,const char * format,...)1136 PHPAPI ZEND_COLD void php_error_docref_unchecked(const char *docref, int type, const char *format, ...)
1137 {
1138 	php_error_docref_impl(docref, type, format);
1139 }
1140 /* }}} */
1141 
1142 /* {{{ php_error_docref1 */
1143 /* See: CODING_STANDARDS.md for details. */
php_error_docref1(const char * docref,const char * param1,int type,const char * format,...)1144 PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, int type, const char *format, ...)
1145 {
1146 	va_list args;
1147 
1148 	va_start(args, format);
1149 	php_verror(docref, param1, type, format, args);
1150 	va_end(args);
1151 }
1152 /* }}} */
1153 
1154 /* {{{ php_error_docref2 */
1155 /* See: CODING_STANDARDS.md for details. */
php_error_docref2(const char * docref,const char * param1,const char * param2,int type,const char * format,...)1156 PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format, ...)
1157 {
1158 	char *params;
1159 	va_list args;
1160 
1161 	spprintf(&params, 0, "%s,%s", param1, param2);
1162 	va_start(args, format);
1163 	php_verror(docref, params ? params : "...", type, format, args);
1164 	va_end(args);
1165 	if (params) {
1166 		efree(params);
1167 	}
1168 }
1169 /* }}} */
1170 
1171 #ifdef PHP_WIN32
php_win32_docref1_from_error(DWORD error,const char * param1)1172 PHPAPI ZEND_COLD void php_win32_docref1_from_error(DWORD error, const char *param1) {
1173 	char *buf = php_win32_error_to_msg(error);
1174 	size_t buf_len;
1175 
1176 	buf_len = strlen(buf);
1177 	if (buf_len >= 2) {
1178 		buf[buf_len - 1] = '\0';
1179 		buf[buf_len - 2] = '\0';
1180 	}
1181 	php_error_docref1(NULL, param1, E_WARNING, "%s (code: %lu)", buf, error);
1182 	php_win32_error_msg_free(buf);
1183 }
1184 
php_win32_docref2_from_error(DWORD error,const char * param1,const char * param2)1185 PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2) {
1186 	char *buf = php_win32_error_to_msg(error);
1187 	php_error_docref2(NULL, param1, param2, E_WARNING, "%s (code: %lu)", buf, error);
1188 	php_win32_error_msg_free(buf);
1189 }
1190 #endif
1191 
1192 /* {{{ php_html_puts */
php_html_puts(const char * str,size_t size)1193 PHPAPI void php_html_puts(const char *str, size_t size)
1194 {
1195 	zend_html_puts(str, size);
1196 }
1197 /* }}} */
1198 
clear_last_error(void)1199 static void clear_last_error(void) {
1200 	if (PG(last_error_message)) {
1201 		zend_string_release(PG(last_error_message));
1202 		PG(last_error_message) = NULL;
1203 	}
1204 	if (PG(last_error_file)) {
1205 		zend_string_release(PG(last_error_file));
1206 		PG(last_error_file) = NULL;
1207 	}
1208 }
1209 
1210 #if ZEND_DEBUG
1211 /* {{{ 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)1212 static void report_zend_debug_error_notify_cb(int type, zend_string *error_filename, uint32_t error_lineno, zend_string *message)
1213 {
1214 	if (PG(report_zend_debug)) {
1215 		bool trigger_break;
1216 
1217 		switch (type) {
1218 			case E_ERROR:
1219 			case E_CORE_ERROR:
1220 			case E_COMPILE_ERROR:
1221 			case E_USER_ERROR:
1222 				trigger_break=1;
1223 				break;
1224 			default:
1225 				trigger_break=0;
1226 				break;
1227 		}
1228 
1229 		zend_output_debug_string(trigger_break, "%s(%" PRIu32 ") : %s", ZSTR_VAL(error_filename), error_lineno, ZSTR_VAL(message));
1230 	}
1231 }
1232 /* }}} */
1233 #endif
1234 
1235 /* {{{ php_error_cb
1236  extended error handling function */
php_error_cb(int orig_type,zend_string * error_filename,const uint32_t error_lineno,zend_string * message)1237 static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
1238 {
1239 	bool display;
1240 	int type = orig_type & E_ALL;
1241 
1242 	/* check for repeated errors to be ignored */
1243 	if (PG(ignore_repeated_errors) && PG(last_error_message)) {
1244 		/* no check for PG(last_error_file) is needed since it cannot
1245 		 * be NULL if PG(last_error_message) is not NULL */
1246 		if (!zend_string_equals(PG(last_error_message), message)
1247 			|| (!PG(ignore_repeated_source)
1248 				&& ((PG(last_error_lineno) != (int)error_lineno)
1249 					|| !zend_string_equals(PG(last_error_file), error_filename)))) {
1250 			display = 1;
1251 		} else {
1252 			display = 0;
1253 		}
1254 	} else {
1255 		display = 1;
1256 	}
1257 
1258 	/* according to error handling mode, throw exception or show it */
1259 	if (EG(error_handling) == EH_THROW) {
1260 		switch (type) {
1261 			case E_WARNING:
1262 			case E_CORE_WARNING:
1263 			case E_COMPILE_WARNING:
1264 			case E_USER_WARNING:
1265 				/* throw an exception if we are in EH_THROW mode and the type is warning.
1266 				 * fatal errors are real errors and cannot be made exceptions.
1267 				 * exclude deprecated for the sake of BC to old damaged code.
1268 				 * notices are no errors and are not treated as such like E_WARNINGS.
1269 				 * DO NOT overwrite a pending exception.
1270 				 */
1271 				if (!EG(exception)) {
1272 					zend_throw_error_exception(EG(exception_class), message, 0, type);
1273 				}
1274 				return;
1275 			default:
1276 				break;
1277 		}
1278 	}
1279 
1280 	/* store the error if it has changed */
1281 	if (display) {
1282 		clear_last_error();
1283 		if (!error_filename) {
1284 			error_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
1285 		}
1286 		PG(last_error_type) = type;
1287 		PG(last_error_message) = zend_string_copy(message);
1288 		PG(last_error_file) = zend_string_copy(error_filename);
1289 		PG(last_error_lineno) = error_lineno;
1290 	}
1291 
1292 	if (zend_alloc_in_memory_limit_error_reporting()) {
1293 		php_output_discard_all();
1294 	}
1295 
1296 	/* display/log the error if necessary */
1297 	if (display && ((EG(error_reporting) & type) || (type & E_CORE))
1298 		&& (PG(log_errors) || PG(display_errors) || (!module_initialized))) {
1299 		char *error_type_str;
1300 		int syslog_type_int = LOG_NOTICE;
1301 
1302 		switch (type) {
1303 			case E_ERROR:
1304 			case E_CORE_ERROR:
1305 			case E_COMPILE_ERROR:
1306 			case E_USER_ERROR:
1307 				error_type_str = "Fatal error";
1308 				syslog_type_int = LOG_ERR;
1309 				break;
1310 			case E_RECOVERABLE_ERROR:
1311 				error_type_str = "Recoverable fatal error";
1312 				syslog_type_int = LOG_ERR;
1313 				break;
1314 			case E_WARNING:
1315 			case E_CORE_WARNING:
1316 			case E_COMPILE_WARNING:
1317 			case E_USER_WARNING:
1318 				error_type_str = "Warning";
1319 				syslog_type_int = LOG_WARNING;
1320 				break;
1321 			case E_PARSE:
1322 				error_type_str = "Parse error";
1323 				syslog_type_int = LOG_ERR;
1324 				break;
1325 			case E_NOTICE:
1326 			case E_USER_NOTICE:
1327 				error_type_str = "Notice";
1328 				syslog_type_int = LOG_NOTICE;
1329 				break;
1330 			case E_STRICT:
1331 				error_type_str = "Strict Standards";
1332 				syslog_type_int = LOG_INFO;
1333 				break;
1334 			case E_DEPRECATED:
1335 			case E_USER_DEPRECATED:
1336 				error_type_str = "Deprecated";
1337 				syslog_type_int = LOG_INFO;
1338 				break;
1339 			default:
1340 				error_type_str = "Unknown error";
1341 				break;
1342 		}
1343 
1344 		if (PG(log_errors)
1345 				|| (!module_initialized && (!PG(display_startup_errors) || !PG(display_errors)))) {
1346 			char *log_buffer;
1347 #ifdef PHP_WIN32
1348 			if (type == E_CORE_ERROR || type == E_CORE_WARNING) {
1349 				syslog(LOG_ALERT, "PHP %s: %s (%s)", error_type_str, ZSTR_VAL(message), GetCommandLine());
1350 			}
1351 #endif
1352 			spprintf(&log_buffer, 0, "PHP %s:  %s in %s on line %" PRIu32, error_type_str, ZSTR_VAL(message), ZSTR_VAL(error_filename), error_lineno);
1353 			php_log_err_with_severity(log_buffer, syslog_type_int);
1354 			efree(log_buffer);
1355 		}
1356 
1357 		if (PG(display_errors) && ((module_initialized && !PG(during_request_startup)) || (PG(display_startup_errors)))) {
1358 			if (PG(xmlrpc_errors)) {
1359 				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);
1360 			} else {
1361 				char *prepend_string = INI_STR("error_prepend_string");
1362 				char *append_string = INI_STR("error_append_string");
1363 
1364 				if (PG(html_errors)) {
1365 					if (type == E_ERROR || type == E_PARSE) {
1366 						zend_string *buf = escape_html(ZSTR_VAL(message), ZSTR_LEN(message));
1367 						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));
1368 						zend_string_free(buf);
1369 					} else {
1370 						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));
1371 					}
1372 				} else {
1373 					/* Write CLI/CGI errors to stderr if display_errors = "stderr" */
1374 					if ((!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "cgi") || !strcmp(sapi_module.name, "phpdbg")) &&
1375 						PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR
1376 					) {
1377 						fprintf(stderr, "%s: ", error_type_str);
1378 						fwrite(ZSTR_VAL(message), sizeof(char), ZSTR_LEN(message), stderr);
1379 						fprintf(stderr, " in %s on line %" PRIu32 "\n", ZSTR_VAL(error_filename), error_lineno);
1380 #ifdef PHP_WIN32
1381 						fflush(stderr);
1382 #endif
1383 					} else {
1384 						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));
1385 					}
1386 				}
1387 			}
1388 		}
1389 	}
1390 
1391 	/* Bail out if we can't recover */
1392 	switch (type) {
1393 		case E_CORE_ERROR:
1394 			if(!module_initialized) {
1395 				/* bad error in module startup - no way we can live with this */
1396 				exit(-2);
1397 			}
1398 		ZEND_FALLTHROUGH;
1399 		case E_ERROR:
1400 		case E_RECOVERABLE_ERROR:
1401 		case E_PARSE:
1402 		case E_COMPILE_ERROR:
1403 		case E_USER_ERROR:
1404 			EG(exit_status) = 255;
1405 			if (module_initialized) {
1406 				if (!PG(display_errors) &&
1407 				    !SG(headers_sent) &&
1408 					SG(sapi_headers).http_response_code == 200
1409 				) {
1410 					sapi_header_line ctr = {0};
1411 
1412 					ctr.line = "HTTP/1.0 500 Internal Server Error";
1413 					ctr.line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
1414 					sapi_header_op(SAPI_HEADER_REPLACE, &ctr);
1415 				}
1416 				/* the parser would return 1 (failure), we can bail out nicely */
1417 				if (!(orig_type & E_DONT_BAIL)) {
1418 					/* restore memory limit */
1419 					zend_set_memory_limit(PG(memory_limit));
1420 					zend_objects_store_mark_destructed(&EG(objects_store));
1421 					if (CG(in_compilation) && (type == E_COMPILE_ERROR || type == E_PARSE)) {
1422 						/* We bailout during compilation which may for example leave stale entries in CG(loop_var_stack).
1423 						 * If code is compiled during shutdown, we need to make sure the compiler is reset to a clean state,
1424 						 * otherwise this will lead to incorrect compilation during shutdown.
1425 						 * We don't do a full re-initialization via init_compiler() because that will also reset streams and resources. */
1426 						shutdown_compiler();
1427 						zend_init_compiler_data_structures();
1428 					}
1429 					zend_bailout();
1430 					return;
1431 				}
1432 			}
1433 			break;
1434 	}
1435 }
1436 /* }}} */
1437 
1438 /* {{{ php_get_current_user */
php_get_current_user(void)1439 PHPAPI char *php_get_current_user(void)
1440 {
1441 	zend_stat_t *pstat = NULL;
1442 
1443 	if (SG(request_info).current_user) {
1444 		return SG(request_info).current_user;
1445 	}
1446 
1447 	/* FIXME: I need to have this somehow handled if
1448 	USE_SAPI is defined, because cgi will also be
1449 	interfaced in USE_SAPI */
1450 
1451 	pstat = sapi_get_stat();
1452 
1453 	if (!pstat) {
1454 		return "";
1455 	} else {
1456 #ifdef PHP_WIN32
1457 		char *name = php_win32_get_username();
1458 		int len;
1459 
1460 		if (!name) {
1461 			return "";
1462 		}
1463 		len = (int)strlen(name);
1464 		name[len] = '\0';
1465 		SG(request_info).current_user_length = len;
1466 		SG(request_info).current_user = estrndup(name, len);
1467 		free(name);
1468 		return SG(request_info).current_user;
1469 #else
1470 		struct passwd *pwd;
1471 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
1472 		struct passwd _pw;
1473 		struct passwd *retpwptr = NULL;
1474 		int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
1475 		char *pwbuf;
1476 
1477 		if (pwbuflen < 1) {
1478 			return "";
1479 		}
1480 		pwbuf = emalloc(pwbuflen);
1481 		if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
1482 			efree(pwbuf);
1483 			return "";
1484 		}
1485 		if (retpwptr == NULL) {
1486 			efree(pwbuf);
1487 			return "";
1488 		}
1489 		pwd = &_pw;
1490 #else
1491 		if ((pwd=getpwuid(pstat->st_uid))==NULL) {
1492 			return "";
1493 		}
1494 #endif
1495 		SG(request_info).current_user_length = strlen(pwd->pw_name);
1496 		SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
1497 #if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
1498 		efree(pwbuf);
1499 #endif
1500 		return SG(request_info).current_user;
1501 #endif
1502 	}
1503 }
1504 /* }}} */
1505 
1506 /* {{{ Sets the maximum time a script can run */
PHP_FUNCTION(set_time_limit)1507 PHP_FUNCTION(set_time_limit)
1508 {
1509 	zend_long new_timeout;
1510 	char *new_timeout_str;
1511 	size_t new_timeout_strlen;
1512 	zend_string *key;
1513 
1514 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &new_timeout) == FAILURE) {
1515 		RETURN_THROWS();
1516 	}
1517 
1518 	new_timeout_strlen = zend_spprintf(&new_timeout_str, 0, ZEND_LONG_FMT, new_timeout);
1519 
1520 	key = ZSTR_INIT_LITERAL("max_execution_time", 0);
1521 	if (zend_alter_ini_entry_chars_ex(key, new_timeout_str, new_timeout_strlen, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == SUCCESS) {
1522 		RETVAL_TRUE;
1523 	} else {
1524 		RETVAL_FALSE;
1525 	}
1526 	zend_string_release_ex(key, 0);
1527 	efree(new_timeout_str);
1528 }
1529 /* }}} */
1530 
1531 /* {{{ php_fopen_wrapper_for_zend */
php_fopen_wrapper_for_zend(zend_string * filename,zend_string ** opened_path)1532 static FILE *php_fopen_wrapper_for_zend(zend_string *filename, zend_string **opened_path)
1533 {
1534 	*opened_path = filename;
1535 	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);
1536 }
1537 /* }}} */
1538 
php_zend_stream_closer(void * handle)1539 static void php_zend_stream_closer(void *handle) /* {{{ */
1540 {
1541 	php_stream_close((php_stream*)handle);
1542 }
1543 /* }}} */
1544 
php_zend_stream_fsizer(void * handle)1545 static size_t php_zend_stream_fsizer(void *handle) /* {{{ */
1546 {
1547 	php_stream *stream = handle;
1548 	php_stream_statbuf ssb;
1549 
1550 	/* File size reported by stat() may be inaccurate if stream filters are used.
1551 	 * TODO: Should stat() be generally disabled if filters are used? */
1552 	if (stream->readfilters.head) {
1553 		return 0;
1554 	}
1555 
1556 	if (php_stream_stat(stream, &ssb) == 0) {
1557 		return ssb.sb.st_size;
1558 	}
1559 	return 0;
1560 }
1561 /* }}} */
1562 
php_stream_open_for_zend(zend_file_handle * handle)1563 static zend_result php_stream_open_for_zend(zend_file_handle *handle) /* {{{ */
1564 {
1565 	return php_stream_open_for_zend_ex(handle, USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE);
1566 }
1567 /* }}} */
1568 
php_stream_open_for_zend_ex(zend_file_handle * handle,int mode)1569 PHPAPI zend_result php_stream_open_for_zend_ex(zend_file_handle *handle, int mode) /* {{{ */
1570 {
1571 	zend_string *opened_path;
1572 	zend_string *filename;
1573 	php_stream *stream;
1574 
1575 	ZEND_ASSERT(handle->type == ZEND_HANDLE_FILENAME);
1576 	opened_path = filename = handle->filename;
1577 	stream = php_stream_open_wrapper((char *)ZSTR_VAL(filename), "rb", mode | STREAM_OPEN_FOR_ZEND_STREAM, &opened_path);
1578 	if (stream) {
1579 		memset(handle, 0, sizeof(zend_file_handle));
1580 		handle->type = ZEND_HANDLE_STREAM;
1581 		handle->filename = filename;
1582 		handle->opened_path = opened_path;
1583 		handle->handle.stream.handle  = stream;
1584 		handle->handle.stream.reader  = (zend_stream_reader_t)_php_stream_read;
1585 		handle->handle.stream.fsizer  = php_zend_stream_fsizer;
1586 		handle->handle.stream.isatty  = 0;
1587 		handle->handle.stream.closer = php_zend_stream_closer;
1588 		/* suppress warning if this stream is not explicitly closed */
1589 		php_stream_auto_cleanup(stream);
1590 		/* Disable buffering to avoid double buffering between PHP and Zend streams. */
1591 		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, PHP_STREAM_BUFFER_NONE, NULL);
1592 
1593 		return SUCCESS;
1594 	}
1595 	return FAILURE;
1596 }
1597 /* }}} */
1598 
php_resolve_path_for_zend(zend_string * filename)1599 static zend_string *php_resolve_path_for_zend(zend_string *filename) /* {{{ */
1600 {
1601 	return php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), PG(include_path));
1602 }
1603 /* }}} */
1604 
1605 /* {{{ php_get_configuration_directive_for_zend */
php_get_configuration_directive_for_zend(zend_string * name)1606 static zval *php_get_configuration_directive_for_zend(zend_string *name)
1607 {
1608 	return cfg_get_entry_ex(name);
1609 }
1610 /* }}} */
1611 
1612 /* {{{ php_free_request_globals */
php_free_request_globals(void)1613 static void php_free_request_globals(void)
1614 {
1615 	clear_last_error();
1616 	if (PG(php_sys_temp_dir)) {
1617 		efree(PG(php_sys_temp_dir));
1618 		PG(php_sys_temp_dir) = NULL;
1619 	}
1620 
1621 	EG(filename_override) = NULL;
1622 	EG(lineno_override) = -1;
1623 }
1624 /* }}} */
1625 
1626 /* {{{ php_message_handler_for_zend */
php_message_handler_for_zend(zend_long message,const void * data)1627 static ZEND_COLD void php_message_handler_for_zend(zend_long message, const void *data)
1628 {
1629 	switch (message) {
1630 		case ZMSG_FAILED_INCLUDE_FOPEN: {
1631 			char *tmp = estrdup((char *) data);
1632 			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)));
1633 			efree(tmp);
1634 			break;
1635 		}
1636 		case ZMSG_FAILED_REQUIRE_FOPEN: {
1637 			char *tmp = estrdup((char *) data);
1638 			zend_throw_error(NULL, "Failed opening required '%s' (include_path='%s')", php_strip_url_passwd(tmp), STR_PRINT(PG(include_path)));
1639 			efree(tmp);
1640 			break;
1641 		}
1642 		case ZMSG_FAILED_HIGHLIGHT_FOPEN: {
1643 			char *tmp = estrdup((char *) data);
1644 			php_error_docref(NULL, E_WARNING, "Failed opening '%s' for highlighting", php_strip_url_passwd(tmp));
1645 			efree(tmp);
1646 			break;
1647 		}
1648 		case ZMSG_MEMORY_LEAK_DETECTED:
1649 		case ZMSG_MEMORY_LEAK_REPEATED:
1650 #if ZEND_DEBUG
1651 			if (EG(error_reporting) & E_WARNING) {
1652 				char memory_leak_buf[1024];
1653 
1654 				if (message==ZMSG_MEMORY_LEAK_DETECTED) {
1655 					zend_leak_info *t = (zend_leak_info *) data;
1656 
1657 					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));
1658 					if (t->orig_filename) {
1659 						char relay_buf[512];
1660 
1661 						snprintf(relay_buf, 512, "%s(%" PRIu32 ") : Actual location (location was relayed)\n", t->orig_filename, t->orig_lineno);
1662 						strlcat(memory_leak_buf, relay_buf, sizeof(memory_leak_buf));
1663 					}
1664 				} else {
1665 					unsigned long leak_count = (uintptr_t) data;
1666 
1667 					snprintf(memory_leak_buf, 512, "Last leak repeated %lu time%s\n", leak_count, (leak_count>1?"s":""));
1668 				}
1669 #	if defined(PHP_WIN32)
1670 				if (IsDebuggerPresent()) {
1671 					OutputDebugString(memory_leak_buf);
1672 				} else {
1673 					fprintf(stderr, "%s", memory_leak_buf);
1674 				}
1675 #	else
1676 				fprintf(stderr, "%s", memory_leak_buf);
1677 #	endif
1678 			}
1679 #endif
1680 			break;
1681 		case ZMSG_MEMORY_LEAKS_GRAND_TOTAL:
1682 #if ZEND_DEBUG
1683 			if (EG(error_reporting) & E_WARNING) {
1684 				char memory_leak_buf[512];
1685 
1686 				snprintf(memory_leak_buf, 512, "=== Total %d memory leaks detected ===\n", *((uint32_t *) data));
1687 #	if defined(PHP_WIN32)
1688 				if (IsDebuggerPresent()) {
1689 					OutputDebugString(memory_leak_buf);
1690 				} else {
1691 					fprintf(stderr, "%s", memory_leak_buf);
1692 				}
1693 #	else
1694 				fprintf(stderr, "%s", memory_leak_buf);
1695 #	endif
1696 			}
1697 #endif
1698 			break;
1699 		case ZMSG_LOG_SCRIPT_NAME: {
1700 				struct tm *ta, tmbuf;
1701 				time_t curtime;
1702 				char *datetime_str, asctimebuf[52];
1703 				char memory_leak_buf[4096];
1704 
1705 				time(&curtime);
1706 				ta = php_localtime_r(&curtime, &tmbuf);
1707 				datetime_str = php_asctime_r(ta, asctimebuf);
1708 				if (datetime_str) {
1709 					datetime_str[strlen(datetime_str)-1]=0;	/* get rid of the trailing newline */
1710 					snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[%s]  Script:  '%s'\n", datetime_str, SAFE_FILENAME(SG(request_info).path_translated));
1711 				} else {
1712 					snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[null]  Script:  '%s'\n", SAFE_FILENAME(SG(request_info).path_translated));
1713 				}
1714 #	if defined(PHP_WIN32)
1715 				if (IsDebuggerPresent()) {
1716 					OutputDebugString(memory_leak_buf);
1717 				} else {
1718 					fprintf(stderr, "%s", memory_leak_buf);
1719 				}
1720 #	else
1721 				fprintf(stderr, "%s", memory_leak_buf);
1722 #	endif
1723 			}
1724 			break;
1725 	}
1726 }
1727 /* }}} */
1728 
1729 
php_on_timeout(int seconds)1730 void php_on_timeout(int seconds)
1731 {
1732 	PG(connection_status) |= PHP_CONNECTION_TIMEOUT;
1733 }
1734 
1735 #if PHP_SIGCHILD
1736 /* {{{ sigchld_handler */
sigchld_handler(int apar)1737 static void sigchld_handler(int apar)
1738 {
1739 	int errno_save = errno;
1740 
1741 	while (waitpid(-1, NULL, WNOHANG) > 0);
1742 	signal(SIGCHLD, sigchld_handler);
1743 
1744 	errno = errno_save;
1745 }
1746 /* }}} */
1747 #endif
1748 
1749 /* {{{ php_request_startup */
php_request_startup(void)1750 zend_result php_request_startup(void)
1751 {
1752 	zend_result retval = SUCCESS;
1753 
1754 	zend_interned_strings_activate();
1755 
1756 #ifdef HAVE_DTRACE
1757 	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));
1758 #endif /* HAVE_DTRACE */
1759 
1760 #ifdef PHP_WIN32
1761 # if defined(ZTS)
1762 	_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
1763 # endif
1764 	PG(com_initialized) = 0;
1765 #endif
1766 
1767 #if PHP_SIGCHILD
1768 	signal(SIGCHLD, sigchld_handler);
1769 #endif
1770 
1771 	zend_try {
1772 		PG(in_error_log) = 0;
1773 		PG(during_request_startup) = 1;
1774 
1775 		php_output_activate();
1776 
1777 		/* initialize global variables */
1778 		PG(modules_activated) = 0;
1779 		PG(header_is_being_sent) = 0;
1780 		PG(connection_status) = PHP_CONNECTION_NORMAL;
1781 		PG(in_user_include) = 0;
1782 
1783 		zend_activate();
1784 		sapi_activate();
1785 
1786 #ifdef ZEND_SIGNALS
1787 		zend_signal_activate();
1788 #endif
1789 
1790 		if (PG(max_input_time) == -1) {
1791 			zend_set_timeout(EG(timeout_seconds), 1);
1792 		} else {
1793 			zend_set_timeout(PG(max_input_time), 1);
1794 		}
1795 
1796 		/* Disable realpath cache if an open_basedir is set */
1797 		if (PG(open_basedir) && *PG(open_basedir)) {
1798 			CWDG(realpath_cache_size_limit) = 0;
1799 		}
1800 
1801 		if (PG(expose_php) && !SG(headers_sent)) {
1802 			sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
1803 		}
1804 
1805 		if (PG(output_handler) && PG(output_handler)[0]) {
1806 			zval oh;
1807 
1808 			ZVAL_STRING(&oh, PG(output_handler));
1809 			php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS);
1810 			zval_ptr_dtor(&oh);
1811 		} else if (PG(output_buffering)) {
1812 			php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS);
1813 		} else if (PG(implicit_flush)) {
1814 			php_output_set_implicit_flush(1);
1815 		}
1816 
1817 		/* We turn this off in php_execute_script() */
1818 		/* PG(during_request_startup) = 0; */
1819 
1820 		php_hash_environment();
1821 		zend_activate_modules();
1822 		PG(modules_activated)=1;
1823 	} zend_catch {
1824 		retval = FAILURE;
1825 	} zend_end_try();
1826 
1827 	SG(sapi_started) = 1;
1828 
1829 	return retval;
1830 }
1831 /* }}} */
1832 
1833 /* {{{ php_request_shutdown */
php_request_shutdown(void * dummy)1834 void php_request_shutdown(void *dummy)
1835 {
1836 	bool report_memleaks;
1837 
1838 	EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
1839 
1840 	report_memleaks = PG(report_memleaks);
1841 
1842 	/* EG(current_execute_data) points into nirvana and therefore cannot be safely accessed
1843 	 * inside zend_executor callback functions.
1844 	 */
1845 	EG(current_execute_data) = NULL;
1846 
1847 	php_deactivate_ticks();
1848 
1849 	/* 0. Call any open observer end handlers that are still open after a zend_bailout */
1850 	if (ZEND_OBSERVER_ENABLED) {
1851 		zend_observer_fcall_end_all();
1852 	}
1853 
1854 	/* 1. Call all possible shutdown functions registered with register_shutdown_function() */
1855 	if (PG(modules_activated)) {
1856 		php_call_shutdown_functions();
1857 	}
1858 
1859 	/* 2. Call all possible __destruct() functions */
1860 	zend_try {
1861 		zend_call_destructors();
1862 	} zend_end_try();
1863 
1864 	/* 3. Flush all output buffers */
1865 	zend_try {
1866 		php_output_end_all();
1867 	} zend_end_try();
1868 
1869 	/* 4. Reset max_execution_time (no longer executing php code after response sent) */
1870 	zend_try {
1871 		zend_unset_timeout();
1872 	} zend_end_try();
1873 
1874 	/* 5. Call all extensions RSHUTDOWN functions */
1875 	if (PG(modules_activated)) {
1876 		zend_deactivate_modules();
1877 	}
1878 
1879 	/* 6. Shutdown output layer (send the set HTTP headers, cleanup output handlers, etc.) */
1880 	zend_try {
1881 		php_output_deactivate();
1882 	} zend_end_try();
1883 
1884 	/* 7. Free shutdown functions */
1885 	if (PG(modules_activated)) {
1886 		php_free_shutdown_functions();
1887 	}
1888 
1889 	/* 8. Destroy super-globals */
1890 	zend_try {
1891 		int i;
1892 
1893 		for (i=0; i<NUM_TRACK_VARS; i++) {
1894 			zval_ptr_dtor(&PG(http_globals)[i]);
1895 		}
1896 	} zend_end_try();
1897 
1898 	/* 9. Shutdown scanner/executor/compiler and restore ini entries */
1899 	zend_deactivate();
1900 
1901 	/* 10. free request-bound globals */
1902 	php_free_request_globals();
1903 
1904 	/* 11. Call all extensions post-RSHUTDOWN functions */
1905 	zend_try {
1906 		zend_post_deactivate_modules();
1907 	} zend_end_try();
1908 
1909 	/* 12. SAPI related shutdown*/
1910 	zend_try {
1911 		sapi_deactivate_module();
1912 	} zend_end_try();
1913 	/* free SAPI stuff */
1914 	sapi_deactivate_destroy();
1915 
1916 	/* 13. free virtual CWD memory */
1917 	virtual_cwd_deactivate();
1918 
1919 	/* 14. Destroy stream hashes */
1920 	zend_try {
1921 		php_shutdown_stream_hashes();
1922 	} zend_end_try();
1923 
1924 	/* 15. Free Willy (here be crashes) */
1925 	zend_arena_destroy(CG(arena));
1926 	zend_interned_strings_deactivate();
1927 	zend_try {
1928 		shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0);
1929 	} zend_end_try();
1930 
1931 	/* Reset memory limit, as the reset during INI_STAGE_DEACTIVATE may have failed.
1932 	 * At this point, no memory beyond a single chunk should be in use. */
1933 	zend_set_memory_limit(PG(memory_limit));
1934 
1935 	/* 16. Deactivate Zend signals */
1936 #ifdef ZEND_SIGNALS
1937 	zend_signal_deactivate();
1938 #endif
1939 
1940 #ifdef PHP_WIN32
1941 	if (PG(com_initialized)) {
1942 		CoUninitialize();
1943 		PG(com_initialized) = 0;
1944 	}
1945 #endif
1946 
1947 #ifdef HAVE_DTRACE
1948 	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));
1949 #endif /* HAVE_DTRACE */
1950 }
1951 /* }}} */
1952 
1953 /* {{{ php_com_initialize */
php_com_initialize(void)1954 PHPAPI void php_com_initialize(void)
1955 {
1956 #ifdef PHP_WIN32
1957 	if (!PG(com_initialized)) {
1958 		if (CoInitialize(NULL) == S_OK) {
1959 			PG(com_initialized) = 1;
1960 		}
1961 	}
1962 #endif
1963 }
1964 /* }}} */
1965 
1966 #ifdef ZTS
1967 /* {{{ core_globals_ctor */
core_globals_ctor(php_core_globals * core_globals)1968 static void core_globals_ctor(php_core_globals *core_globals)
1969 {
1970 	memset(core_globals, 0, sizeof(*core_globals));
1971 	php_startup_ticks();
1972 }
1973 /* }}} */
1974 #endif
1975 
1976 /* {{{ core_globals_dtor */
core_globals_dtor(php_core_globals * core_globals)1977 static void core_globals_dtor(php_core_globals *core_globals)
1978 {
1979 	/* These should have been freed earlier. */
1980 	ZEND_ASSERT(!core_globals->last_error_message);
1981 	ZEND_ASSERT(!core_globals->last_error_file);
1982 
1983 	if (core_globals->disable_classes) {
1984 		free(core_globals->disable_classes);
1985 	}
1986 	if (core_globals->php_binary) {
1987 		free(core_globals->php_binary);
1988 	}
1989 
1990 	php_shutdown_ticks(core_globals);
1991 }
1992 /* }}} */
1993 
PHP_MINFO_FUNCTION(php_core)1994 PHP_MINFO_FUNCTION(php_core) { /* {{{ */
1995 	php_info_print_table_start();
1996 	php_info_print_table_row(2, "PHP Version", PHP_VERSION);
1997 	php_info_print_table_end();
1998 	DISPLAY_INI_ENTRIES();
1999 }
2000 /* }}} */
2001 
2002 /* {{{ php_register_extensions */
php_register_extensions(zend_module_entry * const * ptr,int count)2003 zend_result php_register_extensions(zend_module_entry * const * ptr, int count)
2004 {
2005 	zend_module_entry * const * end = ptr + count;
2006 
2007 	while (ptr < end) {
2008 		if (*ptr) {
2009 			if (zend_register_internal_module(*ptr)==NULL) {
2010 				return FAILURE;
2011 			}
2012 		}
2013 		ptr++;
2014 	}
2015 	return SUCCESS;
2016 }
2017 
2018 #ifdef PHP_WIN32
2019 static _invalid_parameter_handler old_invalid_parameter_handler;
2020 
dummy_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)2021 void dummy_invalid_parameter_handler(
2022 		const wchar_t *expression,
2023 		const wchar_t *function,
2024 		const wchar_t *file,
2025 		unsigned int   line,
2026 		uintptr_t      pReserved)
2027 {
2028 	static int called = 0;
2029 	char buf[1024];
2030 	int len;
2031 
2032 	if (!called) {
2033 			if(PG(windows_show_crt_warning)) {
2034 			called = 1;
2035 			if (function) {
2036 				if (file) {
2037 					len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws' (%ws:%u)", function, file, line);
2038 				} else {
2039 					len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws'", function);
2040 				}
2041 			} else {
2042 				len = _snprintf(buf, sizeof(buf)-1, "Invalid CRT parameter detected (function not known)");
2043 			}
2044 			zend_error(E_WARNING, "%s", buf);
2045 			called = 0;
2046 		}
2047 	}
2048 }
2049 #endif
2050 
2051 /* {{{ php_module_startup */
php_module_startup(sapi_module_struct * sf,zend_module_entry * additional_module)2052 zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_module)
2053 {
2054 	zend_utility_functions zuf;
2055 	zend_utility_values zuv;
2056 	zend_result retval = SUCCESS;
2057 	int module_number = 0;
2058 	zend_module_entry *module;
2059 
2060 #ifdef PHP_WIN32
2061 	WORD wVersionRequested = MAKEWORD(2, 0);
2062 	WSADATA wsaData;
2063 
2064 	old_invalid_parameter_handler =
2065 		_set_invalid_parameter_handler(dummy_invalid_parameter_handler);
2066 	if (old_invalid_parameter_handler != NULL) {
2067 		_set_invalid_parameter_handler(old_invalid_parameter_handler);
2068 	}
2069 
2070 	/* Disable the message box for assertions.*/
2071 	_CrtSetReportMode(_CRT_ASSERT, 0);
2072 #endif
2073 
2074 #ifdef ZTS
2075 	(void)ts_resource(0);
2076 #endif
2077 
2078 #ifdef PHP_WIN32
2079 	if (!php_win32_init_random_bytes()) {
2080 		fprintf(stderr, "\ncrypt algorithm provider initialization failed\n");
2081 		return FAILURE;
2082 	}
2083 #endif
2084 
2085 	module_shutdown = false;
2086 	module_startup = true;
2087 	sapi_initialize_empty_request();
2088 	sapi_activate();
2089 
2090 	if (module_initialized) {
2091 		return SUCCESS;
2092 	}
2093 
2094 	sapi_module = *sf;
2095 
2096 	php_output_startup();
2097 
2098 #ifdef ZTS
2099 	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);
2100 #ifdef PHP_WIN32
2101 	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);
2102 #endif
2103 #else
2104 	memset(&core_globals, 0, sizeof(core_globals));
2105 	php_startup_ticks();
2106 #endif
2107 	gc_globals_ctor();
2108 
2109 	zuf.error_function = php_error_cb;
2110 	zuf.printf_function = php_printf;
2111 	zuf.write_function = php_output_write;
2112 	zuf.fopen_function = php_fopen_wrapper_for_zend;
2113 	zuf.message_handler = php_message_handler_for_zend;
2114 	zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
2115 	zuf.ticks_function = php_run_ticks;
2116 	zuf.on_timeout = php_on_timeout;
2117 	zuf.stream_open_function = php_stream_open_for_zend;
2118 	zuf.printf_to_smart_string_function = php_printf_to_smart_string;
2119 	zuf.printf_to_smart_str_function = php_printf_to_smart_str;
2120 	zuf.getenv_function = sapi_getenv;
2121 	zuf.resolve_path_function = php_resolve_path_for_zend;
2122 	zend_startup(&zuf);
2123 	zend_reset_lc_ctype_locale();
2124 	zend_update_current_locale();
2125 
2126 	zend_observer_startup();
2127 #if ZEND_DEBUG
2128 	zend_observer_error_register(report_zend_debug_error_notify_cb);
2129 #endif
2130 
2131 #if HAVE_TZSET
2132 	tzset();
2133 #endif
2134 
2135 #ifdef PHP_WIN32
2136 	char *img_err;
2137 	if (!php_win32_crt_compatible(&img_err)) {
2138 		php_error(E_CORE_WARNING, img_err);
2139 		efree(img_err);
2140 		return FAILURE;
2141 	}
2142 
2143 	/* start up winsock services */
2144 	if (WSAStartup(wVersionRequested, &wsaData) != 0) {
2145 		fprintf(stderr, "\nwinsock.dll unusable. %d\n", WSAGetLastError());
2146 		return FAILURE;
2147 	}
2148 	php_win32_signal_ctrl_handler_init();
2149 #endif
2150 
2151 	le_index_ptr = zend_register_list_destructors_ex(NULL, NULL, "index pointer", 0);
2152 
2153 	php_binary_init();
2154 	register_main_symbols(module_number);
2155 
2156 	/* this will read in php.ini, set up the configuration parameters,
2157 	   load zend extensions and register php function extensions
2158 	   to be loaded later */
2159 	zend_stream_init();
2160 	if (php_init_config() == FAILURE) {
2161 		return FAILURE;
2162 	}
2163 	zend_stream_shutdown();
2164 
2165 	/* Register PHP core ini entries */
2166 	zend_register_ini_entries_ex(ini_entries, module_number, MODULE_PERSISTENT);
2167 
2168 	/* Register Zend ini entries */
2169 	zend_register_standard_ini_entries();
2170 
2171 #ifdef ZEND_WIN32
2172 	/* Until the current ini values was setup, the current cp is 65001.
2173 		If the actual ini values are different, some stuff needs to be updated.
2174 		It concerns at least main_cwd_state and there might be more. As we're
2175 		still in the startup phase, lets use the chance and reinit the relevant
2176 		item according to the current codepage. Still, if ini_set() is used
2177 		later on, a more intelligent way to update such stuff is needed.
2178 		Startup/shutdown routines could involve touching globals and thus
2179 		can't always be used on demand. */
2180 	if (!php_win32_cp_use_unicode()) {
2181 		virtual_cwd_main_cwd_init(1);
2182 	}
2183 #endif
2184 
2185 	/* Disable realpath cache if an open_basedir is set */
2186 	if (PG(open_basedir) && *PG(open_basedir)) {
2187 		CWDG(realpath_cache_size_limit) = 0;
2188 	}
2189 
2190 	PG(have_called_openlog) = 0;
2191 
2192 	/* initialize stream wrappers registry
2193 	 * (this uses configuration parameters from php.ini)
2194 	 */
2195 	if (php_init_stream_wrappers(module_number) == FAILURE)	{
2196 		fprintf(stderr, "PHP:  Unable to initialize stream url wrappers.\n");
2197 		return FAILURE;
2198 	}
2199 
2200 	zuv.html_errors = 1;
2201 	php_startup_auto_globals();
2202 	zend_set_utility_values(&zuv);
2203 	php_startup_sapi_content_types();
2204 
2205 	/* Begin to fingerprint the process state */
2206 	zend_startup_system_id();
2207 
2208 	/* startup extensions statically compiled in */
2209 	if (php_register_internal_extensions_func() == FAILURE) {
2210 		fprintf(stderr, "Unable to start builtin modules\n");
2211 		return FAILURE;
2212 	}
2213 
2214 	/* start additional PHP extensions */
2215 	if (additional_module && (zend_register_internal_module(additional_module) == NULL)) {
2216 		return FAILURE;
2217 	}
2218 
2219 	/* load and startup extensions compiled as shared objects (aka DLLs)
2220 	   as requested by php.ini entries
2221 	   these are loaded after initialization of internal extensions
2222 	   as extensions *might* rely on things from ext/standard
2223 	   which is always an internal extension and to be initialized
2224 	   ahead of all other internals
2225 	 */
2226 	php_ini_register_extensions();
2227 	zend_startup_modules();
2228 
2229 	/* start Zend extensions */
2230 	zend_startup_extensions();
2231 
2232 	zend_collect_module_handlers();
2233 
2234 	/* register additional functions */
2235 	if (sapi_module.additional_functions) {
2236 		if ((module = zend_hash_str_find_ptr(&module_registry, "standard", sizeof("standard")-1)) != NULL) {
2237 			EG(current_module) = module;
2238 			zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT);
2239 			EG(current_module) = NULL;
2240 		}
2241 	}
2242 
2243 	/* disable certain classes and functions as requested by php.ini */
2244 	zend_disable_functions(INI_STR("disable_functions"));
2245 	php_disable_classes();
2246 
2247 	/* make core report what it should */
2248 	if ((module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core")-1)) != NULL) {
2249 		module->version = PHP_VERSION;
2250 		module->info_func = PHP_MINFO(php_core);
2251 	}
2252 
2253 	/* freeze the list of observer fcall_init handlers */
2254 	zend_observer_post_startup();
2255 
2256 	/* Extensions that add engine hooks after this point do so at their own peril */
2257 	zend_finalize_system_id();
2258 
2259 	module_initialized = true;
2260 
2261 	if (zend_post_startup() != SUCCESS) {
2262 		return FAILURE;
2263 	}
2264 
2265 	/* Check for deprecated directives */
2266 	/* NOTE: If you add anything here, remember to add it to build/Makefile.global! */
2267 	{
2268 		struct {
2269 			const long error_level;
2270 			const char *phrase;
2271 			const char *directives[18]; /* Remember to change this if the number of directives change */
2272 		} directives[2] = {
2273 			{
2274 				E_DEPRECATED,
2275 				"Directive '%s' is deprecated",
2276 				{
2277 					"allow_url_include",
2278 					NULL
2279 				}
2280 			},
2281 			{
2282 				E_CORE_ERROR,
2283 				"Directive '%s' is no longer available in PHP",
2284 				{
2285 					"allow_call_time_pass_reference",
2286 					"asp_tags",
2287 					"define_syslog_variables",
2288 					"highlight.bg",
2289 					"magic_quotes_gpc",
2290 					"magic_quotes_runtime",
2291 					"magic_quotes_sybase",
2292 					"register_globals",
2293 					"register_long_arrays",
2294 					"safe_mode",
2295 					"safe_mode_gid",
2296 					"safe_mode_include_dir",
2297 					"safe_mode_exec_dir",
2298 					"safe_mode_allowed_env_vars",
2299 					"safe_mode_protected_env_vars",
2300 					"zend.ze1_compatibility_mode",
2301 					"track_errors",
2302 					NULL
2303 				}
2304 			}
2305 		};
2306 
2307 		unsigned int i;
2308 
2309 		zend_try {
2310 			/* 2 = Count of deprecation structs */
2311 			for (i = 0; i < 2; i++) {
2312 				const char **p = directives[i].directives;
2313 
2314 				while(*p) {
2315 					zend_long value;
2316 
2317 					if (cfg_get_long((char*)*p, &value) == SUCCESS && value) {
2318 						zend_error(directives[i].error_level, directives[i].phrase, *p);
2319 					}
2320 
2321 					++p;
2322 				}
2323 			}
2324 		} zend_catch {
2325 			retval = FAILURE;
2326 		} zend_end_try();
2327 	}
2328 
2329 	virtual_cwd_deactivate();
2330 
2331 	sapi_deactivate();
2332 	module_startup = false;
2333 
2334 	/* Don't leak errors from startup into the per-request phase. */
2335 	clear_last_error();
2336 	shutdown_memory_manager(1, 0);
2337 	virtual_cwd_activate();
2338 
2339 	zend_interned_strings_switch_storage(1);
2340 
2341 #if ZEND_RC_DEBUG
2342 	if (retval == SUCCESS) {
2343 		zend_rc_debug = 1;
2344 	}
2345 #endif
2346 
2347 	/* we're done */
2348 	return retval;
2349 }
2350 /* }}} */
2351 
2352 /* {{{ php_module_shutdown_wrapper */
php_module_shutdown_wrapper(sapi_module_struct * sapi_globals)2353 int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals)
2354 {
2355 	php_module_shutdown();
2356 	return SUCCESS;
2357 }
2358 /* }}} */
2359 
2360 /* {{{ php_module_shutdown */
php_module_shutdown(void)2361 void php_module_shutdown(void)
2362 {
2363 	int module_number=0;
2364 
2365 	module_shutdown = true;
2366 
2367 	if (!module_initialized) {
2368 		return;
2369 	}
2370 
2371 	zend_interned_strings_switch_storage(0);
2372 
2373 #if ZEND_RC_DEBUG
2374 	zend_rc_debug = 0;
2375 #endif
2376 
2377 #ifdef PHP_WIN32
2378 	(void)php_win32_shutdown_random_bytes();
2379 	php_win32_signal_ctrl_handler_shutdown();
2380 #endif
2381 
2382 	sapi_flush();
2383 
2384 	zend_shutdown();
2385 
2386 #ifdef PHP_WIN32
2387 	/*close winsock */
2388 	WSACleanup();
2389 #endif
2390 
2391 	/* Destroys filter & transport registries too */
2392 	php_shutdown_stream_wrappers(module_number);
2393 
2394 	zend_unregister_ini_entries_ex(module_number, MODULE_PERSISTENT);
2395 
2396 	/* close down the ini config */
2397 	php_shutdown_config();
2398 	clear_last_error();
2399 
2400 #ifndef ZTS
2401 	zend_ini_shutdown();
2402 	shutdown_memory_manager(CG(unclean_shutdown), 1);
2403 #else
2404 	zend_ini_global_shutdown();
2405 #endif
2406 
2407 	php_output_shutdown();
2408 
2409 #ifndef ZTS
2410 	zend_interned_strings_dtor();
2411 #endif
2412 
2413 	if (zend_post_shutdown_cb) {
2414 		void (*cb)(void) = zend_post_shutdown_cb;
2415 
2416 		zend_post_shutdown_cb = NULL;
2417 		cb();
2418 	}
2419 
2420 	module_initialized = false;
2421 
2422 #ifndef ZTS
2423 	core_globals_dtor(&core_globals);
2424 	gc_globals_dtor();
2425 #else
2426 	ts_free_id(core_globals_id);
2427 #endif
2428 
2429 #ifdef PHP_WIN32
2430 	if (old_invalid_parameter_handler == NULL) {
2431 		_set_invalid_parameter_handler(old_invalid_parameter_handler);
2432 	}
2433 #endif
2434 
2435 	zend_observer_shutdown();
2436 }
2437 /* }}} */
2438 
php_execute_script_ex(zend_file_handle * primary_file,zval * retval)2439 PHPAPI bool php_execute_script_ex(zend_file_handle *primary_file, zval *retval)
2440 {
2441 	zend_file_handle *prepend_file_p = NULL, *append_file_p = NULL;
2442 	zend_file_handle prepend_file, append_file;
2443 #ifdef HAVE_BROKEN_GETCWD
2444 	volatile int old_cwd_fd = -1;
2445 #else
2446 	char *old_cwd;
2447 	ALLOCA_FLAG(use_heap)
2448 #endif
2449 	bool result = true;
2450 
2451 #ifndef HAVE_BROKEN_GETCWD
2452 # define OLD_CWD_SIZE 4096
2453 	old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
2454 	old_cwd[0] = '\0';
2455 #endif
2456 
2457 	zend_try {
2458 		char realfile[MAXPATHLEN];
2459 
2460 #ifdef PHP_WIN32
2461 		if(primary_file->filename) {
2462 			UpdateIniFromRegistry(ZSTR_VAL(primary_file->filename));
2463 		}
2464 #endif
2465 
2466 		PG(during_request_startup) = 0;
2467 
2468 		if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
2469 #ifdef HAVE_BROKEN_GETCWD
2470 			/* this looks nasty to me */
2471 			old_cwd_fd = open(".", 0);
2472 #else
2473 			php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
2474 #endif
2475 			VCWD_CHDIR_FILE(ZSTR_VAL(primary_file->filename));
2476 		}
2477 
2478 		/* Only lookup the real file path and add it to the included_files list if already opened
2479 		 *   otherwise it will get opened and added to the included_files list in zend_execute_scripts
2480 		 */
2481 		if (primary_file->filename &&
2482 			!zend_string_equals_literal(primary_file->filename, "Standard input code") &&
2483 			primary_file->opened_path == NULL &&
2484 			primary_file->type != ZEND_HANDLE_FILENAME
2485 		) {
2486 			if (expand_filepath(ZSTR_VAL(primary_file->filename), realfile)) {
2487 				primary_file->opened_path = zend_string_init(realfile, strlen(realfile), 0);
2488 				zend_hash_add_empty_element(&EG(included_files), primary_file->opened_path);
2489 			}
2490 		}
2491 
2492 		if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
2493 			zend_stream_init_filename(&prepend_file, PG(auto_prepend_file));
2494 			prepend_file_p = &prepend_file;
2495 		}
2496 
2497 		if (PG(auto_append_file) && PG(auto_append_file)[0]) {
2498 			zend_stream_init_filename(&append_file, PG(auto_append_file));
2499 			append_file_p = &append_file;
2500 		}
2501 		if (PG(max_input_time) != -1) {
2502 #ifdef PHP_WIN32
2503 			zend_unset_timeout();
2504 #endif
2505 			zend_set_timeout(INI_INT("max_execution_time"), 0);
2506 		}
2507 
2508 		if (prepend_file_p && result) {
2509 			result = zend_execute_script(ZEND_REQUIRE, NULL, prepend_file_p) == SUCCESS;
2510 		}
2511 		if (result) {
2512 			result = zend_execute_script(ZEND_REQUIRE, retval, primary_file) == SUCCESS;
2513 		}
2514 		if (append_file_p && result) {
2515 			result = zend_execute_script(ZEND_REQUIRE, NULL, append_file_p) == SUCCESS;
2516 		}
2517 	} zend_catch {
2518 		result = false;
2519 	} zend_end_try();
2520 
2521 	if (prepend_file_p) {
2522 		zend_destroy_file_handle(prepend_file_p);
2523 	}
2524 
2525 	if (append_file_p) {
2526 		zend_destroy_file_handle(append_file_p);
2527 	}
2528 
2529 	if (EG(exception)) {
2530 		zend_try {
2531 			zend_exception_error(EG(exception), E_ERROR);
2532 		} zend_end_try();
2533 	}
2534 
2535 #ifdef HAVE_BROKEN_GETCWD
2536 	if (old_cwd_fd != -1) {
2537 		fchdir(old_cwd_fd);
2538 		close(old_cwd_fd);
2539 	}
2540 #else
2541 	if (old_cwd[0] != '\0') {
2542 		php_ignore_value(VCWD_CHDIR(old_cwd));
2543 	}
2544 	free_alloca(old_cwd, use_heap);
2545 #endif
2546 	return result;
2547 }
2548 
2549 /* {{{ php_execute_script */
php_execute_script(zend_file_handle * primary_file)2550 PHPAPI bool php_execute_script(zend_file_handle *primary_file)
2551 {
2552 	return php_execute_script_ex(primary_file, NULL);
2553 }
2554 /* }}} */
2555 
2556 /* {{{ php_execute_simple_script */
php_execute_simple_script(zend_file_handle * primary_file,zval * ret)2557 PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval *ret)
2558 {
2559 	char *old_cwd;
2560 	ALLOCA_FLAG(use_heap)
2561 
2562 	EG(exit_status) = 0;
2563 #define OLD_CWD_SIZE 4096
2564 	old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
2565 	old_cwd[0] = '\0';
2566 
2567 	zend_try {
2568 #ifdef PHP_WIN32
2569 		if(primary_file->filename) {
2570 			UpdateIniFromRegistry(ZSTR_VAL(primary_file->filename));
2571 		}
2572 #endif
2573 
2574 		PG(during_request_startup) = 0;
2575 
2576 		if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
2577 			php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
2578 			VCWD_CHDIR_FILE(ZSTR_VAL(primary_file->filename));
2579 		}
2580 		zend_execute_scripts(ZEND_REQUIRE, ret, 1, primary_file);
2581 	} zend_end_try();
2582 
2583 	if (old_cwd[0] != '\0') {
2584 		php_ignore_value(VCWD_CHDIR(old_cwd));
2585 	}
2586 
2587 	free_alloca(old_cwd, use_heap);
2588 	return EG(exit_status);
2589 }
2590 /* }}} */
2591 
2592 /* {{{ php_handle_aborted_connection */
php_handle_aborted_connection(void)2593 PHPAPI void php_handle_aborted_connection(void)
2594 {
2595 
2596 	PG(connection_status) = PHP_CONNECTION_ABORTED;
2597 	php_output_set_status(PHP_OUTPUT_DISABLED);
2598 
2599 	if (!PG(ignore_user_abort)) {
2600 		zend_bailout();
2601 	}
2602 }
2603 /* }}} */
2604 
2605 /* {{{ php_handle_auth_data */
php_handle_auth_data(const char * auth)2606 PHPAPI int php_handle_auth_data(const char *auth)
2607 {
2608 	int ret = -1;
2609 	size_t auth_len = auth != NULL ? strlen(auth) : 0;
2610 
2611 	if (auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Basic ", sizeof("Basic ")-1, sizeof("Basic ")-1) == 0) {
2612 		char *pass;
2613 		zend_string *user;
2614 
2615 		user = php_base64_decode((const unsigned char*)auth + 6, auth_len - 6);
2616 		if (user) {
2617 			pass = strchr(ZSTR_VAL(user), ':');
2618 			if (pass) {
2619 				*pass++ = '\0';
2620 				SG(request_info).auth_user = estrndup(ZSTR_VAL(user), ZSTR_LEN(user));
2621 				SG(request_info).auth_password = estrdup(pass);
2622 				ret = 0;
2623 			}
2624 			zend_string_free(user);
2625 		}
2626 	}
2627 
2628 	if (ret == -1) {
2629 		SG(request_info).auth_user = SG(request_info).auth_password = NULL;
2630 	} else {
2631 		SG(request_info).auth_digest = NULL;
2632 	}
2633 
2634 	if (ret == -1 && auth && auth_len > 0 && zend_binary_strncasecmp(auth, auth_len, "Digest ", sizeof("Digest ")-1, sizeof("Digest ")-1) == 0) {
2635 		SG(request_info).auth_digest = estrdup(auth + 7);
2636 		ret = 0;
2637 	}
2638 
2639 	if (ret == -1) {
2640 		SG(request_info).auth_digest = NULL;
2641 	}
2642 
2643 	return ret;
2644 }
2645 /* }}} */
2646 
2647 /* {{{ php_lint_script */
php_lint_script(zend_file_handle * file)2648 PHPAPI zend_result php_lint_script(zend_file_handle *file)
2649 {
2650 	zend_op_array *op_array;
2651 	zend_result retval = FAILURE;
2652 
2653 	zend_try {
2654 		op_array = zend_compile_file(file, ZEND_INCLUDE);
2655 
2656 		if (op_array) {
2657 			destroy_op_array(op_array);
2658 			efree(op_array);
2659 			retval = SUCCESS;
2660 		}
2661 	} zend_end_try();
2662 	if (EG(exception)) {
2663 		zend_exception_error(EG(exception), E_ERROR);
2664 	}
2665 
2666 	return retval;
2667 }
2668 /* }}} */
2669 
2670 #ifdef ZTS
2671 /* {{{ php_reserve_tsrm_memory */
php_reserve_tsrm_memory(void)2672 PHPAPI void php_reserve_tsrm_memory(void)
2673 {
2674 	tsrm_reserve(
2675 		TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
2676 		TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)) +
2677 		TSRM_ALIGNED_SIZE(sizeof(zend_php_scanner_globals)) +
2678 		TSRM_ALIGNED_SIZE(sizeof(zend_ini_scanner_globals)) +
2679 		TSRM_ALIGNED_SIZE(sizeof(virtual_cwd_globals)) +
2680 #ifdef ZEND_SIGNALS
2681 		TSRM_ALIGNED_SIZE(sizeof(zend_signal_globals_t)) +
2682 #endif
2683 		TSRM_ALIGNED_SIZE(zend_mm_globals_size()) +
2684 		TSRM_ALIGNED_SIZE(zend_gc_globals_size()) +
2685 		TSRM_ALIGNED_SIZE(sizeof(php_core_globals)) +
2686 		TSRM_ALIGNED_SIZE(sizeof(sapi_globals_struct))
2687 	);
2688 }
2689 /* }}} */
2690 
php_tsrm_startup_ex(int expected_threads)2691 PHPAPI bool php_tsrm_startup_ex(int expected_threads)
2692 {
2693 	bool ret = tsrm_startup(expected_threads, 1, 0, NULL);
2694 	php_reserve_tsrm_memory();
2695 	(void)ts_resource(0);
2696 	return ret;
2697 }
2698 
2699 /* {{{ php_tsrm_startup */
php_tsrm_startup(void)2700 PHPAPI bool php_tsrm_startup(void)
2701 {
2702 	return php_tsrm_startup_ex(1);
2703 }
2704 /* }}} */
2705 #endif
2706