xref: /PHP-8.2/ext/standard/basic_functions.c (revision 0faa1d20)
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    |          Zeev Suraski <zeev@php.net>                                 |
15    +----------------------------------------------------------------------+
16  */
17 
18 #include "php.h"
19 #include "php_streams.h"
20 #include "php_main.h"
21 #include "php_globals.h"
22 #include "php_variables.h"
23 #include "php_ini.h"
24 #include "php_image.h"
25 #include "php_standard.h"
26 #include "php_math.h"
27 #include "php_http.h"
28 #include "php_incomplete_class.h"
29 #include "php_getopt.h"
30 #include "php_ext_syslog.h"
31 #include "ext/standard/info.h"
32 #include "ext/session/php_session.h"
33 #include "zend_exceptions.h"
34 #include "zend_attributes.h"
35 #include "zend_ini.h"
36 #include "zend_operators.h"
37 #include "ext/standard/php_dns.h"
38 #include "ext/standard/php_uuencode.h"
39 #include "ext/standard/crc32_x86.h"
40 
41 #ifdef PHP_WIN32
42 #include "win32/php_win32_globals.h"
43 #include "win32/time.h"
44 #include "win32/ioutil.h"
45 #endif
46 
47 typedef struct yy_buffer_state *YY_BUFFER_STATE;
48 
49 #include "zend.h"
50 #include "zend_ini_scanner.h"
51 #include "zend_language_scanner.h"
52 #include <zend_language_parser.h>
53 
54 #include "zend_portability.h"
55 
56 #include <stdarg.h>
57 #include <stdlib.h>
58 #include <math.h>
59 #include <time.h>
60 #include <stdio.h>
61 
62 #ifndef PHP_WIN32
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #endif
66 
67 #ifndef PHP_WIN32
68 # include <netdb.h>
69 #else
70 #include "win32/inet.h"
71 #endif
72 
73 #ifdef HAVE_ARPA_INET_H
74 # include <arpa/inet.h>
75 #endif
76 
77 #ifdef HAVE_UNISTD_H
78 # include <unistd.h>
79 #endif
80 
81 #include <string.h>
82 #include <locale.h>
83 
84 #ifdef HAVE_SYS_MMAN_H
85 # include <sys/mman.h>
86 #endif
87 
88 #ifdef HAVE_SYS_LOADAVG_H
89 # include <sys/loadavg.h>
90 #endif
91 
92 #ifdef PHP_WIN32
93 # include "win32/unistd.h"
94 #endif
95 
96 #ifndef INADDR_NONE
97 # define INADDR_NONE ((zend_ulong) -1)
98 #endif
99 
100 #include "zend_globals.h"
101 #include "php_globals.h"
102 #include "SAPI.h"
103 #include "php_ticks.h"
104 
105 #ifdef ZTS
106 PHPAPI int basic_globals_id;
107 #else
108 PHPAPI php_basic_globals basic_globals;
109 #endif
110 
111 #include "php_fopen_wrappers.h"
112 #include "streamsfuncs.h"
113 #include "basic_functions_arginfo.h"
114 
115 #if __has_feature(memory_sanitizer)
116 # include <sanitizer/msan_interface.h>
117 #endif
118 
119 typedef struct _user_tick_function_entry {
120 	zend_fcall_info fci;
121 	zend_fcall_info_cache fci_cache;
122 	bool calling;
123 } user_tick_function_entry;
124 
125 #if HAVE_PUTENV
126 typedef struct {
127 	char *putenv_string;
128 	char *previous_value;
129 	zend_string *key;
130 } putenv_entry;
131 #endif
132 
133 /* some prototypes for local functions */
134 static void user_shutdown_function_dtor(zval *zv);
135 static void user_tick_function_dtor(user_tick_function_entry *tick_function_entry);
136 
137 static const zend_module_dep standard_deps[] = { /* {{{ */
138 	ZEND_MOD_OPTIONAL("session")
139 	ZEND_MOD_END
140 };
141 /* }}} */
142 
143 zend_module_entry basic_functions_module = { /* {{{ */
144 	STANDARD_MODULE_HEADER_EX,
145 	NULL,
146 	standard_deps,
147 	"standard",					/* extension name */
148 	ext_functions,				/* function list */
149 	PHP_MINIT(basic),			/* process startup */
150 	PHP_MSHUTDOWN(basic),		/* process shutdown */
151 	PHP_RINIT(basic),			/* request startup */
152 	PHP_RSHUTDOWN(basic),		/* request shutdown */
153 	PHP_MINFO(basic),			/* extension info */
154 	PHP_STANDARD_VERSION,		/* extension version */
155 	STANDARD_MODULE_PROPERTIES
156 };
157 /* }}} */
158 
159 #ifdef HAVE_PUTENV
php_putenv_destructor(zval * zv)160 static void php_putenv_destructor(zval *zv) /* {{{ */
161 {
162 	putenv_entry *pe = Z_PTR_P(zv);
163 
164 	if (pe->previous_value) {
165 # ifdef PHP_WIN32
166 		/* MSVCRT has a bug in putenv() when setting a variable that
167 		 * is already set; if the SetEnvironmentVariable() API call
168 		 * fails, the Crt will double free() a string.
169 		 * We try to avoid this by setting our own value first */
170 		SetEnvironmentVariable(ZSTR_VAL(pe->key), "bugbug");
171 # endif
172 		putenv(pe->previous_value);
173 # ifdef PHP_WIN32
174 		efree(pe->previous_value);
175 # endif
176 	} else {
177 # ifdef HAVE_UNSETENV
178 		unsetenv(ZSTR_VAL(pe->key));
179 # elif defined(PHP_WIN32)
180 		SetEnvironmentVariable(ZSTR_VAL(pe->key), NULL);
181 # ifndef ZTS
182 		_putenv_s(ZSTR_VAL(pe->key), "");
183 # endif
184 # else
185 		char **env;
186 
187 		for (env = environ; env != NULL && *env != NULL; env++) {
188 			if (!strncmp(*env, ZSTR_VAL(pe->key), ZSTR_LEN(pe->key))
189 					&& (*env)[ZSTR_LEN(pe->key)] == '=') {	/* found it */
190 				*env = "";
191 				break;
192 			}
193 		}
194 # endif
195 	}
196 #ifdef HAVE_TZSET
197 	/* don't forget to reset the various libc globals that
198 	 * we might have changed by an earlier call to tzset(). */
199 	if (zend_string_equals_literal_ci(pe->key, "TZ")) {
200 		tzset();
201 	}
202 #endif
203 
204 	free(pe->putenv_string);
205 	zend_string_release(pe->key);
206 	efree(pe);
207 }
208 /* }}} */
209 #endif
210 
basic_globals_ctor(php_basic_globals * basic_globals_p)211 static void basic_globals_ctor(php_basic_globals *basic_globals_p) /* {{{ */
212 {
213 	BG(umask) = -1;
214 	BG(user_tick_functions) = NULL;
215 	BG(user_filter_map) = NULL;
216 	BG(serialize_lock) = 0;
217 
218 	memset(&BG(serialize), 0, sizeof(BG(serialize)));
219 	memset(&BG(unserialize), 0, sizeof(BG(unserialize)));
220 
221 	memset(&BG(url_adapt_session_ex), 0, sizeof(BG(url_adapt_session_ex)));
222 	memset(&BG(url_adapt_output_ex), 0, sizeof(BG(url_adapt_output_ex)));
223 
224 	BG(url_adapt_session_ex).type = 1;
225 	BG(url_adapt_output_ex).type  = 0;
226 
227 	zend_hash_init(&BG(url_adapt_session_hosts_ht), 0, NULL, NULL, 1);
228 	zend_hash_init(&BG(url_adapt_output_hosts_ht), 0, NULL, NULL, 1);
229 
230 #if defined(_REENTRANT)
231 	memset(&BG(mblen_state), 0, sizeof(BG(mblen_state)));
232 #endif
233 
234 	BG(page_uid) = -1;
235 	BG(page_gid) = -1;
236 
237 	BG(syslog_device) = NULL;
238 }
239 /* }}} */
240 
basic_globals_dtor(php_basic_globals * basic_globals_p)241 static void basic_globals_dtor(php_basic_globals *basic_globals_p) /* {{{ */
242 {
243 	if (basic_globals_p->url_adapt_session_ex.tags) {
244 		zend_hash_destroy(basic_globals_p->url_adapt_session_ex.tags);
245 		free(basic_globals_p->url_adapt_session_ex.tags);
246 	}
247 	if (basic_globals_p->url_adapt_output_ex.tags) {
248 		zend_hash_destroy(basic_globals_p->url_adapt_output_ex.tags);
249 		free(basic_globals_p->url_adapt_output_ex.tags);
250 	}
251 
252 	zend_hash_destroy(&basic_globals_p->url_adapt_session_hosts_ht);
253 	zend_hash_destroy(&basic_globals_p->url_adapt_output_hosts_ht);
254 }
255 /* }}} */
256 
php_get_nan(void)257 PHPAPI double php_get_nan(void) /* {{{ */
258 {
259 	return ZEND_NAN;
260 }
261 /* }}} */
262 
php_get_inf(void)263 PHPAPI double php_get_inf(void) /* {{{ */
264 {
265 	return ZEND_INFINITY;
266 }
267 /* }}} */
268 
269 #define BASIC_MINIT_SUBMODULE(module) \
270 	if (PHP_MINIT(module)(INIT_FUNC_ARGS_PASSTHRU) != SUCCESS) {\
271 		return FAILURE; \
272 	}
273 
274 #define BASIC_RINIT_SUBMODULE(module) \
275 	PHP_RINIT(module)(INIT_FUNC_ARGS_PASSTHRU);
276 
277 #define BASIC_MINFO_SUBMODULE(module) \
278 	PHP_MINFO(module)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
279 
280 #define BASIC_RSHUTDOWN_SUBMODULE(module) \
281 	PHP_RSHUTDOWN(module)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
282 
283 #define BASIC_MSHUTDOWN_SUBMODULE(module) \
284 	PHP_MSHUTDOWN(module)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
285 
PHP_MINIT_FUNCTION(basic)286 PHP_MINIT_FUNCTION(basic) /* {{{ */
287 {
288 #ifdef ZTS
289 	ts_allocate_id(&basic_globals_id, sizeof(php_basic_globals), (ts_allocate_ctor) basic_globals_ctor, (ts_allocate_dtor) basic_globals_dtor);
290 # ifdef PHP_WIN32
291 	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 );
292 # endif
293 #else
294 	basic_globals_ctor(&basic_globals);
295 # ifdef PHP_WIN32
296 	php_win32_core_globals_ctor(&the_php_win32_core_globals);
297 # endif
298 #endif
299 
300 	register_basic_functions_symbols(module_number);
301 
302 	php_ce_incomplete_class = register_class___PHP_Incomplete_Class();
303 	php_register_incomplete_class_handlers();
304 
305 	assertion_error_ce = register_class_AssertionError(zend_ce_error);
306 
307 #ifdef ENABLE_TEST_CLASS
308 	test_class_startup();
309 #endif
310 
311 	register_phpinfo_constants(INIT_FUNC_ARGS_PASSTHRU);
312 	register_html_constants(INIT_FUNC_ARGS_PASSTHRU);
313 
314 	BASIC_MINIT_SUBMODULE(var)
315 	BASIC_MINIT_SUBMODULE(file)
316 	BASIC_MINIT_SUBMODULE(pack)
317 	BASIC_MINIT_SUBMODULE(browscap)
318 	BASIC_MINIT_SUBMODULE(standard_filters)
319 	BASIC_MINIT_SUBMODULE(user_filters)
320 	BASIC_MINIT_SUBMODULE(password)
321 
322 #ifdef ZTS
323 	BASIC_MINIT_SUBMODULE(localeconv)
324 #endif
325 
326 #ifdef HAVE_NL_LANGINFO
327 	BASIC_MINIT_SUBMODULE(nl_langinfo)
328 #endif
329 
330 #ifdef ZEND_INTRIN_SSE4_2_FUNC_PTR
331 	BASIC_MINIT_SUBMODULE(string_intrin)
332 #endif
333 
334 #ifdef ZEND_INTRIN_SSE4_2_PCLMUL_FUNC_PTR
335 	BASIC_MINIT_SUBMODULE(crc32_x86_intrin)
336 #endif
337 
338 #if defined(ZEND_INTRIN_AVX2_FUNC_PTR) || defined(ZEND_INTRIN_SSSE3_FUNC_PTR)
339 	BASIC_MINIT_SUBMODULE(base64_intrin)
340 #endif
341 
342 	BASIC_MINIT_SUBMODULE(crypt)
343 
344 	BASIC_MINIT_SUBMODULE(dir)
345 #ifdef HAVE_SYSLOG_H
346 	BASIC_MINIT_SUBMODULE(syslog)
347 #endif
348 	BASIC_MINIT_SUBMODULE(array)
349 	BASIC_MINIT_SUBMODULE(assert)
350 	BASIC_MINIT_SUBMODULE(url_scanner_ex)
351 #ifdef PHP_CAN_SUPPORT_PROC_OPEN
352 	BASIC_MINIT_SUBMODULE(proc_open)
353 #endif
354 	BASIC_MINIT_SUBMODULE(exec)
355 
356 	BASIC_MINIT_SUBMODULE(user_streams)
357 
358 	php_register_url_stream_wrapper("php", &php_stream_php_wrapper);
359 	php_register_url_stream_wrapper("file", &php_plain_files_wrapper);
360 #ifdef HAVE_GLOB
361 	php_register_url_stream_wrapper("glob", &php_glob_stream_wrapper);
362 #endif
363 	php_register_url_stream_wrapper("data", &php_stream_rfc2397_wrapper);
364 	php_register_url_stream_wrapper("http", &php_stream_http_wrapper);
365 	php_register_url_stream_wrapper("ftp", &php_stream_ftp_wrapper);
366 
367 	BASIC_MINIT_SUBMODULE(hrtime)
368 
369 	return SUCCESS;
370 }
371 /* }}} */
372 
PHP_MSHUTDOWN_FUNCTION(basic)373 PHP_MSHUTDOWN_FUNCTION(basic) /* {{{ */
374 {
375 #ifdef ZTS
376 	ts_free_id(basic_globals_id);
377 #ifdef PHP_WIN32
378 	ts_free_id(php_win32_core_globals_id);
379 #endif
380 #else
381 	basic_globals_dtor(&basic_globals);
382 #ifdef PHP_WIN32
383 	php_win32_core_globals_dtor(&the_php_win32_core_globals);
384 #endif
385 #endif
386 
387 	php_unregister_url_stream_wrapper("php");
388 	php_unregister_url_stream_wrapper("http");
389 	php_unregister_url_stream_wrapper("ftp");
390 
391 	BASIC_MSHUTDOWN_SUBMODULE(browscap)
392 	BASIC_MSHUTDOWN_SUBMODULE(array)
393 	BASIC_MSHUTDOWN_SUBMODULE(assert)
394 	BASIC_MSHUTDOWN_SUBMODULE(url_scanner_ex)
395 	BASIC_MSHUTDOWN_SUBMODULE(file)
396 	BASIC_MSHUTDOWN_SUBMODULE(standard_filters)
397 #ifdef ZTS
398 	BASIC_MSHUTDOWN_SUBMODULE(localeconv)
399 #endif
400 	BASIC_MSHUTDOWN_SUBMODULE(crypt)
401 	BASIC_MSHUTDOWN_SUBMODULE(password)
402 
403 	return SUCCESS;
404 }
405 /* }}} */
406 
PHP_RINIT_FUNCTION(basic)407 PHP_RINIT_FUNCTION(basic) /* {{{ */
408 {
409 	memset(BG(strtok_table), 0, 256);
410 
411 	BG(serialize_lock) = 0;
412 	memset(&BG(serialize), 0, sizeof(BG(serialize)));
413 	memset(&BG(unserialize), 0, sizeof(BG(unserialize)));
414 
415 	BG(strtok_string) = NULL;
416 	BG(strtok_last) = NULL;
417 	BG(ctype_string) = NULL;
418 	BG(locale_changed) = 0;
419 	BG(user_compare_fci) = empty_fcall_info;
420 	BG(user_compare_fci_cache) = empty_fcall_info_cache;
421 	BG(page_uid) = -1;
422 	BG(page_gid) = -1;
423 	BG(page_inode) = -1;
424 	BG(page_mtime) = -1;
425 #ifdef HAVE_PUTENV
426 	zend_hash_init(&BG(putenv_ht), 1, NULL, php_putenv_destructor, 0);
427 #endif
428 	BG(user_shutdown_function_names) = NULL;
429 
430 	PHP_RINIT(filestat)(INIT_FUNC_ARGS_PASSTHRU);
431 	BASIC_RINIT_SUBMODULE(dir)
432 	BASIC_RINIT_SUBMODULE(url_scanner_ex)
433 
434 	/* Setup default context */
435 	FG(default_context) = NULL;
436 
437 	/* Default to global wrappers only */
438 	FG(stream_wrappers) = NULL;
439 
440 	/* Default to global filters only */
441 	FG(stream_filters) = NULL;
442 
443 	return SUCCESS;
444 }
445 /* }}} */
446 
PHP_RSHUTDOWN_FUNCTION(basic)447 PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */
448 {
449 	if (BG(strtok_string)) {
450 		zend_string_release(BG(strtok_string));
451 		BG(strtok_string) = NULL;
452 	}
453 #ifdef HAVE_PUTENV
454 	tsrm_env_lock();
455 	zend_hash_destroy(&BG(putenv_ht));
456 	tsrm_env_unlock();
457 #endif
458 
459 	if (BG(umask) != -1) {
460 		umask(BG(umask));
461 	}
462 
463 	/* Check if locale was changed and change it back
464 	 * to the value in startup environment */
465 	if (BG(locale_changed)) {
466 		setlocale(LC_ALL, "C");
467 		zend_reset_lc_ctype_locale();
468 		zend_update_current_locale();
469 		if (BG(ctype_string)) {
470 			zend_string_release_ex(BG(ctype_string), 0);
471 			BG(ctype_string) = NULL;
472 		}
473 	}
474 
475 	/* FG(stream_wrappers) and FG(stream_filters) are destroyed
476 	 * during php_request_shutdown() */
477 
478 	PHP_RSHUTDOWN(filestat)(SHUTDOWN_FUNC_ARGS_PASSTHRU);
479 #ifdef HAVE_SYSLOG_H
480 	BASIC_RSHUTDOWN_SUBMODULE(syslog);
481 #endif
482 	BASIC_RSHUTDOWN_SUBMODULE(assert)
483 	BASIC_RSHUTDOWN_SUBMODULE(url_scanner_ex)
484 	BASIC_RSHUTDOWN_SUBMODULE(streams)
485 #ifdef PHP_WIN32
486 	BASIC_RSHUTDOWN_SUBMODULE(win32_core_globals)
487 #endif
488 
489 	if (BG(user_tick_functions)) {
490 		zend_llist_destroy(BG(user_tick_functions));
491 		efree(BG(user_tick_functions));
492 		BG(user_tick_functions) = NULL;
493 	}
494 
495 	BASIC_RSHUTDOWN_SUBMODULE(user_filters)
496 	BASIC_RSHUTDOWN_SUBMODULE(browscap)
497 
498 	BG(page_uid) = -1;
499 	BG(page_gid) = -1;
500 	return SUCCESS;
501 }
502 /* }}} */
503 
PHP_MINFO_FUNCTION(basic)504 PHP_MINFO_FUNCTION(basic) /* {{{ */
505 {
506 	php_info_print_table_start();
507 	BASIC_MINFO_SUBMODULE(dl)
508 	BASIC_MINFO_SUBMODULE(mail)
509 	php_info_print_table_end();
510 	BASIC_MINFO_SUBMODULE(assert)
511 }
512 /* }}} */
513 
514 /* {{{ Given the name of a constant this function will return the constant's associated value */
PHP_FUNCTION(constant)515 PHP_FUNCTION(constant)
516 {
517 	zend_string *const_name;
518 	zval *c;
519 	zend_class_entry *scope;
520 
521 	ZEND_PARSE_PARAMETERS_START(1, 1)
522 		Z_PARAM_STR(const_name)
523 	ZEND_PARSE_PARAMETERS_END();
524 
525 	scope = zend_get_executed_scope();
526 	c = zend_get_constant_ex(const_name, scope, ZEND_FETCH_CLASS_EXCEPTION);
527 	if (!c) {
528 		RETURN_THROWS();
529 	}
530 
531 	ZVAL_COPY_OR_DUP(return_value, c);
532 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
533 		if (UNEXPECTED(zval_update_constant_ex(return_value, scope) != SUCCESS)) {
534 			RETURN_THROWS();
535 		}
536 	}
537 }
538 /* }}} */
539 
540 #ifdef HAVE_INET_NTOP
541 /* {{{ Converts a packed inet address to a human readable IP address string */
PHP_FUNCTION(inet_ntop)542 PHP_FUNCTION(inet_ntop)
543 {
544 	char *address;
545 	size_t address_len;
546 	int af = AF_INET;
547 	char buffer[40];
548 
549 	ZEND_PARSE_PARAMETERS_START(1, 1)
550 		Z_PARAM_STRING(address, address_len)
551 	ZEND_PARSE_PARAMETERS_END();
552 
553 #ifdef HAVE_IPV6
554 	if (address_len == 16) {
555 		af = AF_INET6;
556 	} else
557 #endif
558 	if (address_len != 4) {
559 		RETURN_FALSE;
560 	}
561 
562 	if (!inet_ntop(af, address, buffer, sizeof(buffer))) {
563 		RETURN_FALSE;
564 	}
565 
566 	RETURN_STRING(buffer);
567 }
568 /* }}} */
569 #endif /* HAVE_INET_NTOP */
570 
571 #ifdef HAVE_INET_PTON
572 /* {{{ Converts a human readable IP address to a packed binary string */
PHP_FUNCTION(inet_pton)573 PHP_FUNCTION(inet_pton)
574 {
575 	int ret, af = AF_INET;
576 	char *address;
577 	size_t address_len;
578 	char buffer[17];
579 
580 	ZEND_PARSE_PARAMETERS_START(1, 1)
581 		Z_PARAM_STRING(address, address_len)
582 	ZEND_PARSE_PARAMETERS_END();
583 
584 	memset(buffer, 0, sizeof(buffer));
585 
586 #ifdef HAVE_IPV6
587 	if (strchr(address, ':')) {
588 		af = AF_INET6;
589 	} else
590 #endif
591 	if (!strchr(address, '.')) {
592 		RETURN_FALSE;
593 	}
594 
595 	ret = inet_pton(af, address, buffer);
596 
597 	if (ret <= 0) {
598 		RETURN_FALSE;
599 	}
600 
601 	RETURN_STRINGL(buffer, af == AF_INET ? 4 : 16);
602 }
603 /* }}} */
604 #endif /* HAVE_INET_PTON */
605 
606 /* {{{ Converts a string containing an (IPv4) Internet Protocol dotted address into a proper address */
PHP_FUNCTION(ip2long)607 PHP_FUNCTION(ip2long)
608 {
609 	char *addr;
610 	size_t addr_len;
611 #ifdef HAVE_INET_PTON
612 	struct in_addr ip;
613 #else
614 	zend_ulong ip;
615 #endif
616 
617 	ZEND_PARSE_PARAMETERS_START(1, 1)
618 		Z_PARAM_STRING(addr, addr_len)
619 	ZEND_PARSE_PARAMETERS_END();
620 
621 #ifdef HAVE_INET_PTON
622 	if (addr_len == 0 || inet_pton(AF_INET, addr, &ip) != 1) {
623 		RETURN_FALSE;
624 	}
625 	RETURN_LONG(ntohl(ip.s_addr));
626 #else
627 	if (addr_len == 0 || (ip = inet_addr(addr)) == INADDR_NONE) {
628 		/* The only special case when we should return -1 ourselves,
629 		 * because inet_addr() considers it wrong. We return 0xFFFFFFFF and
630 		 * not -1 or ~0 because of 32/64bit issues. */
631 		if (addr_len == sizeof("255.255.255.255") - 1 &&
632 			!memcmp(addr, "255.255.255.255", sizeof("255.255.255.255") - 1)
633 		) {
634 			RETURN_LONG(0xFFFFFFFF);
635 		}
636 		RETURN_FALSE;
637 	}
638 	RETURN_LONG(ntohl(ip));
639 #endif
640 }
641 /* }}} */
642 
643 /* {{{ Converts an (IPv4) Internet network address into a string in Internet standard dotted format */
PHP_FUNCTION(long2ip)644 PHP_FUNCTION(long2ip)
645 {
646 	zend_ulong ip;
647 	zend_long sip;
648 	struct in_addr myaddr;
649 #ifdef HAVE_INET_PTON
650 	char str[40];
651 #endif
652 
653 	ZEND_PARSE_PARAMETERS_START(1, 1)
654 		Z_PARAM_LONG(sip)
655 	ZEND_PARSE_PARAMETERS_END();
656 
657 	/* autoboxes on 32bit platforms, but that's expected */
658 	ip = (zend_ulong)sip;
659 
660 	myaddr.s_addr = htonl(ip);
661 #ifdef HAVE_INET_PTON
662 	if (inet_ntop(AF_INET, &myaddr, str, sizeof(str))) {
663 		RETURN_STRING(str);
664 	} else {
665 		RETURN_FALSE;
666 	}
667 #else
668 	RETURN_STRING(inet_ntoa(myaddr));
669 #endif
670 }
671 /* }}} */
672 
673 /********************
674  * System Functions *
675  ********************/
676 
php_getenv(const char * str,size_t str_len)677 PHPAPI zend_string *php_getenv(const char *str, size_t str_len) {
678 #ifdef PHP_WIN32
679 	{
680 		wchar_t *keyw = php_win32_cp_conv_any_to_w(str, str_len, PHP_WIN32_CP_IGNORE_LEN_P);
681 		if (!keyw) {
682 			return NULL;
683 		}
684 
685 		SetLastError(0);
686 		/* If the given buffer is not large enough to hold the data, the return value is
687 		 * the buffer size,  in characters, required to hold the string and its terminating
688 		 * null character. We use this return value to alloc the final buffer. */
689 		wchar_t dummybuf;
690 		DWORD size = GetEnvironmentVariableW(keyw, &dummybuf, 0);
691 		if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
692 			/* The environment variable doesn't exist. */
693 			free(keyw);
694 			return NULL;
695 		}
696 
697 		if (size == 0) {
698 			/* env exists, but it is empty */
699 			free(keyw);
700 			return ZSTR_EMPTY_ALLOC();
701 		}
702 
703 		wchar_t *valw = emalloc((size + 1) * sizeof(wchar_t));
704 		size = GetEnvironmentVariableW(keyw, valw, size);
705 		if (size == 0) {
706 			/* has been removed between the two calls */
707 			free(keyw);
708 			efree(valw);
709 			return ZSTR_EMPTY_ALLOC();
710 		} else {
711 			char *ptr = php_win32_cp_w_to_any(valw);
712 			zend_string *result = zend_string_init(ptr, strlen(ptr), 0);
713 			free(ptr);
714 			free(keyw);
715 			efree(valw);
716 			return result;
717 		}
718 	}
719 #else
720 	tsrm_env_lock();
721 
722 	/* system method returns a const */
723 	char *ptr = getenv(str);
724 	zend_string *result = NULL;
725 	if (ptr) {
726 		result = zend_string_init(ptr, strlen(ptr), 0);
727 	}
728 
729 	tsrm_env_unlock();
730 	return result;
731 #endif
732 }
733 
734 /* {{{ Get the value of an environment variable or every available environment variable
735    if no varname is present  */
PHP_FUNCTION(getenv)736 PHP_FUNCTION(getenv)
737 {
738 	char *str = NULL;
739 	size_t str_len;
740 	bool local_only = 0;
741 
742 	ZEND_PARSE_PARAMETERS_START(0, 2)
743 		Z_PARAM_OPTIONAL
744 		Z_PARAM_STRING_OR_NULL(str, str_len)
745 		Z_PARAM_BOOL(local_only)
746 	ZEND_PARSE_PARAMETERS_END();
747 
748 	if (!str) {
749 		array_init(return_value);
750 		php_load_environment_variables(return_value);
751 		return;
752 	}
753 
754 	if (!local_only) {
755 		/* SAPI method returns an emalloc()'d string */
756 		char *ptr = sapi_getenv(str, str_len);
757 		if (ptr) {
758 			// TODO: avoid reallocation ???
759 			RETVAL_STRING(ptr);
760 			efree(ptr);
761 			return;
762 		}
763 	}
764 
765 	zend_string *res = php_getenv(str, str_len);
766 	if (res) {
767 		RETURN_STR(res);
768 	}
769 	RETURN_FALSE;
770 }
771 /* }}} */
772 
773 #ifdef HAVE_PUTENV
774 /* {{{ Set the value of an environment variable */
PHP_FUNCTION(putenv)775 PHP_FUNCTION(putenv)
776 {
777 	char *setting;
778 	size_t setting_len;
779 	char *p, **env;
780 	putenv_entry pe;
781 #ifdef PHP_WIN32
782 	const char *value = NULL;
783 	int error_code;
784 #endif
785 
786 	ZEND_PARSE_PARAMETERS_START(1, 1)
787 		Z_PARAM_STRING(setting, setting_len)
788 	ZEND_PARSE_PARAMETERS_END();
789 
790 	if (setting_len == 0 || setting[0] == '=') {
791 		zend_argument_value_error(1, "must have a valid syntax");
792 		RETURN_THROWS();
793 	}
794 
795 	pe.putenv_string = zend_strndup(setting, setting_len);
796 	if ((p = strchr(setting, '='))) {
797 		pe.key = zend_string_init(setting, p - setting, 0);
798 #ifdef PHP_WIN32
799 		value = p + 1;
800 #endif
801 	} else {
802 		pe.key = zend_string_init(setting, setting_len, 0);
803 	}
804 
805 	tsrm_env_lock();
806 	zend_hash_del(&BG(putenv_ht), pe.key);
807 
808 	/* find previous value */
809 	pe.previous_value = NULL;
810 	for (env = environ; env != NULL && *env != NULL; env++) {
811 		if (!strncmp(*env, ZSTR_VAL(pe.key), ZSTR_LEN(pe.key))
812 				&& (*env)[ZSTR_LEN(pe.key)] == '=') {	/* found it */
813 #ifdef PHP_WIN32
814 			/* must copy previous value because MSVCRT's putenv can free the string without notice */
815 			pe.previous_value = estrdup(*env);
816 #else
817 			pe.previous_value = *env;
818 #endif
819 			break;
820 		}
821 	}
822 
823 #ifdef HAVE_UNSETENV
824 	if (!p) { /* no '=' means we want to unset it */
825 		unsetenv(pe.putenv_string);
826 	}
827 	if (!p || putenv(pe.putenv_string) == 0) { /* success */
828 #else
829 # ifndef PHP_WIN32
830 	if (putenv(pe.putenv_string) == 0) { /* success */
831 # else
832 		wchar_t *keyw, *valw = NULL;
833 
834 		keyw = php_win32_cp_any_to_w(ZSTR_VAL(pe.key));
835 		if (value) {
836 			valw = php_win32_cp_any_to_w(value);
837 		}
838 		/* valw may be NULL, but the failed conversion still needs to be checked. */
839 		if (!keyw || !valw && value) {
840 			tsrm_env_unlock();
841 			free(pe.putenv_string);
842 			zend_string_release(pe.key);
843 			free(keyw);
844 			free(valw);
845 			RETURN_FALSE;
846 		}
847 
848 	error_code = SetEnvironmentVariableW(keyw, valw);
849 
850 	if (error_code != 0
851 # ifndef ZTS
852 	/* We need both SetEnvironmentVariable and _putenv here as some
853 		dependency lib could use either way to read the environment.
854 		Obviously the CRT version will be useful more often. But
855 		generally, doing both brings us on the safe track at least
856 		in NTS build. */
857 	&& _wputenv_s(keyw, valw ? valw : L"") == 0
858 # endif
859 	) { /* success */
860 # endif
861 #endif
862 		zend_hash_add_mem(&BG(putenv_ht), pe.key, &pe, sizeof(putenv_entry));
863 #ifdef HAVE_TZSET
864 		if (zend_string_equals_literal_ci(pe.key, "TZ")) {
865 			tzset();
866 		}
867 #endif
868 		tsrm_env_unlock();
869 #ifdef PHP_WIN32
870 		free(keyw);
871 		free(valw);
872 #endif
873 		RETURN_TRUE;
874 	} else {
875 		free(pe.putenv_string);
876 		zend_string_release(pe.key);
877 #ifdef PHP_WIN32
878 		free(keyw);
879 		free(valw);
880 #endif
881 		RETURN_FALSE;
882 	}
883 }
884 /* }}} */
885 #endif
886 
887 /* {{{ free_argv()
888    Free the memory allocated to an argv array. */
889 static void free_argv(char **argv, int argc)
890 {
891 	int i;
892 
893 	if (argv) {
894 		for (i = 0; i < argc; i++) {
895 			if (argv[i]) {
896 				efree(argv[i]);
897 			}
898 		}
899 		efree(argv);
900 	}
901 }
902 /* }}} */
903 
904 /* {{{ free_longopts()
905    Free the memory allocated to an longopt array. */
906 static void free_longopts(opt_struct *longopts)
907 {
908 	opt_struct *p;
909 
910 	if (longopts) {
911 		for (p = longopts; p && p->opt_char != '-'; p++) {
912 			if (p->opt_name != NULL) {
913 				efree((char *)(p->opt_name));
914 			}
915 		}
916 	}
917 }
918 /* }}} */
919 
920 /* {{{ parse_opts()
921    Convert the typical getopt input characters to the php_getopt struct array */
922 static int parse_opts(char * opts, opt_struct ** result)
923 {
924 	opt_struct * paras = NULL;
925 	unsigned int i, count = 0;
926 	unsigned int opts_len = (unsigned int)strlen(opts);
927 
928 	for (i = 0; i < opts_len; i++) {
929 		if ((opts[i] >= 48 && opts[i] <= 57) ||
930 			(opts[i] >= 65 && opts[i] <= 90) ||
931 			(opts[i] >= 97 && opts[i] <= 122)
932 		) {
933 			count++;
934 		}
935 	}
936 
937 	paras = safe_emalloc(sizeof(opt_struct), count, 0);
938 	memset(paras, 0, sizeof(opt_struct) * count);
939 	*result = paras;
940 	while ( (*opts >= 48 && *opts <= 57) || /* 0 - 9 */
941 			(*opts >= 65 && *opts <= 90) || /* A - Z */
942 			(*opts >= 97 && *opts <= 122)   /* a - z */
943 	) {
944 		paras->opt_char = *opts;
945 		paras->need_param = *(++opts) == ':';
946 		paras->opt_name = NULL;
947 		if (paras->need_param == 1) {
948 			opts++;
949 			if (*opts == ':') {
950 				paras->need_param++;
951 				opts++;
952 			}
953 		}
954 		paras++;
955 	}
956 	return count;
957 }
958 /* }}} */
959 
960 /* {{{ Get options from the command line argument list */
961 PHP_FUNCTION(getopt)
962 {
963 	char *options = NULL, **argv = NULL;
964 	char opt[2] = { '\0' };
965 	char *optname;
966 	int argc = 0, o;
967 	size_t options_len = 0, len;
968 	char *php_optarg = NULL;
969 	int php_optind = 1;
970 	zval val, *args = NULL, *p_longopts = NULL;
971 	zval *zoptind = NULL;
972 	size_t optname_len = 0;
973 	opt_struct *opts, *orig_opts;
974 
975 	ZEND_PARSE_PARAMETERS_START(1, 3)
976 		Z_PARAM_STRING(options, options_len)
977 		Z_PARAM_OPTIONAL
978 		Z_PARAM_ARRAY(p_longopts)
979 		Z_PARAM_ZVAL(zoptind)
980 	ZEND_PARSE_PARAMETERS_END();
981 
982 	/* Init zoptind to 1 */
983 	if (zoptind) {
984 		ZEND_TRY_ASSIGN_REF_LONG(zoptind, 1);
985 	}
986 
987 	/* Get argv from the global symbol table. We calculate argc ourselves
988 	 * in order to be on the safe side, even though it is also available
989 	 * from the symbol table. */
990 	if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) &&
991 		((args = zend_hash_find_ex_ind(Z_ARRVAL_P(&PG(http_globals)[TRACK_VARS_SERVER]), ZSTR_KNOWN(ZEND_STR_ARGV), 1)) != NULL ||
992 		(args = zend_hash_find_ex_ind(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV), 1)) != NULL)
993 	) {
994 		int pos = 0;
995 		zval *entry;
996 
997 		if (Z_TYPE_P(args) != IS_ARRAY) {
998 			RETURN_FALSE;
999 		}
1000 		argc = zend_hash_num_elements(Z_ARRVAL_P(args));
1001 
1002 		/* Attempt to allocate enough memory to hold all of the arguments
1003 		 * and a trailing NULL */
1004 		argv = (char **) safe_emalloc(sizeof(char *), (argc + 1), 0);
1005 
1006 		/* Iterate over the hash to construct the argv array. */
1007 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), entry) {
1008 			zend_string *tmp_arg_str;
1009 			zend_string *arg_str = zval_get_tmp_string(entry, &tmp_arg_str);
1010 
1011 			argv[pos++] = estrdup(ZSTR_VAL(arg_str));
1012 
1013 			zend_tmp_string_release(tmp_arg_str);
1014 		} ZEND_HASH_FOREACH_END();
1015 
1016 		/* The C Standard requires argv[argc] to be NULL - this might
1017 		 * keep some getopt implementations happy. */
1018 		argv[argc] = NULL;
1019 	} else {
1020 		/* Return false if we can't find argv. */
1021 		RETURN_FALSE;
1022 	}
1023 
1024 	len = parse_opts(options, &opts);
1025 
1026 	if (p_longopts) {
1027 		int count;
1028 		zval *entry;
1029 
1030 		count = zend_hash_num_elements(Z_ARRVAL_P(p_longopts));
1031 
1032 		/* the first <len> slots are filled by the one short ops
1033 		 * we now extend our array and jump to the new added structs */
1034 		opts = (opt_struct *) safe_erealloc(opts, sizeof(opt_struct), (len + count + 1), 0);
1035 		orig_opts = opts;
1036 		opts += len;
1037 
1038 		memset(opts, 0, count * sizeof(opt_struct));
1039 
1040 		/* Iterate over the hash to construct the argv array. */
1041 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(p_longopts), entry) {
1042 			zend_string *tmp_arg_str;
1043 			zend_string *arg_str = zval_get_tmp_string(entry, &tmp_arg_str);
1044 
1045 			opts->need_param = 0;
1046 			opts->opt_name = estrdup(ZSTR_VAL(arg_str));
1047 			len = strlen(opts->opt_name);
1048 			if ((len > 0) && (opts->opt_name[len - 1] == ':')) {
1049 				opts->need_param++;
1050 				opts->opt_name[len - 1] = '\0';
1051 				if ((len > 1) && (opts->opt_name[len - 2] == ':')) {
1052 					opts->need_param++;
1053 					opts->opt_name[len - 2] = '\0';
1054 				}
1055 			}
1056 			opts->opt_char = 0;
1057 			opts++;
1058 
1059 			zend_tmp_string_release(tmp_arg_str);
1060 		} ZEND_HASH_FOREACH_END();
1061 	} else {
1062 		opts = (opt_struct*) erealloc(opts, sizeof(opt_struct) * (len + 1));
1063 		orig_opts = opts;
1064 		opts += len;
1065 	}
1066 
1067 	/* php_getopt want to identify the last param */
1068 	opts->opt_char   = '-';
1069 	opts->need_param = 0;
1070 	opts->opt_name   = NULL;
1071 
1072 	/* Initialize the return value as an array. */
1073 	array_init(return_value);
1074 
1075 	/* after our pointer arithmetic jump back to the first element */
1076 	opts = orig_opts;
1077 
1078 	while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1)) != -1) {
1079 		/* Skip unknown arguments. */
1080 		if (o == PHP_GETOPT_INVALID_ARG) {
1081 			continue;
1082 		}
1083 
1084 		/* Prepare the option character and the argument string. */
1085 		if (o == 0) {
1086 			optname = opts[php_optidx].opt_name;
1087 		} else {
1088 			if (o == 1) {
1089 				o = '-';
1090 			}
1091 			opt[0] = o;
1092 			optname = opt;
1093 		}
1094 
1095 		if (php_optarg != NULL) {
1096 			/* keep the arg as binary, since the encoding is not known */
1097 			ZVAL_STRING(&val, php_optarg);
1098 		} else {
1099 			ZVAL_FALSE(&val);
1100 		}
1101 
1102 		/* Add this option / argument pair to the result hash. */
1103 		optname_len = strlen(optname);
1104 		if (!(optname_len > 1 && optname[0] == '0') && is_numeric_string(optname, optname_len, NULL, NULL, 0) == IS_LONG) {
1105 			/* numeric string */
1106 			int optname_int = atoi(optname);
1107 			if ((args = zend_hash_index_find(Z_ARRVAL_P(return_value), optname_int)) != NULL) {
1108 				if (Z_TYPE_P(args) != IS_ARRAY) {
1109 					convert_to_array(args);
1110 				}
1111 				zend_hash_next_index_insert(Z_ARRVAL_P(args), &val);
1112 			} else {
1113 				zend_hash_index_update(Z_ARRVAL_P(return_value), optname_int, &val);
1114 			}
1115 		} else {
1116 			/* other strings */
1117 			if ((args = zend_hash_str_find(Z_ARRVAL_P(return_value), optname, strlen(optname))) != NULL) {
1118 				if (Z_TYPE_P(args) != IS_ARRAY) {
1119 					convert_to_array(args);
1120 				}
1121 				zend_hash_next_index_insert(Z_ARRVAL_P(args), &val);
1122 			} else {
1123 				zend_hash_str_add(Z_ARRVAL_P(return_value), optname, strlen(optname), &val);
1124 			}
1125 		}
1126 
1127 		php_optarg = NULL;
1128 	}
1129 
1130 	/* Set zoptind to php_optind */
1131 	if (zoptind) {
1132 		ZEND_TRY_ASSIGN_REF_LONG(zoptind, php_optind);
1133 	}
1134 
1135 	free_longopts(orig_opts);
1136 	efree(orig_opts);
1137 	free_argv(argv, argc);
1138 }
1139 /* }}} */
1140 
1141 /* {{{ Flush the output buffer */
1142 PHP_FUNCTION(flush)
1143 {
1144 	ZEND_PARSE_PARAMETERS_NONE();
1145 
1146 	sapi_flush();
1147 }
1148 /* }}} */
1149 
1150 /* {{{ Delay for a given number of seconds */
1151 PHP_FUNCTION(sleep)
1152 {
1153 	zend_long num;
1154 
1155 	ZEND_PARSE_PARAMETERS_START(1, 1)
1156 		Z_PARAM_LONG(num)
1157 	ZEND_PARSE_PARAMETERS_END();
1158 
1159 	if (num < 0) {
1160 		zend_argument_value_error(1, "must be greater than or equal to 0");
1161 		RETURN_THROWS();
1162 	}
1163 
1164 	RETURN_LONG(php_sleep((unsigned int)num));
1165 }
1166 /* }}} */
1167 
1168 /* {{{ Delay for a given number of micro seconds */
1169 PHP_FUNCTION(usleep)
1170 {
1171 	zend_long num;
1172 
1173 	ZEND_PARSE_PARAMETERS_START(1, 1)
1174 		Z_PARAM_LONG(num)
1175 	ZEND_PARSE_PARAMETERS_END();
1176 
1177 	if (num < 0) {
1178 		zend_argument_value_error(1, "must be greater than or equal to 0");
1179 		RETURN_THROWS();
1180 	}
1181 
1182 #ifdef HAVE_USLEEP
1183 	usleep((unsigned int)num);
1184 #endif
1185 }
1186 /* }}} */
1187 
1188 #ifdef HAVE_NANOSLEEP
1189 /* {{{ Delay for a number of seconds and nano seconds */
1190 PHP_FUNCTION(time_nanosleep)
1191 {
1192 	zend_long tv_sec, tv_nsec;
1193 	struct timespec php_req, php_rem;
1194 
1195 	ZEND_PARSE_PARAMETERS_START(2, 2)
1196 		Z_PARAM_LONG(tv_sec)
1197 		Z_PARAM_LONG(tv_nsec)
1198 	ZEND_PARSE_PARAMETERS_END();
1199 
1200 	if (tv_sec < 0) {
1201 		zend_argument_value_error(1, "must be greater than or equal to 0");
1202 		RETURN_THROWS();
1203 	}
1204 	if (tv_nsec < 0) {
1205 		zend_argument_value_error(2, "must be greater than or equal to 0");
1206 		RETURN_THROWS();
1207 	}
1208 
1209 	php_req.tv_sec = (time_t) tv_sec;
1210 	php_req.tv_nsec = (long)tv_nsec;
1211 	if (!nanosleep(&php_req, &php_rem)) {
1212 		RETURN_TRUE;
1213 	} else if (errno == EINTR) {
1214 		array_init(return_value);
1215 		add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
1216 		add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
1217 		return;
1218 	} else if (errno == EINVAL) {
1219 		zend_value_error("Nanoseconds was not in the range 0 to 999 999 999 or seconds was negative");
1220 		RETURN_THROWS();
1221 	}
1222 
1223 	RETURN_FALSE;
1224 }
1225 /* }}} */
1226 
1227 /* {{{ Make the script sleep until the specified time */
1228 PHP_FUNCTION(time_sleep_until)
1229 {
1230 	double target_secs;
1231 	struct timeval tm;
1232 	struct timespec php_req, php_rem;
1233 	uint64_t current_ns, target_ns, diff_ns;
1234 	const uint64_t ns_per_sec = 1000000000;
1235 	const double top_target_sec = (double)(UINT64_MAX / ns_per_sec);
1236 
1237 	ZEND_PARSE_PARAMETERS_START(1, 1)
1238 		Z_PARAM_DOUBLE(target_secs)
1239 	ZEND_PARSE_PARAMETERS_END();
1240 
1241 	if (gettimeofday((struct timeval *) &tm, NULL) != 0) {
1242 		RETURN_FALSE;
1243 	}
1244 
1245 	if (UNEXPECTED(!(target_secs >= 0 && target_secs <= top_target_sec))) {
1246 		zend_argument_value_error(1, "must be between 0 and %" PRIu64, (uint64_t)top_target_sec);
1247 		RETURN_THROWS();
1248 	}
1249 
1250 	target_ns = (uint64_t) (target_secs * ns_per_sec);
1251 	current_ns = ((uint64_t) tm.tv_sec) * ns_per_sec + ((uint64_t) tm.tv_usec) * 1000;
1252 	if (target_ns < current_ns) {
1253 		php_error_docref(NULL, E_WARNING, "Argument #1 ($timestamp) must be greater than or equal to the current time");
1254 		RETURN_FALSE;
1255 	}
1256 
1257 	diff_ns = target_ns - current_ns;
1258 	php_req.tv_sec = (time_t) (diff_ns / ns_per_sec);
1259 	php_req.tv_nsec = (long) (diff_ns % ns_per_sec);
1260 
1261 	while (nanosleep(&php_req, &php_rem)) {
1262 		if (errno == EINTR) {
1263 			php_req.tv_sec = php_rem.tv_sec;
1264 			php_req.tv_nsec = php_rem.tv_nsec;
1265 		} else {
1266 			RETURN_FALSE;
1267 		}
1268 	}
1269 
1270 	RETURN_TRUE;
1271 }
1272 /* }}} */
1273 #endif
1274 
1275 /* {{{ Get the name of the owner of the current PHP script */
1276 PHP_FUNCTION(get_current_user)
1277 {
1278 	ZEND_PARSE_PARAMETERS_NONE();
1279 
1280 	RETURN_STRING(php_get_current_user());
1281 }
1282 /* }}} */
1283 
1284 #define ZVAL_SET_INI_STR(zv, val) do { \
1285 	if (ZSTR_IS_INTERNED(val)) { \
1286 		ZVAL_INTERNED_STR(zv, val); \
1287 	} else if (ZSTR_LEN(val) == 0) { \
1288 		ZVAL_EMPTY_STRING(zv); \
1289 	} else if (ZSTR_LEN(val) == 1) { \
1290 		ZVAL_CHAR(zv, ZSTR_VAL(val)[0]); \
1291 	} else if (!(GC_FLAGS(val) & GC_PERSISTENT)) { \
1292 		ZVAL_NEW_STR(zv, zend_string_copy(val)); \
1293 	} else { \
1294 		ZVAL_NEW_STR(zv, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0)); \
1295 	} \
1296 } while (0)
1297 
1298 static void add_config_entries(HashTable *hash, zval *return_value);
1299 
1300 /* {{{ add_config_entry */
1301 static void add_config_entry(zend_ulong h, zend_string *key, zval *entry, zval *retval)
1302 {
1303 	if (Z_TYPE_P(entry) == IS_STRING) {
1304 		zval str_zv;
1305 		ZVAL_SET_INI_STR(&str_zv, Z_STR_P(entry));
1306 		if (key) {
1307 			add_assoc_zval_ex(retval, ZSTR_VAL(key), ZSTR_LEN(key), &str_zv);
1308 		} else {
1309 			add_index_zval(retval, h, &str_zv);
1310 		}
1311 	} else if (Z_TYPE_P(entry) == IS_ARRAY) {
1312 		zval tmp;
1313 		array_init(&tmp);
1314 		add_config_entries(Z_ARRVAL_P(entry), &tmp);
1315 		zend_hash_update(Z_ARRVAL_P(retval), key, &tmp);
1316 	}
1317 }
1318 /* }}} */
1319 
1320 /* {{{ add_config_entries */
1321 static void add_config_entries(HashTable *hash, zval *return_value) /* {{{ */
1322 {
1323 	zend_ulong h;
1324 	zend_string *key;
1325 	zval *zv;
1326 
1327 	ZEND_HASH_FOREACH_KEY_VAL(hash, h, key, zv)
1328 		add_config_entry(h, key, zv, return_value);
1329 	ZEND_HASH_FOREACH_END();
1330 }
1331 /* }}} */
1332 
1333 /* {{{ Get the value of a PHP configuration option */
1334 PHP_FUNCTION(get_cfg_var)
1335 {
1336 	zend_string *varname;
1337 
1338 	ZEND_PARSE_PARAMETERS_START(1, 1)
1339 		Z_PARAM_STR(varname)
1340 	ZEND_PARSE_PARAMETERS_END();
1341 
1342 	zval *retval = cfg_get_entry_ex(varname);
1343 
1344 	if (retval) {
1345 		if (Z_TYPE_P(retval) == IS_ARRAY) {
1346 			array_init(return_value);
1347 			add_config_entries(Z_ARRVAL_P(retval), return_value);
1348 			return;
1349 		} else {
1350 			ZVAL_SET_INI_STR(return_value, Z_STR_P(retval));
1351 		}
1352 	} else {
1353 		RETURN_FALSE;
1354 	}
1355 }
1356 /* }}} */
1357 
1358 /*
1359 	1st arg = error message
1360 	2nd arg = error option
1361 	3rd arg = optional parameters (email address or tcp address)
1362 	4th arg = used for additional headers if email
1363 
1364 error options:
1365 	0 = send to php_error_log (uses syslog or file depending on ini setting)
1366 	1 = send via email to 3rd parameter 4th option = additional headers
1367 	2 = send via tcp/ip to 3rd parameter (name or ip:port)
1368 	3 = save to file in 3rd parameter
1369 	4 = send to SAPI logger directly
1370 */
1371 
1372 /* {{{ Send an error message somewhere */
1373 PHP_FUNCTION(error_log)
1374 {
1375 	char *message, *opt = NULL, *headers = NULL;
1376 	size_t message_len, opt_len = 0, headers_len = 0;
1377 	zend_long erropt = 0;
1378 
1379 	ZEND_PARSE_PARAMETERS_START(1, 4)
1380 		Z_PARAM_STRING(message, message_len)
1381 		Z_PARAM_OPTIONAL
1382 		Z_PARAM_LONG(erropt)
1383 		Z_PARAM_PATH_OR_NULL(opt, opt_len)
1384 		Z_PARAM_STRING_OR_NULL(headers, headers_len)
1385 	ZEND_PARSE_PARAMETERS_END();
1386 
1387 	if (_php_error_log_ex((int) erropt, message, message_len, opt, headers) == FAILURE) {
1388 		RETURN_FALSE;
1389 	}
1390 
1391 	RETURN_TRUE;
1392 }
1393 /* }}} */
1394 
1395 /* For BC (not binary-safe!) */
1396 PHPAPI int _php_error_log(int opt_err, const char *message, const char *opt, const char *headers) /* {{{ */
1397 {
1398 	return _php_error_log_ex(opt_err, message, (opt_err == 3) ? strlen(message) : 0, opt, headers);
1399 }
1400 /* }}} */
1401 
1402 PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_len, const char *opt, const char *headers) /* {{{ */
1403 {
1404 	php_stream *stream = NULL;
1405 	size_t nbytes;
1406 
1407 	switch (opt_err)
1408 	{
1409 		case 1:		/*send an email */
1410 			if (!php_mail(opt, "PHP error_log message", message, headers, NULL)) {
1411 				return FAILURE;
1412 			}
1413 			break;
1414 
1415 		case 2:		/*send to an address */
1416 			zend_value_error("TCP/IP option is not available for error logging");
1417 			return FAILURE;
1418 
1419 		case 3:		/*save to a file */
1420 			stream = php_stream_open_wrapper(opt, "a", REPORT_ERRORS, NULL);
1421 			if (!stream) {
1422 				return FAILURE;
1423 			}
1424 			nbytes = php_stream_write(stream, message, message_len);
1425 			php_stream_close(stream);
1426 			if (nbytes != message_len) {
1427 				return FAILURE;
1428 			}
1429 			break;
1430 
1431 		case 4: /* send to SAPI */
1432 			if (sapi_module.log_message) {
1433 				sapi_module.log_message(message, -1);
1434 			} else {
1435 				return FAILURE;
1436 			}
1437 			break;
1438 
1439 		default:
1440 			php_log_err_with_severity(message, LOG_NOTICE);
1441 			break;
1442 	}
1443 	return SUCCESS;
1444 }
1445 /* }}} */
1446 
1447 /* {{{ Get the last occurred error as associative array. Returns NULL if there hasn't been an error yet. */
1448 PHP_FUNCTION(error_get_last)
1449 {
1450 	ZEND_PARSE_PARAMETERS_NONE();
1451 
1452 	if (PG(last_error_message)) {
1453 		zval tmp;
1454 		array_init(return_value);
1455 
1456 		ZVAL_LONG(&tmp, PG(last_error_type));
1457 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_TYPE), &tmp);
1458 
1459 		ZVAL_STR_COPY(&tmp, PG(last_error_message));
1460 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
1461 
1462 		ZVAL_STR_COPY(&tmp, PG(last_error_file));
1463 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
1464 
1465 		ZVAL_LONG(&tmp, PG(last_error_lineno));
1466 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
1467 	}
1468 }
1469 /* }}} */
1470 
1471 /* {{{ Clear the last occurred error. */
1472 PHP_FUNCTION(error_clear_last)
1473 {
1474 	ZEND_PARSE_PARAMETERS_NONE();
1475 
1476 	if (PG(last_error_message)) {
1477 		PG(last_error_type) = 0;
1478 		PG(last_error_lineno) = 0;
1479 
1480 		zend_string_release(PG(last_error_message));
1481 		PG(last_error_message) = NULL;
1482 
1483 		if (PG(last_error_file)) {
1484 			zend_string_release(PG(last_error_file));
1485 			PG(last_error_file) = NULL;
1486 		}
1487 	}
1488 }
1489 /* }}} */
1490 
1491 /* {{{ Call a user function which is the first parameter
1492    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1493 PHP_FUNCTION(call_user_func)
1494 {
1495 	zval retval;
1496 	zend_fcall_info fci;
1497 	zend_fcall_info_cache fci_cache;
1498 
1499 	ZEND_PARSE_PARAMETERS_START(1, -1)
1500 		Z_PARAM_FUNC(fci, fci_cache)
1501 		Z_PARAM_VARIADIC_WITH_NAMED(fci.params, fci.param_count, fci.named_params)
1502 	ZEND_PARSE_PARAMETERS_END();
1503 
1504 	fci.retval = &retval;
1505 
1506 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1507 		if (Z_ISREF(retval)) {
1508 			zend_unwrap_reference(&retval);
1509 		}
1510 		ZVAL_COPY_VALUE(return_value, &retval);
1511 	}
1512 }
1513 /* }}} */
1514 
1515 /* {{{ Call a user function which is the first parameter with the arguments contained in array
1516    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1517 PHP_FUNCTION(call_user_func_array)
1518 {
1519 	zval retval;
1520 	HashTable *params;
1521 	zend_fcall_info fci;
1522 	zend_fcall_info_cache fci_cache;
1523 
1524 	ZEND_PARSE_PARAMETERS_START(2, 2)
1525 		Z_PARAM_FUNC(fci, fci_cache)
1526 		Z_PARAM_ARRAY_HT(params)
1527 	ZEND_PARSE_PARAMETERS_END();
1528 
1529 	fci.named_params = params;
1530 	fci.retval = &retval;
1531 
1532 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1533 		if (Z_ISREF(retval)) {
1534 			zend_unwrap_reference(&retval);
1535 		}
1536 		ZVAL_COPY_VALUE(return_value, &retval);
1537 	}
1538 }
1539 /* }}} */
1540 
1541 /* {{{ Call a user function which is the first parameter */
1542 PHP_FUNCTION(forward_static_call)
1543 {
1544 	zval retval;
1545 	zend_fcall_info fci;
1546 	zend_fcall_info_cache fci_cache;
1547 	zend_class_entry *called_scope;
1548 
1549 	ZEND_PARSE_PARAMETERS_START(1, -1)
1550 		Z_PARAM_FUNC(fci, fci_cache)
1551 		Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
1552 	ZEND_PARSE_PARAMETERS_END();
1553 
1554 	if (!EX(prev_execute_data) || !EX(prev_execute_data)->func->common.scope) {
1555 		zend_throw_error(NULL, "Cannot call forward_static_call() when no class scope is active");
1556 		RETURN_THROWS();
1557 	}
1558 
1559 	fci.retval = &retval;
1560 
1561 	called_scope = zend_get_called_scope(execute_data);
1562 	if (called_scope && fci_cache.calling_scope &&
1563 		instanceof_function(called_scope, fci_cache.calling_scope)) {
1564 			fci_cache.called_scope = called_scope;
1565 	}
1566 
1567 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1568 		if (Z_ISREF(retval)) {
1569 			zend_unwrap_reference(&retval);
1570 		}
1571 		ZVAL_COPY_VALUE(return_value, &retval);
1572 	}
1573 }
1574 /* }}} */
1575 
1576 /* {{{ Call a static method which is the first parameter with the arguments contained in array */
1577 PHP_FUNCTION(forward_static_call_array)
1578 {
1579 	zval *params, retval;
1580 	zend_fcall_info fci;
1581 	zend_fcall_info_cache fci_cache;
1582 	zend_class_entry *called_scope;
1583 
1584 	ZEND_PARSE_PARAMETERS_START(2, 2)
1585 		Z_PARAM_FUNC(fci, fci_cache)
1586 		Z_PARAM_ARRAY(params)
1587 	ZEND_PARSE_PARAMETERS_END();
1588 
1589 	zend_fcall_info_args(&fci, params);
1590 	fci.retval = &retval;
1591 
1592 	called_scope = zend_get_called_scope(execute_data);
1593 	if (called_scope && fci_cache.calling_scope &&
1594 		instanceof_function(called_scope, fci_cache.calling_scope)) {
1595 			fci_cache.called_scope = called_scope;
1596 	}
1597 
1598 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1599 		if (Z_ISREF(retval)) {
1600 			zend_unwrap_reference(&retval);
1601 		}
1602 		ZVAL_COPY_VALUE(return_value, &retval);
1603 	}
1604 
1605 	zend_fcall_info_args_clear(&fci, 1);
1606 }
1607 /* }}} */
1608 
1609 static void fci_addref(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1610 {
1611 	Z_TRY_ADDREF(fci->function_name);
1612 	if (fci_cache->object) {
1613 		GC_ADDREF(fci_cache->object);
1614 	}
1615 }
1616 
1617 static void fci_release(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1618 {
1619 	zval_ptr_dtor(&fci->function_name);
1620 	if (fci_cache->object) {
1621 		zend_object_release(fci_cache->object);
1622 	}
1623 }
1624 
1625 void user_shutdown_function_dtor(zval *zv) /* {{{ */
1626 {
1627 	php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1628 
1629 	zend_fcall_info_args_clear(&shutdown_function_entry->fci, true);
1630 	fci_release(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1631 	efree(shutdown_function_entry);
1632 }
1633 /* }}} */
1634 
1635 void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
1636 {
1637 	zend_fcall_info_args_clear(&tick_function_entry->fci, true);
1638 	fci_release(&tick_function_entry->fci, &tick_function_entry->fci_cache);
1639 }
1640 /* }}} */
1641 
1642 static int user_shutdown_function_call(zval *zv) /* {{{ */
1643 {
1644 	php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1645 	zval retval;
1646 	zend_result call_status;
1647 
1648 	/* set retval zval for FCI struct */
1649 	shutdown_function_entry->fci.retval = &retval;
1650 	call_status = zend_call_function(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1651 	ZEND_ASSERT(call_status == SUCCESS);
1652 	zval_ptr_dtor(&retval);
1653 
1654 	return 0;
1655 }
1656 /* }}} */
1657 
1658 static void user_tick_function_call(user_tick_function_entry *tick_fe) /* {{{ */
1659 {
1660 	/* Prevent re-entrant calls to the same user ticks function */
1661 	if (!tick_fe->calling) {
1662 		zval tmp;
1663 
1664 		/* set tmp zval */
1665 		tick_fe->fci.retval = &tmp;
1666 
1667 		tick_fe->calling = true;
1668 		zend_call_function(&tick_fe->fci, &tick_fe->fci_cache);
1669 
1670 		/* Destroy return value */
1671 		zval_ptr_dtor(&tmp);
1672 		tick_fe->calling = false;
1673 	}
1674 }
1675 /* }}} */
1676 
1677 static void run_user_tick_functions(int tick_count, void *arg) /* {{{ */
1678 {
1679 	zend_llist_apply(BG(user_tick_functions), (llist_apply_func_t) user_tick_function_call);
1680 }
1681 /* }}} */
1682 
1683 static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_tick_function_entry * tick_fe2) /* {{{ */
1684 {
1685 	zval *func1 = &tick_fe1->fci.function_name;
1686 	zval *func2 = &tick_fe2->fci.function_name;
1687 	int ret;
1688 
1689 	if (Z_TYPE_P(func1) == IS_STRING && Z_TYPE_P(func2) == IS_STRING) {
1690 		ret = zend_binary_zval_strcmp(func1, func2) == 0;
1691 	} else if (Z_TYPE_P(func1) == IS_ARRAY && Z_TYPE_P(func2) == IS_ARRAY) {
1692 		ret = zend_compare_arrays(func1, func2) == 0;
1693 	} else if (Z_TYPE_P(func1) == IS_OBJECT && Z_TYPE_P(func2) == IS_OBJECT) {
1694 		ret = zend_compare_objects(func1, func2) == 0;
1695 	} else {
1696 		ret = 0;
1697 	}
1698 
1699 	if (ret && tick_fe1->calling) {
1700 		zend_throw_error(NULL, "Registered tick function cannot be unregistered while it is being executed");
1701 		return 0;
1702 	}
1703 	return ret;
1704 }
1705 /* }}} */
1706 
1707 PHPAPI void php_call_shutdown_functions(void) /* {{{ */
1708 {
1709 	if (BG(user_shutdown_function_names)) {
1710 		zend_try {
1711 			zend_hash_apply(BG(user_shutdown_function_names), user_shutdown_function_call);
1712 		} zend_end_try();
1713 	}
1714 }
1715 /* }}} */
1716 
1717 PHPAPI void php_free_shutdown_functions(void) /* {{{ */
1718 {
1719 	if (BG(user_shutdown_function_names))
1720 		zend_try {
1721 			zend_hash_destroy(BG(user_shutdown_function_names));
1722 			FREE_HASHTABLE(BG(user_shutdown_function_names));
1723 			BG(user_shutdown_function_names) = NULL;
1724 		} zend_catch {
1725 			/* maybe shutdown method call exit, we just ignore it */
1726 			FREE_HASHTABLE(BG(user_shutdown_function_names));
1727 			BG(user_shutdown_function_names) = NULL;
1728 		} zend_end_try();
1729 }
1730 /* }}} */
1731 
1732 /* {{{ Register a user-level function to be called on request termination */
1733 PHP_FUNCTION(register_shutdown_function)
1734 {
1735 	php_shutdown_function_entry entry;
1736 	zval *params = NULL;
1737 	uint32_t param_count = 0;
1738 	bool status;
1739 
1740 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &entry.fci, &entry.fci_cache, &params, &param_count) == FAILURE) {
1741 		RETURN_THROWS();
1742 	}
1743 
1744 	fci_addref(&entry.fci, &entry.fci_cache);
1745 	zend_fcall_info_argp(&entry.fci, param_count, params);
1746 
1747 	status = append_user_shutdown_function(&entry);
1748 	ZEND_ASSERT(status);
1749 }
1750 /* }}} */
1751 
1752 PHPAPI bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1753 {
1754 	if (!BG(user_shutdown_function_names)) {
1755 		ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1756 		zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1757 	}
1758 
1759 	zend_hash_str_update_mem(BG(user_shutdown_function_names), function_name, function_len, shutdown_function_entry, sizeof(php_shutdown_function_entry));
1760 	return 1;
1761 }
1762 /* }}} */
1763 
1764 PHPAPI bool remove_user_shutdown_function(const char *function_name, size_t function_len) /* {{{ */
1765 {
1766 	if (BG(user_shutdown_function_names)) {
1767 		return zend_hash_str_del(BG(user_shutdown_function_names), function_name, function_len) != FAILURE;
1768 	}
1769 
1770 	return 0;
1771 }
1772 /* }}} */
1773 
1774 PHPAPI bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1775 {
1776 	if (!BG(user_shutdown_function_names)) {
1777 		ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1778 		zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1779 	}
1780 
1781 	return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL;
1782 }
1783 /* }}} */
1784 
1785 ZEND_API void php_get_highlight_struct(zend_syntax_highlighter_ini *syntax_highlighter_ini) /* {{{ */
1786 {
1787 	syntax_highlighter_ini->highlight_comment = INI_STR("highlight.comment");
1788 	syntax_highlighter_ini->highlight_default = INI_STR("highlight.default");
1789 	syntax_highlighter_ini->highlight_html    = INI_STR("highlight.html");
1790 	syntax_highlighter_ini->highlight_keyword = INI_STR("highlight.keyword");
1791 	syntax_highlighter_ini->highlight_string  = INI_STR("highlight.string");
1792 }
1793 /* }}} */
1794 
1795 /* {{{ Syntax highlight a source file */
1796 PHP_FUNCTION(highlight_file)
1797 {
1798 	char *filename;
1799 	size_t filename_len;
1800 	int ret;
1801 	zend_syntax_highlighter_ini syntax_highlighter_ini;
1802 	bool i = 0;
1803 
1804 	ZEND_PARSE_PARAMETERS_START(1, 2)
1805 		Z_PARAM_PATH(filename, filename_len)
1806 		Z_PARAM_OPTIONAL
1807 		Z_PARAM_BOOL(i)
1808 	ZEND_PARSE_PARAMETERS_END();
1809 
1810 	if (php_check_open_basedir(filename)) {
1811 		RETURN_FALSE;
1812 	}
1813 
1814 	if (i) {
1815 		php_output_start_default();
1816 	}
1817 
1818 	php_get_highlight_struct(&syntax_highlighter_ini);
1819 
1820 	ret = highlight_file(filename, &syntax_highlighter_ini);
1821 
1822 	if (ret == FAILURE) {
1823 		if (i) {
1824 			php_output_end();
1825 		}
1826 		RETURN_FALSE;
1827 	}
1828 
1829 	if (i) {
1830 		php_output_get_contents(return_value);
1831 		php_output_discard();
1832 		ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1833 	} else {
1834 		RETURN_TRUE;
1835 	}
1836 }
1837 /* }}} */
1838 
1839 /* {{{ Return source with stripped comments and whitespace */
1840 PHP_FUNCTION(php_strip_whitespace)
1841 {
1842 	zend_string *filename;
1843 	zend_lex_state original_lex_state;
1844 	zend_file_handle file_handle;
1845 
1846 	ZEND_PARSE_PARAMETERS_START(1, 1)
1847 		Z_PARAM_PATH_STR(filename)
1848 	ZEND_PARSE_PARAMETERS_END();
1849 
1850 	php_output_start_default();
1851 
1852 	zend_stream_init_filename_ex(&file_handle, filename);
1853 	zend_save_lexical_state(&original_lex_state);
1854 	if (open_file_for_scanning(&file_handle) == FAILURE) {
1855 		zend_restore_lexical_state(&original_lex_state);
1856 		php_output_end();
1857 		zend_destroy_file_handle(&file_handle);
1858 		RETURN_EMPTY_STRING();
1859 	}
1860 
1861 	zend_strip();
1862 
1863 	zend_restore_lexical_state(&original_lex_state);
1864 
1865 	php_output_get_contents(return_value);
1866 	php_output_discard();
1867 	zend_destroy_file_handle(&file_handle);
1868 }
1869 /* }}} */
1870 
1871 /* {{{ Syntax highlight a string or optionally return it */
1872 PHP_FUNCTION(highlight_string)
1873 {
1874 	zend_string *str;
1875 	zend_syntax_highlighter_ini syntax_highlighter_ini;
1876 	char *hicompiled_string_description;
1877 	bool i = 0;
1878 	int old_error_reporting = EG(error_reporting);
1879 
1880 	ZEND_PARSE_PARAMETERS_START(1, 2)
1881 		Z_PARAM_STR(str)
1882 		Z_PARAM_OPTIONAL
1883 		Z_PARAM_BOOL(i)
1884 	ZEND_PARSE_PARAMETERS_END();
1885 
1886 	if (i) {
1887 		php_output_start_default();
1888 	}
1889 
1890 	EG(error_reporting) = E_ERROR;
1891 
1892 	php_get_highlight_struct(&syntax_highlighter_ini);
1893 
1894 	hicompiled_string_description = zend_make_compiled_string_description("highlighted code");
1895 
1896 	highlight_string(str, &syntax_highlighter_ini, hicompiled_string_description);
1897 	efree(hicompiled_string_description);
1898 
1899 	EG(error_reporting) = old_error_reporting;
1900 
1901 	if (i) {
1902 		php_output_get_contents(return_value);
1903 		php_output_discard();
1904 		ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1905 	} else {
1906 		// TODO Make this function void?
1907 		RETURN_TRUE;
1908 	}
1909 }
1910 /* }}} */
1911 
1912 /* {{{ Get interpreted size from the ini shorthand syntax */
1913 PHP_FUNCTION(ini_parse_quantity)
1914 {
1915 	zend_string *shorthand;
1916 	zend_string *errstr;
1917 
1918 	ZEND_PARSE_PARAMETERS_START(1, 1)
1919 		Z_PARAM_STR(shorthand)
1920 	ZEND_PARSE_PARAMETERS_END();
1921 
1922 	RETVAL_LONG(zend_ini_parse_quantity(shorthand, &errstr));
1923 
1924 	if (errstr) {
1925 		zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
1926 		zend_string_release(errstr);
1927 	}
1928 }
1929 /* }}} */
1930 
1931 /* {{{ Get a configuration option */
1932 PHP_FUNCTION(ini_get)
1933 {
1934 	zend_string *varname, *val;
1935 
1936 	ZEND_PARSE_PARAMETERS_START(1, 1)
1937 		Z_PARAM_STR(varname)
1938 	ZEND_PARSE_PARAMETERS_END();
1939 
1940 	val = zend_ini_get_value(varname);
1941 
1942 	if (!val) {
1943 		RETURN_FALSE;
1944 	}
1945 
1946 	ZVAL_SET_INI_STR(return_value, val);
1947 }
1948 /* }}} */
1949 
1950 /* {{{ Get all configuration options */
1951 PHP_FUNCTION(ini_get_all)
1952 {
1953 	char *extname = NULL;
1954 	size_t extname_len = 0, module_number = 0;
1955 	zend_module_entry *module;
1956 	bool details = 1;
1957 	zend_string *key;
1958 	zend_ini_entry *ini_entry;
1959 
1960 
1961 	ZEND_PARSE_PARAMETERS_START(0, 2)
1962 		Z_PARAM_OPTIONAL
1963 		Z_PARAM_STRING_OR_NULL(extname, extname_len)
1964 		Z_PARAM_BOOL(details)
1965 	ZEND_PARSE_PARAMETERS_END();
1966 
1967 	zend_ini_sort_entries();
1968 
1969 	if (extname) {
1970 		if ((module = zend_hash_str_find_ptr(&module_registry, extname, extname_len)) == NULL) {
1971 			php_error_docref(NULL, E_WARNING, "Extension \"%s\" cannot be found", extname);
1972 			RETURN_FALSE;
1973 		}
1974 		module_number = module->module_number;
1975 	}
1976 
1977 	array_init(return_value);
1978 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(ini_directives), key, ini_entry) {
1979 		zval option;
1980 
1981 		if (module_number != 0 && ini_entry->module_number != module_number) {
1982 			continue;
1983 		}
1984 
1985 		if (key == NULL || ZSTR_VAL(key)[0] != 0) {
1986 			if (details) {
1987 				array_init(&option);
1988 
1989 				if (ini_entry->orig_value) {
1990 					add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->orig_value));
1991 				} else if (ini_entry->value) {
1992 					add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->value));
1993 				} else {
1994 					add_assoc_null(&option, "global_value");
1995 				}
1996 
1997 				if (ini_entry->value) {
1998 					add_assoc_str(&option, "local_value", zend_string_copy(ini_entry->value));
1999 				} else {
2000 					add_assoc_null(&option, "local_value");
2001 				}
2002 
2003 				add_assoc_long(&option, "access", ini_entry->modifiable);
2004 
2005 				zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &option);
2006 			} else {
2007 				if (ini_entry->value) {
2008 					zval zv;
2009 
2010 					ZVAL_STR_COPY(&zv, ini_entry->value);
2011 					zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &zv);
2012 				} else {
2013 					zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &EG(uninitialized_zval));
2014 				}
2015 			}
2016 		}
2017 	} ZEND_HASH_FOREACH_END();
2018 }
2019 /* }}} */
2020 
2021 static int php_ini_check_path(char *option_name, size_t option_len, char *new_option_name, size_t new_option_len) /* {{{ */
2022 {
2023 	if (option_len + 1 != new_option_len) {
2024 		return 0;
2025 	}
2026 
2027 	return !strncmp(option_name, new_option_name, option_len);
2028 }
2029 /* }}} */
2030 
2031 /* {{{ Set a configuration option, returns false on error and the old value of the configuration option on success */
2032 PHP_FUNCTION(ini_set)
2033 {
2034 	zend_string *varname;
2035 	zval *new_value;
2036 	zend_string *val;
2037 
2038 	ZEND_PARSE_PARAMETERS_START(2, 2)
2039 		Z_PARAM_STR(varname)
2040 		Z_PARAM_ZVAL(new_value)
2041 	ZEND_PARSE_PARAMETERS_END();
2042 
2043 	if (Z_TYPE_P(new_value) > IS_STRING) {
2044 		zend_argument_type_error(2, "must be of type string|int|float|bool|null");
2045 		RETURN_THROWS();
2046 	}
2047 
2048 	val = zend_ini_get_value(varname);
2049 
2050 	if (val) {
2051 		ZVAL_SET_INI_STR(return_value, val);
2052 	} else {
2053 		RETVAL_FALSE;
2054 	}
2055 
2056 	zend_string *new_value_tmp_str;
2057 	zend_string *new_value_str = zval_get_tmp_string(new_value, &new_value_tmp_str);
2058 
2059 #define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
2060 	/* open basedir check */
2061 	if (PG(open_basedir)) {
2062 		if (_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "error_log") ||
2063 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.class.path") ||
2064 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.home") ||
2065 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "mail.log") ||
2066 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.library.path") ||
2067 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "vpopmail.directory")) {
2068 			if (php_check_open_basedir(ZSTR_VAL(new_value_str))) {
2069 				zval_ptr_dtor_str(return_value);
2070 				zend_tmp_string_release(new_value_tmp_str);
2071 				RETURN_FALSE;
2072 			}
2073 		}
2074 	}
2075 #undef _CHECK_PATH
2076 
2077 	if (zend_alter_ini_entry_ex(varname, new_value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2078 		zval_ptr_dtor_str(return_value);
2079 		RETVAL_FALSE;
2080 	}
2081 	zend_tmp_string_release(new_value_tmp_str);
2082 }
2083 /* }}} */
2084 
2085 /* {{{ Restore the value of a configuration option specified by varname */
2086 PHP_FUNCTION(ini_restore)
2087 {
2088 	zend_string *varname;
2089 
2090 	ZEND_PARSE_PARAMETERS_START(1, 1)
2091 		Z_PARAM_STR(varname)
2092 	ZEND_PARSE_PARAMETERS_END();
2093 
2094 	zend_restore_ini_entry(varname, PHP_INI_STAGE_RUNTIME);
2095 }
2096 /* }}} */
2097 
2098 /* {{{ Sets the include_path configuration option */
2099 PHP_FUNCTION(set_include_path)
2100 {
2101 	zend_string *new_value;
2102 	char *old_value;
2103 	zend_string *key;
2104 
2105 	ZEND_PARSE_PARAMETERS_START(1, 1)
2106 		Z_PARAM_PATH_STR(new_value)
2107 	ZEND_PARSE_PARAMETERS_END();
2108 
2109 	old_value = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2110 	/* copy to return here, because alter might free it! */
2111 	if (old_value) {
2112 		RETVAL_STRING(old_value);
2113 	} else {
2114 		RETVAL_FALSE;
2115 	}
2116 
2117 	key = zend_string_init("include_path", sizeof("include_path") - 1, 0);
2118 	if (zend_alter_ini_entry_ex(key, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2119 		zend_string_release_ex(key, 0);
2120 		zval_ptr_dtor_str(return_value);
2121 		RETURN_FALSE;
2122 	}
2123 	zend_string_release_ex(key, 0);
2124 }
2125 /* }}} */
2126 
2127 /* {{{ Get the current include_path configuration option */
2128 PHP_FUNCTION(get_include_path)
2129 {
2130 	char *str;
2131 
2132 	ZEND_PARSE_PARAMETERS_NONE();
2133 
2134 	str = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2135 
2136 	if (str == NULL) {
2137 		RETURN_FALSE;
2138 	}
2139 
2140 	RETURN_STRING(str);
2141 }
2142 /* }}} */
2143 
2144 /* {{{ Prints out or returns information about the specified variable */
2145 PHP_FUNCTION(print_r)
2146 {
2147 	zval *var;
2148 	bool do_return = 0;
2149 
2150 	ZEND_PARSE_PARAMETERS_START(1, 2)
2151 		Z_PARAM_ZVAL(var)
2152 		Z_PARAM_OPTIONAL
2153 		Z_PARAM_BOOL(do_return)
2154 	ZEND_PARSE_PARAMETERS_END();
2155 
2156 	if (do_return) {
2157 		RETURN_STR(zend_print_zval_r_to_str(var, 0));
2158 	} else {
2159 		zend_print_zval_r(var, 0);
2160 		RETURN_TRUE;
2161 	}
2162 }
2163 /* }}} */
2164 
2165 /* {{{ Returns true if client disconnected */
2166 PHP_FUNCTION(connection_aborted)
2167 {
2168 	ZEND_PARSE_PARAMETERS_NONE();
2169 
2170 	RETURN_LONG(PG(connection_status) & PHP_CONNECTION_ABORTED);
2171 }
2172 /* }}} */
2173 
2174 /* {{{ Returns the connection status bitfield */
2175 PHP_FUNCTION(connection_status)
2176 {
2177 	ZEND_PARSE_PARAMETERS_NONE();
2178 
2179 	RETURN_LONG(PG(connection_status));
2180 }
2181 /* }}} */
2182 
2183 /* {{{ Set whether we want to ignore a user abort event or not */
2184 PHP_FUNCTION(ignore_user_abort)
2185 {
2186 	bool arg = 0;
2187 	bool arg_is_null = 1;
2188 	int old_setting;
2189 
2190 	ZEND_PARSE_PARAMETERS_START(0, 1)
2191 		Z_PARAM_OPTIONAL
2192 		Z_PARAM_BOOL_OR_NULL(arg, arg_is_null)
2193 	ZEND_PARSE_PARAMETERS_END();
2194 
2195 	old_setting = (unsigned short)PG(ignore_user_abort);
2196 
2197 	if (!arg_is_null) {
2198 		zend_string *key = zend_string_init("ignore_user_abort", sizeof("ignore_user_abort") - 1, 0);
2199 		zend_alter_ini_entry_chars(key, arg ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2200 		zend_string_release_ex(key, 0);
2201 	}
2202 
2203 	RETURN_LONG(old_setting);
2204 }
2205 /* }}} */
2206 
2207 #ifdef HAVE_GETSERVBYNAME
2208 /* {{{ Returns port associated with service. Protocol must be "tcp" or "udp" */
2209 PHP_FUNCTION(getservbyname)
2210 {
2211 	zend_string *name;
2212 	char *proto;
2213 	size_t proto_len;
2214 	struct servent *serv;
2215 
2216 	ZEND_PARSE_PARAMETERS_START(2, 2)
2217 		Z_PARAM_STR(name)
2218 		Z_PARAM_STRING(proto, proto_len)
2219 	ZEND_PARSE_PARAMETERS_END();
2220 
2221 
2222 /* empty string behaves like NULL on windows implementation of
2223    getservbyname. Let be portable instead. */
2224 #ifdef PHP_WIN32
2225 	if (proto_len == 0) {
2226 		RETURN_FALSE;
2227 	}
2228 #endif
2229 
2230 	serv = getservbyname(ZSTR_VAL(name), proto);
2231 
2232 #ifdef _AIX
2233 	/*
2234         On AIX, imap is only known as imap2 in /etc/services, while on Linux imap is an alias for imap2.
2235         If a request for imap gives no result, we try again with imap2.
2236         */
2237 	if (serv == NULL && zend_string_equals_literal(name, "imap")) {
2238 		serv = getservbyname("imap2", proto);
2239 	}
2240 #endif
2241 	if (serv == NULL) {
2242 		RETURN_FALSE;
2243 	}
2244 
2245 	RETURN_LONG(ntohs(serv->s_port));
2246 }
2247 /* }}} */
2248 #endif
2249 
2250 #ifdef HAVE_GETSERVBYPORT
2251 /* {{{ Returns service name associated with port. Protocol must be "tcp" or "udp" */
2252 PHP_FUNCTION(getservbyport)
2253 {
2254 	char *proto;
2255 	size_t proto_len;
2256 	zend_long port;
2257 	struct servent *serv;
2258 
2259 	ZEND_PARSE_PARAMETERS_START(2, 2)
2260 		Z_PARAM_LONG(port)
2261 		Z_PARAM_STRING(proto, proto_len)
2262 	ZEND_PARSE_PARAMETERS_END();
2263 
2264 	serv = getservbyport(htons((unsigned short) port), proto);
2265 
2266 	if (serv == NULL) {
2267 		RETURN_FALSE;
2268 	}
2269 
2270 	/* MSAN false positive, getservbyport() is not properly intercepted. */
2271 #if __has_feature(memory_sanitizer)
2272 	__msan_unpoison_string(serv->s_name);
2273 #endif
2274 	RETURN_STRING(serv->s_name);
2275 }
2276 /* }}} */
2277 #endif
2278 
2279 #ifdef HAVE_GETPROTOBYNAME
2280 /* {{{ Returns protocol number associated with name as per /etc/protocols */
2281 PHP_FUNCTION(getprotobyname)
2282 {
2283 	char *name;
2284 	size_t name_len;
2285 	struct protoent *ent;
2286 
2287 	ZEND_PARSE_PARAMETERS_START(1, 1)
2288 		Z_PARAM_STRING(name, name_len)
2289 	ZEND_PARSE_PARAMETERS_END();
2290 
2291 	ent = getprotobyname(name);
2292 
2293 	if (ent == NULL) {
2294 		RETURN_FALSE;
2295 	}
2296 
2297 	RETURN_LONG(ent->p_proto);
2298 }
2299 /* }}} */
2300 #endif
2301 
2302 #ifdef HAVE_GETPROTOBYNUMBER
2303 /* {{{ Returns protocol name associated with protocol number proto */
2304 PHP_FUNCTION(getprotobynumber)
2305 {
2306 	zend_long proto;
2307 	struct protoent *ent;
2308 
2309 	ZEND_PARSE_PARAMETERS_START(1, 1)
2310 		Z_PARAM_LONG(proto)
2311 	ZEND_PARSE_PARAMETERS_END();
2312 
2313 	ent = getprotobynumber((int)proto);
2314 
2315 	if (ent == NULL) {
2316 		RETURN_FALSE;
2317 	}
2318 
2319 	RETURN_STRING(ent->p_name);
2320 }
2321 /* }}} */
2322 #endif
2323 
2324 /* {{{ Registers a tick callback function */
2325 PHP_FUNCTION(register_tick_function)
2326 {
2327 	user_tick_function_entry tick_fe;
2328 	zval *params = NULL;
2329 	uint32_t param_count = 0;
2330 
2331 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &tick_fe.fci, &tick_fe.fci_cache, &params, &param_count) == FAILURE) {
2332 		RETURN_THROWS();
2333 	}
2334 
2335 	tick_fe.calling = false;
2336 	fci_addref(&tick_fe.fci, &tick_fe.fci_cache);
2337 	zend_fcall_info_argp(&tick_fe.fci, param_count, params);
2338 
2339 	if (!BG(user_tick_functions)) {
2340 		BG(user_tick_functions) = (zend_llist *) emalloc(sizeof(zend_llist));
2341 		zend_llist_init(BG(user_tick_functions),
2342 						sizeof(user_tick_function_entry),
2343 						(llist_dtor_func_t) user_tick_function_dtor, 0);
2344 		php_add_tick_function(run_user_tick_functions, NULL);
2345 	}
2346 
2347 	zend_llist_add_element(BG(user_tick_functions), &tick_fe);
2348 
2349 	RETURN_TRUE;
2350 }
2351 /* }}} */
2352 
2353 /* {{{ Unregisters a tick callback function */
2354 PHP_FUNCTION(unregister_tick_function)
2355 {
2356 	user_tick_function_entry tick_fe;
2357 
2358 	ZEND_PARSE_PARAMETERS_START(1, 1)
2359 		Z_PARAM_FUNC(tick_fe.fci, tick_fe.fci_cache)
2360 	ZEND_PARSE_PARAMETERS_END();
2361 
2362 	if (!BG(user_tick_functions)) {
2363 		return;
2364 	}
2365 
2366 	zend_llist_del_element(BG(user_tick_functions), &tick_fe, (int (*)(void *, void *)) user_tick_function_compare);
2367 }
2368 /* }}} */
2369 
2370 /* {{{ Check if file was created by rfc1867 upload */
2371 PHP_FUNCTION(is_uploaded_file)
2372 {
2373 	char *path;
2374 	size_t path_len;
2375 
2376 	ZEND_PARSE_PARAMETERS_START(1, 1)
2377 		Z_PARAM_PATH(path, path_len)
2378 	ZEND_PARSE_PARAMETERS_END();
2379 
2380 	if (!SG(rfc1867_uploaded_files)) {
2381 		RETURN_FALSE;
2382 	}
2383 
2384 	if (zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) {
2385 		RETURN_TRUE;
2386 	} else {
2387 		RETURN_FALSE;
2388 	}
2389 }
2390 /* }}} */
2391 
2392 /* {{{ Move a file if and only if it was created by an upload */
2393 PHP_FUNCTION(move_uploaded_file)
2394 {
2395 	char *path, *new_path;
2396 	size_t path_len, new_path_len;
2397 	bool successful = 0;
2398 
2399 #ifndef PHP_WIN32
2400 	int oldmask; int ret;
2401 #endif
2402 
2403 	ZEND_PARSE_PARAMETERS_START(2, 2)
2404 		Z_PARAM_STRING(path, path_len)
2405 		Z_PARAM_PATH(new_path, new_path_len)
2406 	ZEND_PARSE_PARAMETERS_END();
2407 
2408 	if (!SG(rfc1867_uploaded_files)) {
2409 		RETURN_FALSE;
2410 	}
2411 
2412 	if (!zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) {
2413 		RETURN_FALSE;
2414 	}
2415 
2416 	if (php_check_open_basedir(new_path)) {
2417 		RETURN_FALSE;
2418 	}
2419 
2420 	if (VCWD_RENAME(path, new_path) == 0) {
2421 		successful = 1;
2422 #ifndef PHP_WIN32
2423 		oldmask = umask(077);
2424 		umask(oldmask);
2425 
2426 		ret = VCWD_CHMOD(new_path, 0666 & ~oldmask);
2427 
2428 		if (ret == -1) {
2429 			php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
2430 		}
2431 #endif
2432 	} else if (php_copy_file_ex(path, new_path, STREAM_DISABLE_OPEN_BASEDIR) == SUCCESS) {
2433 		VCWD_UNLINK(path);
2434 		successful = 1;
2435 	}
2436 
2437 	if (successful) {
2438 		zend_hash_str_del(SG(rfc1867_uploaded_files), path, path_len);
2439 	} else {
2440 		php_error_docref(NULL, E_WARNING, "Unable to move \"%s\" to \"%s\"", path, new_path);
2441 	}
2442 
2443 	RETURN_BOOL(successful);
2444 }
2445 /* }}} */
2446 
2447 /* {{{ php_simple_ini_parser_cb */
2448 static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr)
2449 {
2450 	switch (callback_type) {
2451 
2452 		case ZEND_INI_PARSER_ENTRY:
2453 			if (!arg2) {
2454 				/* bare string - nothing to do */
2455 				break;
2456 			}
2457 			Z_TRY_ADDREF_P(arg2);
2458 			zend_symtable_update(Z_ARRVAL_P(arr), Z_STR_P(arg1), arg2);
2459 			break;
2460 
2461 		case ZEND_INI_PARSER_POP_ENTRY:
2462 		{
2463 			zval hash, *find_hash;
2464 
2465 			if (!arg2) {
2466 				/* bare string - nothing to do */
2467 				break;
2468 			}
2469 
2470 			/* entry in the form x[a]=b where x might need to be an array index */
2471 			if (!(Z_STRLEN_P(arg1) > 1 && Z_STRVAL_P(arg1)[0] == '0') && is_numeric_string(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), NULL, NULL, 0) == IS_LONG) {
2472 				zend_ulong key = (zend_ulong) ZEND_STRTOUL(Z_STRVAL_P(arg1), NULL, 0);
2473 				if ((find_hash = zend_hash_index_find(Z_ARRVAL_P(arr), key)) == NULL) {
2474 					array_init(&hash);
2475 					find_hash = zend_hash_index_add_new(Z_ARRVAL_P(arr), key, &hash);
2476 				}
2477 			} else {
2478 				if ((find_hash = zend_hash_find(Z_ARRVAL_P(arr), Z_STR_P(arg1))) == NULL) {
2479 					array_init(&hash);
2480 					find_hash = zend_hash_add_new(Z_ARRVAL_P(arr), Z_STR_P(arg1), &hash);
2481 				}
2482 			}
2483 
2484 			if (Z_TYPE_P(find_hash) != IS_ARRAY) {
2485 				zval_ptr_dtor_nogc(find_hash);
2486 				array_init(find_hash);
2487 			}
2488 
2489 			if (!arg3 || (Z_TYPE_P(arg3) == IS_STRING && Z_STRLEN_P(arg3) == 0)) {
2490 				Z_TRY_ADDREF_P(arg2);
2491 				add_next_index_zval(find_hash, arg2);
2492 			} else {
2493 				array_set_zval_key(Z_ARRVAL_P(find_hash), arg3, arg2);
2494 			}
2495 		}
2496 		break;
2497 
2498 		case ZEND_INI_PARSER_SECTION:
2499 			break;
2500 	}
2501 }
2502 /* }}} */
2503 
2504 /* {{{ php_ini_parser_cb_with_sections */
2505 static void php_ini_parser_cb_with_sections(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr)
2506 {
2507 	if (callback_type == ZEND_INI_PARSER_SECTION) {
2508 		array_init(&BG(active_ini_file_section));
2509 		zend_symtable_update(Z_ARRVAL_P(arr), Z_STR_P(arg1), &BG(active_ini_file_section));
2510 	} else if (arg2) {
2511 		zval *active_arr;
2512 
2513 		if (Z_TYPE(BG(active_ini_file_section)) != IS_UNDEF) {
2514 			active_arr = &BG(active_ini_file_section);
2515 		} else {
2516 			active_arr = arr;
2517 		}
2518 
2519 		php_simple_ini_parser_cb(arg1, arg2, arg3, callback_type, active_arr);
2520 	}
2521 }
2522 /* }}} */
2523 
2524 /* {{{ Parse configuration file */
2525 PHP_FUNCTION(parse_ini_file)
2526 {
2527 	zend_string *filename = NULL;
2528 	bool process_sections = 0;
2529 	zend_long scanner_mode = ZEND_INI_SCANNER_NORMAL;
2530 	zend_file_handle fh;
2531 	zend_ini_parser_cb_t ini_parser_cb;
2532 
2533 	ZEND_PARSE_PARAMETERS_START(1, 3)
2534 		Z_PARAM_PATH_STR(filename)
2535 		Z_PARAM_OPTIONAL
2536 		Z_PARAM_BOOL(process_sections)
2537 		Z_PARAM_LONG(scanner_mode)
2538 	ZEND_PARSE_PARAMETERS_END();
2539 
2540 	if (ZSTR_LEN(filename) == 0) {
2541 		zend_argument_value_error(1, "cannot be empty");
2542 		RETURN_THROWS();
2543 	}
2544 
2545 	/* Set callback function */
2546 	if (process_sections) {
2547 		ZVAL_UNDEF(&BG(active_ini_file_section));
2548 		ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
2549 	} else {
2550 		ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
2551 	}
2552 
2553 	/* Setup filehandle */
2554 	zend_stream_init_filename_ex(&fh, filename);
2555 
2556 	array_init(return_value);
2557 	if (zend_parse_ini_file(&fh, 0, (int)scanner_mode, ini_parser_cb, return_value) == FAILURE) {
2558 		zend_array_destroy(Z_ARR_P(return_value));
2559 		RETVAL_FALSE;
2560 	}
2561 	zend_destroy_file_handle(&fh);
2562 }
2563 /* }}} */
2564 
2565 /* {{{ Parse configuration string */
2566 PHP_FUNCTION(parse_ini_string)
2567 {
2568 	char *string = NULL, *str = NULL;
2569 	size_t str_len = 0;
2570 	bool process_sections = 0;
2571 	zend_long scanner_mode = ZEND_INI_SCANNER_NORMAL;
2572 	zend_ini_parser_cb_t ini_parser_cb;
2573 
2574 	ZEND_PARSE_PARAMETERS_START(1, 3)
2575 		Z_PARAM_STRING(str, str_len)
2576 		Z_PARAM_OPTIONAL
2577 		Z_PARAM_BOOL(process_sections)
2578 		Z_PARAM_LONG(scanner_mode)
2579 	ZEND_PARSE_PARAMETERS_END();
2580 
2581 	if (INT_MAX - str_len < ZEND_MMAP_AHEAD) {
2582 		RETVAL_FALSE;
2583 	}
2584 
2585 	/* Set callback function */
2586 	if (process_sections) {
2587 		ZVAL_UNDEF(&BG(active_ini_file_section));
2588 		ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
2589 	} else {
2590 		ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
2591 	}
2592 
2593 	/* Setup string */
2594 	string = (char *) emalloc(str_len + ZEND_MMAP_AHEAD);
2595 	memcpy(string, str, str_len);
2596 	memset(string + str_len, 0, ZEND_MMAP_AHEAD);
2597 
2598 	array_init(return_value);
2599 	if (zend_parse_ini_string(string, 0, (int)scanner_mode, ini_parser_cb, return_value) == FAILURE) {
2600 		zend_array_destroy(Z_ARR_P(return_value));
2601 		RETVAL_FALSE;
2602 	}
2603 	efree(string);
2604 }
2605 /* }}} */
2606 
2607 #if ZEND_DEBUG
2608 /* This function returns an array of ALL valid ini options with values and
2609  *  is not the same as ini_get_all() which returns only registered ini options. Only useful for devs to debug php.ini scanner/parser! */
2610 PHP_FUNCTION(config_get_hash) /* {{{ */
2611 {
2612 	ZEND_PARSE_PARAMETERS_NONE();
2613 
2614 	HashTable *hash = php_ini_get_configuration_hash();
2615 
2616 	array_init(return_value);
2617 	add_config_entries(hash, return_value);
2618 }
2619 /* }}} */
2620 #endif
2621 
2622 #ifdef HAVE_GETLOADAVG
2623 /* {{{ */
2624 PHP_FUNCTION(sys_getloadavg)
2625 {
2626 	double load[3];
2627 
2628 	ZEND_PARSE_PARAMETERS_NONE();
2629 
2630 	if (getloadavg(load, 3) == -1) {
2631 		RETURN_FALSE;
2632 	} else {
2633 		array_init(return_value);
2634 		add_index_double(return_value, 0, load[0]);
2635 		add_index_double(return_value, 1, load[1]);
2636 		add_index_double(return_value, 2, load[2]);
2637 	}
2638 }
2639 /* }}} */
2640 #endif
2641