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