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