xref: /php-src/ext/standard/basic_functions.c (revision 0faa1d20)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Andi Gutmans <andi@php.net>                                 |
14    |          Zeev Suraski <zeev@php.net>                                 |
15    +----------------------------------------------------------------------+
16  */
17 
18 #include "php.h"
19 #include "php_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 		add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
1186 		add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
1187 		return;
1188 	} else if (errno == EINVAL) {
1189 		zend_value_error("Nanoseconds was not in the range 0 to 999 999 999 or seconds was negative");
1190 		RETURN_THROWS();
1191 	}
1192 
1193 	RETURN_FALSE;
1194 }
1195 /* }}} */
1196 
1197 /* {{{ Make the script sleep until the specified time */
1198 PHP_FUNCTION(time_sleep_until)
1199 {
1200 	double target_secs;
1201 	struct timeval tm;
1202 	struct timespec php_req, php_rem;
1203 	uint64_t current_ns, target_ns, diff_ns;
1204 	const uint64_t ns_per_sec = 1000000000;
1205 	const double top_target_sec = (double)(UINT64_MAX / ns_per_sec);
1206 
1207 	ZEND_PARSE_PARAMETERS_START(1, 1)
1208 		Z_PARAM_DOUBLE(target_secs)
1209 	ZEND_PARSE_PARAMETERS_END();
1210 
1211 	if (gettimeofday((struct timeval *) &tm, NULL) != 0) {
1212 		RETURN_FALSE;
1213 	}
1214 
1215 	if (UNEXPECTED(!(target_secs >= 0 && target_secs <= top_target_sec))) {
1216 		zend_argument_value_error(1, "must be between 0 and %" PRIu64, (uint64_t)top_target_sec);
1217 		RETURN_THROWS();
1218 	}
1219 
1220 	target_ns = (uint64_t) (target_secs * ns_per_sec);
1221 	current_ns = ((uint64_t) tm.tv_sec) * ns_per_sec + ((uint64_t) tm.tv_usec) * 1000;
1222 	if (target_ns < current_ns) {
1223 		php_error_docref(NULL, E_WARNING, "Argument #1 ($timestamp) must be greater than or equal to the current time");
1224 		RETURN_FALSE;
1225 	}
1226 
1227 	diff_ns = target_ns - current_ns;
1228 	php_req.tv_sec = (time_t) (diff_ns / ns_per_sec);
1229 	php_req.tv_nsec = (long) (diff_ns % ns_per_sec);
1230 
1231 	while (nanosleep(&php_req, &php_rem)) {
1232 		if (errno == EINTR) {
1233 			php_req.tv_sec = php_rem.tv_sec;
1234 			php_req.tv_nsec = php_rem.tv_nsec;
1235 		} else {
1236 			RETURN_FALSE;
1237 		}
1238 	}
1239 
1240 	RETURN_TRUE;
1241 }
1242 /* }}} */
1243 #endif
1244 
1245 /* {{{ Get the name of the owner of the current PHP script */
1246 PHP_FUNCTION(get_current_user)
1247 {
1248 	ZEND_PARSE_PARAMETERS_NONE();
1249 
1250 	RETURN_STRING(php_get_current_user());
1251 }
1252 /* }}} */
1253 
1254 #define ZVAL_SET_INI_STR(zv, val) do { \
1255 	if (ZSTR_IS_INTERNED(val)) { \
1256 		ZVAL_INTERNED_STR(zv, val); \
1257 	} else if (ZSTR_LEN(val) == 0) { \
1258 		ZVAL_EMPTY_STRING(zv); \
1259 	} else if (ZSTR_LEN(val) == 1) { \
1260 		ZVAL_CHAR(zv, ZSTR_VAL(val)[0]); \
1261 	} else if (!(GC_FLAGS(val) & GC_PERSISTENT)) { \
1262 		ZVAL_NEW_STR(zv, zend_string_copy(val)); \
1263 	} else { \
1264 		ZVAL_NEW_STR(zv, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0)); \
1265 	} \
1266 } while (0)
1267 
1268 static void add_config_entries(HashTable *hash, zval *return_value);
1269 
1270 /* {{{ add_config_entry */
1271 static void add_config_entry(zend_ulong h, zend_string *key, zval *entry, zval *retval)
1272 {
1273 	if (Z_TYPE_P(entry) == IS_STRING) {
1274 		zval str_zv;
1275 		ZVAL_SET_INI_STR(&str_zv, Z_STR_P(entry));
1276 		if (key) {
1277 			add_assoc_zval_ex(retval, ZSTR_VAL(key), ZSTR_LEN(key), &str_zv);
1278 		} else {
1279 			add_index_zval(retval, h, &str_zv);
1280 		}
1281 	} else if (Z_TYPE_P(entry) == IS_ARRAY) {
1282 		zval tmp;
1283 		array_init(&tmp);
1284 		add_config_entries(Z_ARRVAL_P(entry), &tmp);
1285 		zend_hash_update(Z_ARRVAL_P(retval), key, &tmp);
1286 	}
1287 }
1288 /* }}} */
1289 
1290 /* {{{ add_config_entries */
1291 static void add_config_entries(HashTable *hash, zval *return_value) /* {{{ */
1292 {
1293 	zend_ulong h;
1294 	zend_string *key;
1295 	zval *zv;
1296 
1297 	ZEND_HASH_FOREACH_KEY_VAL(hash, h, key, zv)
1298 		add_config_entry(h, key, zv, return_value);
1299 	ZEND_HASH_FOREACH_END();
1300 }
1301 /* }}} */
1302 
1303 /* {{{ Get the value of a PHP configuration option */
1304 PHP_FUNCTION(get_cfg_var)
1305 {
1306 	zend_string *varname;
1307 
1308 	ZEND_PARSE_PARAMETERS_START(1, 1)
1309 		Z_PARAM_STR(varname)
1310 	ZEND_PARSE_PARAMETERS_END();
1311 
1312 	zval *retval = cfg_get_entry_ex(varname);
1313 
1314 	if (retval) {
1315 		if (Z_TYPE_P(retval) == IS_ARRAY) {
1316 			array_init(return_value);
1317 			add_config_entries(Z_ARRVAL_P(retval), return_value);
1318 			return;
1319 		} else {
1320 			ZVAL_SET_INI_STR(return_value, Z_STR_P(retval));
1321 		}
1322 	} else {
1323 		RETURN_FALSE;
1324 	}
1325 }
1326 /* }}} */
1327 
1328 /*
1329 	1st arg = error message
1330 	2nd arg = error option
1331 	3rd arg = optional parameters (email address or tcp address)
1332 	4th arg = used for additional headers if email
1333 
1334 error options:
1335 	0 = send to php_error_log (uses syslog or file depending on ini setting)
1336 	1 = send via email to 3rd parameter 4th option = additional headers
1337 	2 = send via tcp/ip to 3rd parameter (name or ip:port)
1338 	3 = save to file in 3rd parameter
1339 	4 = send to SAPI logger directly
1340 */
1341 
1342 /* {{{ Send an error message somewhere */
1343 PHP_FUNCTION(error_log)
1344 {
1345 	char *message, *opt = NULL, *headers = NULL;
1346 	size_t message_len, opt_len = 0, headers_len = 0;
1347 	zend_long erropt = 0;
1348 
1349 	ZEND_PARSE_PARAMETERS_START(1, 4)
1350 		Z_PARAM_STRING(message, message_len)
1351 		Z_PARAM_OPTIONAL
1352 		Z_PARAM_LONG(erropt)
1353 		Z_PARAM_PATH_OR_NULL(opt, opt_len)
1354 		Z_PARAM_STRING_OR_NULL(headers, headers_len)
1355 	ZEND_PARSE_PARAMETERS_END();
1356 
1357 	if (_php_error_log_ex((int) erropt, message, message_len, opt, headers) == FAILURE) {
1358 		RETURN_FALSE;
1359 	}
1360 
1361 	RETURN_TRUE;
1362 }
1363 /* }}} */
1364 
1365 /* For BC (not binary-safe!) */
1366 PHPAPI int _php_error_log(int opt_err, const char *message, const char *opt, const char *headers) /* {{{ */
1367 {
1368 	return _php_error_log_ex(opt_err, message, (opt_err == 3) ? strlen(message) : 0, opt, headers);
1369 }
1370 /* }}} */
1371 
1372 PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_len, const char *opt, const char *headers) /* {{{ */
1373 {
1374 	php_stream *stream = NULL;
1375 	size_t nbytes;
1376 
1377 	switch (opt_err)
1378 	{
1379 		case 1:		/*send an email */
1380 			if (!php_mail(opt, "PHP error_log message", message, headers, NULL)) {
1381 				return FAILURE;
1382 			}
1383 			break;
1384 
1385 		case 2:		/*send to an address */
1386 			zend_value_error("TCP/IP option is not available for error logging");
1387 			return FAILURE;
1388 
1389 		case 3:		/*save to a file */
1390 			stream = php_stream_open_wrapper(opt, "a", REPORT_ERRORS, NULL);
1391 			if (!stream) {
1392 				return FAILURE;
1393 			}
1394 			nbytes = php_stream_write(stream, message, message_len);
1395 			php_stream_close(stream);
1396 			if (nbytes != message_len) {
1397 				return FAILURE;
1398 			}
1399 			break;
1400 
1401 		case 4: /* send to SAPI */
1402 			if (sapi_module.log_message) {
1403 				sapi_module.log_message(message, -1);
1404 			} else {
1405 				return FAILURE;
1406 			}
1407 			break;
1408 
1409 		default:
1410 			php_log_err_with_severity(message, LOG_NOTICE);
1411 			break;
1412 	}
1413 	return SUCCESS;
1414 }
1415 /* }}} */
1416 
1417 /* {{{ Get the last occurred error as associative array. Returns NULL if there hasn't been an error yet. */
1418 PHP_FUNCTION(error_get_last)
1419 {
1420 	ZEND_PARSE_PARAMETERS_NONE();
1421 
1422 	if (PG(last_error_message)) {
1423 		zval tmp;
1424 		array_init(return_value);
1425 
1426 		ZVAL_LONG(&tmp, PG(last_error_type));
1427 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_TYPE), &tmp);
1428 
1429 		ZVAL_STR_COPY(&tmp, PG(last_error_message));
1430 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
1431 
1432 		ZVAL_STR_COPY(&tmp, PG(last_error_file));
1433 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
1434 
1435 		ZVAL_LONG(&tmp, PG(last_error_lineno));
1436 		zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
1437 	}
1438 }
1439 /* }}} */
1440 
1441 /* {{{ Clear the last occurred error. */
1442 PHP_FUNCTION(error_clear_last)
1443 {
1444 	ZEND_PARSE_PARAMETERS_NONE();
1445 
1446 	if (PG(last_error_message)) {
1447 		PG(last_error_type) = 0;
1448 		PG(last_error_lineno) = 0;
1449 
1450 		zend_string_release(PG(last_error_message));
1451 		PG(last_error_message) = NULL;
1452 
1453 		if (PG(last_error_file)) {
1454 			zend_string_release(PG(last_error_file));
1455 			PG(last_error_file) = NULL;
1456 		}
1457 	}
1458 }
1459 /* }}} */
1460 
1461 /* {{{ Call a user function which is the first parameter
1462    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1463 PHP_FUNCTION(call_user_func)
1464 {
1465 	zval retval;
1466 	zend_fcall_info fci;
1467 	zend_fcall_info_cache fci_cache;
1468 
1469 	ZEND_PARSE_PARAMETERS_START(1, -1)
1470 		Z_PARAM_FUNC(fci, fci_cache)
1471 		Z_PARAM_VARIADIC_WITH_NAMED(fci.params, fci.param_count, fci.named_params)
1472 	ZEND_PARSE_PARAMETERS_END();
1473 
1474 	fci.retval = &retval;
1475 
1476 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1477 		if (Z_ISREF(retval)) {
1478 			zend_unwrap_reference(&retval);
1479 		}
1480 		ZVAL_COPY_VALUE(return_value, &retval);
1481 	}
1482 }
1483 /* }}} */
1484 
1485 /* {{{ Call a user function which is the first parameter with the arguments contained in array
1486    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1487 PHP_FUNCTION(call_user_func_array)
1488 {
1489 	zval retval;
1490 	HashTable *params;
1491 	zend_fcall_info fci;
1492 	zend_fcall_info_cache fci_cache;
1493 
1494 	ZEND_PARSE_PARAMETERS_START(2, 2)
1495 		Z_PARAM_FUNC(fci, fci_cache)
1496 		Z_PARAM_ARRAY_HT(params)
1497 	ZEND_PARSE_PARAMETERS_END();
1498 
1499 	fci.named_params = params;
1500 	fci.retval = &retval;
1501 
1502 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1503 		if (Z_ISREF(retval)) {
1504 			zend_unwrap_reference(&retval);
1505 		}
1506 		ZVAL_COPY_VALUE(return_value, &retval);
1507 	}
1508 }
1509 /* }}} */
1510 
1511 /* {{{ Call a user function which is the first parameter */
1512 PHP_FUNCTION(forward_static_call)
1513 {
1514 	zval retval;
1515 	zend_fcall_info fci;
1516 	zend_fcall_info_cache fci_cache;
1517 	zend_class_entry *called_scope;
1518 
1519 	ZEND_PARSE_PARAMETERS_START(1, -1)
1520 		Z_PARAM_FUNC(fci, fci_cache)
1521 		Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
1522 	ZEND_PARSE_PARAMETERS_END();
1523 
1524 	if (!EX(prev_execute_data) || !EX(prev_execute_data)->func->common.scope) {
1525 		zend_throw_error(NULL, "Cannot call forward_static_call() when no class scope is active");
1526 		RETURN_THROWS();
1527 	}
1528 
1529 	fci.retval = &retval;
1530 
1531 	called_scope = zend_get_called_scope(execute_data);
1532 	if (called_scope && fci_cache.calling_scope &&
1533 		instanceof_function(called_scope, fci_cache.calling_scope)) {
1534 			fci_cache.called_scope = called_scope;
1535 	}
1536 
1537 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1538 		if (Z_ISREF(retval)) {
1539 			zend_unwrap_reference(&retval);
1540 		}
1541 		ZVAL_COPY_VALUE(return_value, &retval);
1542 	}
1543 }
1544 /* }}} */
1545 
1546 /* {{{ Call a static method which is the first parameter with the arguments contained in array */
1547 PHP_FUNCTION(forward_static_call_array)
1548 {
1549 	zval retval;
1550 	HashTable *params;
1551 	zend_fcall_info fci;
1552 	zend_fcall_info_cache fci_cache;
1553 	zend_class_entry *called_scope;
1554 
1555 	ZEND_PARSE_PARAMETERS_START(2, 2)
1556 		Z_PARAM_FUNC(fci, fci_cache)
1557 		Z_PARAM_ARRAY_HT(params)
1558 	ZEND_PARSE_PARAMETERS_END();
1559 
1560 	fci.retval = &retval;
1561 	/* Add positional arguments */
1562 	fci.named_params = params;
1563 
1564 	called_scope = zend_get_called_scope(execute_data);
1565 	if (called_scope && fci_cache.calling_scope &&
1566 		instanceof_function(called_scope, fci_cache.calling_scope)) {
1567 			fci_cache.called_scope = called_scope;
1568 	}
1569 
1570 	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1571 		if (Z_ISREF(retval)) {
1572 			zend_unwrap_reference(&retval);
1573 		}
1574 		ZVAL_COPY_VALUE(return_value, &retval);
1575 	}
1576 }
1577 /* }}} */
1578 
1579 static void fci_addref(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1580 {
1581 	Z_TRY_ADDREF(fci->function_name);
1582 	if (fci_cache->object) {
1583 		GC_ADDREF(fci_cache->object);
1584 	}
1585 }
1586 
1587 static void fci_release(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1588 {
1589 	zval_ptr_dtor(&fci->function_name);
1590 	if (fci_cache->object) {
1591 		zend_object_release(fci_cache->object);
1592 	}
1593 }
1594 
1595 void user_shutdown_function_dtor(zval *zv) /* {{{ */
1596 {
1597 	php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1598 
1599 	zend_fcall_info_args_clear(&shutdown_function_entry->fci, true);
1600 	fci_release(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1601 	efree(shutdown_function_entry);
1602 }
1603 /* }}} */
1604 
1605 void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
1606 {
1607 	zend_fcall_info_args_clear(&tick_function_entry->fci, true);
1608 	fci_release(&tick_function_entry->fci, &tick_function_entry->fci_cache);
1609 }
1610 /* }}} */
1611 
1612 static int user_shutdown_function_call(zval *zv) /* {{{ */
1613 {
1614 	php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1615 	zval retval;
1616 	zend_result call_status;
1617 
1618 	/* set retval zval for FCI struct */
1619 	shutdown_function_entry->fci.retval = &retval;
1620 	call_status = zend_call_function(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1621 	ZEND_ASSERT(call_status == SUCCESS);
1622 	zval_ptr_dtor(&retval);
1623 
1624 	return 0;
1625 }
1626 /* }}} */
1627 
1628 static void user_tick_function_call(user_tick_function_entry *tick_fe) /* {{{ */
1629 {
1630 	/* Prevent re-entrant calls to the same user ticks function */
1631 	if (!tick_fe->calling) {
1632 		zval tmp;
1633 
1634 		/* set tmp zval */
1635 		tick_fe->fci.retval = &tmp;
1636 
1637 		tick_fe->calling = true;
1638 		zend_call_function(&tick_fe->fci, &tick_fe->fci_cache);
1639 
1640 		/* Destroy return value */
1641 		zval_ptr_dtor(&tmp);
1642 		tick_fe->calling = false;
1643 	}
1644 }
1645 /* }}} */
1646 
1647 static void run_user_tick_functions(int tick_count, void *arg) /* {{{ */
1648 {
1649 	zend_llist_apply(BG(user_tick_functions), (llist_apply_func_t) user_tick_function_call);
1650 }
1651 /* }}} */
1652 
1653 static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_tick_function_entry * tick_fe2) /* {{{ */
1654 {
1655 	zval *func1 = &tick_fe1->fci.function_name;
1656 	zval *func2 = &tick_fe2->fci.function_name;
1657 	int ret;
1658 
1659 	if (Z_TYPE_P(func1) == IS_STRING && Z_TYPE_P(func2) == IS_STRING) {
1660 		ret = zend_binary_zval_strcmp(func1, func2) == 0;
1661 	} else if (Z_TYPE_P(func1) == IS_ARRAY && Z_TYPE_P(func2) == IS_ARRAY) {
1662 		ret = zend_compare_arrays(func1, func2) == 0;
1663 	} else if (Z_TYPE_P(func1) == IS_OBJECT && Z_TYPE_P(func2) == IS_OBJECT) {
1664 		ret = zend_compare_objects(func1, func2) == 0;
1665 	} else {
1666 		ret = 0;
1667 	}
1668 
1669 	if (ret && tick_fe1->calling) {
1670 		zend_throw_error(NULL, "Registered tick function cannot be unregistered while it is being executed");
1671 		return 0;
1672 	}
1673 	return ret;
1674 }
1675 /* }}} */
1676 
1677 PHPAPI void php_call_shutdown_functions(void) /* {{{ */
1678 {
1679 	if (BG(user_shutdown_function_names)) {
1680 		zend_try {
1681 			zend_hash_apply(BG(user_shutdown_function_names), user_shutdown_function_call);
1682 		} zend_end_try();
1683 	}
1684 }
1685 /* }}} */
1686 
1687 PHPAPI void php_free_shutdown_functions(void) /* {{{ */
1688 {
1689 	if (BG(user_shutdown_function_names))
1690 		zend_try {
1691 			zend_hash_destroy(BG(user_shutdown_function_names));
1692 			FREE_HASHTABLE(BG(user_shutdown_function_names));
1693 			BG(user_shutdown_function_names) = NULL;
1694 		} zend_catch {
1695 			/* maybe shutdown method call exit, we just ignore it */
1696 			FREE_HASHTABLE(BG(user_shutdown_function_names));
1697 			BG(user_shutdown_function_names) = NULL;
1698 		} zend_end_try();
1699 }
1700 /* }}} */
1701 
1702 /* {{{ Register a user-level function to be called on request termination */
1703 PHP_FUNCTION(register_shutdown_function)
1704 {
1705 	php_shutdown_function_entry entry;
1706 	zval *params = NULL;
1707 	uint32_t param_count = 0;
1708 	bool status;
1709 
1710 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &entry.fci, &entry.fci_cache, &params, &param_count) == FAILURE) {
1711 		RETURN_THROWS();
1712 	}
1713 
1714 	fci_addref(&entry.fci, &entry.fci_cache);
1715 	zend_fcall_info_argp(&entry.fci, param_count, params);
1716 
1717 	status = append_user_shutdown_function(&entry);
1718 	ZEND_ASSERT(status);
1719 }
1720 /* }}} */
1721 
1722 PHPAPI bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1723 {
1724 	if (!BG(user_shutdown_function_names)) {
1725 		ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1726 		zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1727 	}
1728 
1729 	zend_hash_str_update_mem(BG(user_shutdown_function_names), function_name, function_len, shutdown_function_entry, sizeof(php_shutdown_function_entry));
1730 	return 1;
1731 }
1732 /* }}} */
1733 
1734 PHPAPI bool remove_user_shutdown_function(const char *function_name, size_t function_len) /* {{{ */
1735 {
1736 	if (BG(user_shutdown_function_names)) {
1737 		return zend_hash_str_del(BG(user_shutdown_function_names), function_name, function_len) != FAILURE;
1738 	}
1739 
1740 	return 0;
1741 }
1742 /* }}} */
1743 
1744 PHPAPI bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1745 {
1746 	if (!BG(user_shutdown_function_names)) {
1747 		ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1748 		zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1749 	}
1750 
1751 	return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL;
1752 }
1753 /* }}} */
1754 
1755 ZEND_API void php_get_highlight_struct(zend_syntax_highlighter_ini *syntax_highlighter_ini) /* {{{ */
1756 {
1757 	syntax_highlighter_ini->highlight_comment = INI_STR("highlight.comment");
1758 	syntax_highlighter_ini->highlight_default = INI_STR("highlight.default");
1759 	syntax_highlighter_ini->highlight_html    = INI_STR("highlight.html");
1760 	syntax_highlighter_ini->highlight_keyword = INI_STR("highlight.keyword");
1761 	syntax_highlighter_ini->highlight_string  = INI_STR("highlight.string");
1762 }
1763 /* }}} */
1764 
1765 /* {{{ Syntax highlight a source file */
1766 PHP_FUNCTION(highlight_file)
1767 {
1768 	char *filename;
1769 	size_t filename_len;
1770 	int ret;
1771 	zend_syntax_highlighter_ini syntax_highlighter_ini;
1772 	bool i = 0;
1773 
1774 	ZEND_PARSE_PARAMETERS_START(1, 2)
1775 		Z_PARAM_PATH(filename, filename_len)
1776 		Z_PARAM_OPTIONAL
1777 		Z_PARAM_BOOL(i)
1778 	ZEND_PARSE_PARAMETERS_END();
1779 
1780 	if (php_check_open_basedir(filename)) {
1781 		RETURN_FALSE;
1782 	}
1783 
1784 	if (i) {
1785 		php_output_start_default();
1786 	}
1787 
1788 	php_get_highlight_struct(&syntax_highlighter_ini);
1789 
1790 	ret = highlight_file(filename, &syntax_highlighter_ini);
1791 
1792 	if (ret == FAILURE) {
1793 		if (i) {
1794 			php_output_end();
1795 		}
1796 		RETURN_FALSE;
1797 	}
1798 
1799 	if (i) {
1800 		php_output_get_contents(return_value);
1801 		php_output_discard();
1802 		ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1803 	} else {
1804 		RETURN_TRUE;
1805 	}
1806 }
1807 /* }}} */
1808 
1809 /* {{{ Return source with stripped comments and whitespace */
1810 PHP_FUNCTION(php_strip_whitespace)
1811 {
1812 	zend_string *filename;
1813 	zend_lex_state original_lex_state;
1814 	zend_file_handle file_handle;
1815 
1816 	ZEND_PARSE_PARAMETERS_START(1, 1)
1817 		Z_PARAM_PATH_STR(filename)
1818 	ZEND_PARSE_PARAMETERS_END();
1819 
1820 	php_output_start_default();
1821 
1822 	zend_stream_init_filename_ex(&file_handle, filename);
1823 	zend_save_lexical_state(&original_lex_state);
1824 	if (open_file_for_scanning(&file_handle) == FAILURE) {
1825 		zend_restore_lexical_state(&original_lex_state);
1826 		php_output_end();
1827 		zend_destroy_file_handle(&file_handle);
1828 		RETURN_EMPTY_STRING();
1829 	}
1830 
1831 	zend_strip();
1832 
1833 	zend_restore_lexical_state(&original_lex_state);
1834 
1835 	php_output_get_contents(return_value);
1836 	php_output_discard();
1837 	zend_destroy_file_handle(&file_handle);
1838 }
1839 /* }}} */
1840 
1841 /* {{{ Syntax highlight a string or optionally return it */
1842 PHP_FUNCTION(highlight_string)
1843 {
1844 	zend_string *str;
1845 	zend_syntax_highlighter_ini syntax_highlighter_ini;
1846 	char *hicompiled_string_description;
1847 	bool i = 0;
1848 	int old_error_reporting = EG(error_reporting);
1849 
1850 	ZEND_PARSE_PARAMETERS_START(1, 2)
1851 		Z_PARAM_STR(str)
1852 		Z_PARAM_OPTIONAL
1853 		Z_PARAM_BOOL(i)
1854 	ZEND_PARSE_PARAMETERS_END();
1855 
1856 	if (i) {
1857 		php_output_start_default();
1858 	}
1859 
1860 	EG(error_reporting) = E_ERROR;
1861 
1862 	php_get_highlight_struct(&syntax_highlighter_ini);
1863 
1864 	hicompiled_string_description = zend_make_compiled_string_description("highlighted code");
1865 
1866 	highlight_string(str, &syntax_highlighter_ini, hicompiled_string_description);
1867 	efree(hicompiled_string_description);
1868 
1869 	EG(error_reporting) = old_error_reporting;
1870 
1871 	if (i) {
1872 		php_output_get_contents(return_value);
1873 		php_output_discard();
1874 		ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1875 	} else {
1876 		// TODO Make this function void?
1877 		RETURN_TRUE;
1878 	}
1879 }
1880 /* }}} */
1881 
1882 /* {{{ Get interpreted size from the ini shorthand syntax */
1883 PHP_FUNCTION(ini_parse_quantity)
1884 {
1885 	zend_string *shorthand;
1886 	zend_string *errstr;
1887 
1888 	ZEND_PARSE_PARAMETERS_START(1, 1)
1889 		Z_PARAM_STR(shorthand)
1890 	ZEND_PARSE_PARAMETERS_END();
1891 
1892 	RETVAL_LONG(zend_ini_parse_quantity(shorthand, &errstr));
1893 
1894 	if (errstr) {
1895 		zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
1896 		zend_string_release(errstr);
1897 	}
1898 }
1899 /* }}} */
1900 
1901 /* {{{ Get a configuration option */
1902 PHP_FUNCTION(ini_get)
1903 {
1904 	zend_string *varname, *val;
1905 
1906 	ZEND_PARSE_PARAMETERS_START(1, 1)
1907 		Z_PARAM_STR(varname)
1908 	ZEND_PARSE_PARAMETERS_END();
1909 
1910 	val = zend_ini_get_value(varname);
1911 
1912 	if (!val) {
1913 		RETURN_FALSE;
1914 	}
1915 
1916 	ZVAL_SET_INI_STR(return_value, val);
1917 }
1918 /* }}} */
1919 
1920 /* {{{ Get all configuration options */
1921 PHP_FUNCTION(ini_get_all)
1922 {
1923 	char *extname = NULL;
1924 	size_t extname_len = 0, module_number = 0;
1925 	zend_module_entry *module;
1926 	bool details = 1;
1927 	zend_string *key;
1928 	zend_ini_entry *ini_entry;
1929 
1930 
1931 	ZEND_PARSE_PARAMETERS_START(0, 2)
1932 		Z_PARAM_OPTIONAL
1933 		Z_PARAM_STRING_OR_NULL(extname, extname_len)
1934 		Z_PARAM_BOOL(details)
1935 	ZEND_PARSE_PARAMETERS_END();
1936 
1937 	zend_ini_sort_entries();
1938 
1939 	if (extname) {
1940 		if ((module = zend_hash_str_find_ptr(&module_registry, extname, extname_len)) == NULL) {
1941 			php_error_docref(NULL, E_WARNING, "Extension \"%s\" cannot be found", extname);
1942 			RETURN_FALSE;
1943 		}
1944 		module_number = module->module_number;
1945 	}
1946 
1947 	array_init(return_value);
1948 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(ini_directives), key, ini_entry) {
1949 		zval option;
1950 
1951 		if (module_number != 0 && ini_entry->module_number != module_number) {
1952 			continue;
1953 		}
1954 
1955 		if (key == NULL || ZSTR_VAL(key)[0] != 0) {
1956 			if (details) {
1957 				array_init(&option);
1958 
1959 				if (ini_entry->orig_value) {
1960 					add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->orig_value));
1961 				} else if (ini_entry->value) {
1962 					add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->value));
1963 				} else {
1964 					add_assoc_null(&option, "global_value");
1965 				}
1966 
1967 				if (ini_entry->value) {
1968 					add_assoc_str(&option, "local_value", zend_string_copy(ini_entry->value));
1969 				} else {
1970 					add_assoc_null(&option, "local_value");
1971 				}
1972 
1973 				add_assoc_long(&option, "access", ini_entry->modifiable);
1974 
1975 				zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &option);
1976 			} else {
1977 				if (ini_entry->value) {
1978 					zval zv;
1979 
1980 					ZVAL_STR_COPY(&zv, ini_entry->value);
1981 					zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &zv);
1982 				} else {
1983 					zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &EG(uninitialized_zval));
1984 				}
1985 			}
1986 		}
1987 	} ZEND_HASH_FOREACH_END();
1988 }
1989 /* }}} */
1990 
1991 static int php_ini_check_path(char *option_name, size_t option_len, char *new_option_name, size_t new_option_len) /* {{{ */
1992 {
1993 	if (option_len + 1 != new_option_len) {
1994 		return 0;
1995 	}
1996 
1997 	return !strncmp(option_name, new_option_name, option_len);
1998 }
1999 /* }}} */
2000 
2001 /* {{{ Set a configuration option, returns false on error and the old value of the configuration option on success */
2002 PHP_FUNCTION(ini_set)
2003 {
2004 	zend_string *varname;
2005 	zval *new_value;
2006 	zend_string *val;
2007 
2008 	ZEND_PARSE_PARAMETERS_START(2, 2)
2009 		Z_PARAM_STR(varname)
2010 		Z_PARAM_ZVAL(new_value)
2011 	ZEND_PARSE_PARAMETERS_END();
2012 
2013 	if (Z_TYPE_P(new_value) > IS_STRING) {
2014 		zend_argument_type_error(2, "must be of type string|int|float|bool|null");
2015 		RETURN_THROWS();
2016 	}
2017 
2018 	val = zend_ini_get_value(varname);
2019 
2020 	if (val) {
2021 		ZVAL_SET_INI_STR(return_value, val);
2022 	} else {
2023 		RETVAL_FALSE;
2024 	}
2025 
2026 	zend_string *new_value_tmp_str;
2027 	zend_string *new_value_str = zval_get_tmp_string(new_value, &new_value_tmp_str);
2028 
2029 #define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
2030 	/* open basedir check */
2031 	if (PG(open_basedir)) {
2032 		if (_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "error_log") ||
2033 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.class.path") ||
2034 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.home") ||
2035 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "mail.log") ||
2036 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.library.path") ||
2037 			_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "vpopmail.directory")) {
2038 			if (php_check_open_basedir(ZSTR_VAL(new_value_str))) {
2039 				zval_ptr_dtor_str(return_value);
2040 				zend_tmp_string_release(new_value_tmp_str);
2041 				RETURN_FALSE;
2042 			}
2043 		}
2044 	}
2045 #undef _CHECK_PATH
2046 
2047 	if (zend_alter_ini_entry_ex(varname, new_value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2048 		zval_ptr_dtor_str(return_value);
2049 		RETVAL_FALSE;
2050 	}
2051 	zend_tmp_string_release(new_value_tmp_str);
2052 }
2053 /* }}} */
2054 
2055 /* {{{ Restore the value of a configuration option specified by varname */
2056 PHP_FUNCTION(ini_restore)
2057 {
2058 	zend_string *varname;
2059 
2060 	ZEND_PARSE_PARAMETERS_START(1, 1)
2061 		Z_PARAM_STR(varname)
2062 	ZEND_PARSE_PARAMETERS_END();
2063 
2064 	zend_restore_ini_entry(varname, PHP_INI_STAGE_RUNTIME);
2065 }
2066 /* }}} */
2067 
2068 /* {{{ Sets the include_path configuration option */
2069 PHP_FUNCTION(set_include_path)
2070 {
2071 	zend_string *new_value;
2072 	char *old_value;
2073 	zend_string *key;
2074 
2075 	ZEND_PARSE_PARAMETERS_START(1, 1)
2076 		Z_PARAM_PATH_STR(new_value)
2077 	ZEND_PARSE_PARAMETERS_END();
2078 
2079 	old_value = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2080 	/* copy to return here, because alter might free it! */
2081 	if (old_value) {
2082 		RETVAL_STRING(old_value);
2083 	} else {
2084 		RETVAL_FALSE;
2085 	}
2086 
2087 	key = ZSTR_INIT_LITERAL("include_path", 0);
2088 	if (zend_alter_ini_entry_ex(key, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2089 		zend_string_release_ex(key, 0);
2090 		zval_ptr_dtor_str(return_value);
2091 		RETURN_FALSE;
2092 	}
2093 	zend_string_release_ex(key, 0);
2094 }
2095 /* }}} */
2096 
2097 /* {{{ Get the current include_path configuration option */
2098 PHP_FUNCTION(get_include_path)
2099 {
2100 	char *str;
2101 
2102 	ZEND_PARSE_PARAMETERS_NONE();
2103 
2104 	str = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2105 
2106 	if (str == NULL) {
2107 		RETURN_FALSE;
2108 	}
2109 
2110 	RETURN_STRING(str);
2111 }
2112 /* }}} */
2113 
2114 /* {{{ Prints out or returns information about the specified variable */
2115 PHP_FUNCTION(print_r)
2116 {
2117 	zval *var;
2118 	bool do_return = 0;
2119 
2120 	ZEND_PARSE_PARAMETERS_START(1, 2)
2121 		Z_PARAM_ZVAL(var)
2122 		Z_PARAM_OPTIONAL
2123 		Z_PARAM_BOOL(do_return)
2124 	ZEND_PARSE_PARAMETERS_END();
2125 
2126 	if (do_return) {
2127 		RETURN_STR(zend_print_zval_r_to_str(var, 0));
2128 	} else {
2129 		zend_print_zval_r(var, 0);
2130 		RETURN_TRUE;
2131 	}
2132 }
2133 /* }}} */
2134 
2135 /* {{{ Returns true if client disconnected */
2136 PHP_FUNCTION(connection_aborted)
2137 {
2138 	ZEND_PARSE_PARAMETERS_NONE();
2139 
2140 	RETURN_LONG(PG(connection_status) & PHP_CONNECTION_ABORTED);
2141 }
2142 /* }}} */
2143 
2144 /* {{{ Returns the connection status bitfield */
2145 PHP_FUNCTION(connection_status)
2146 {
2147 	ZEND_PARSE_PARAMETERS_NONE();
2148 
2149 	RETURN_LONG(PG(connection_status));
2150 }
2151 /* }}} */
2152 
2153 /* {{{ Set whether we want to ignore a user abort event or not */
2154 PHP_FUNCTION(ignore_user_abort)
2155 {
2156 	bool arg = 0;
2157 	bool arg_is_null = 1;
2158 	int old_setting;
2159 
2160 	ZEND_PARSE_PARAMETERS_START(0, 1)
2161 		Z_PARAM_OPTIONAL
2162 		Z_PARAM_BOOL_OR_NULL(arg, arg_is_null)
2163 	ZEND_PARSE_PARAMETERS_END();
2164 
2165 	old_setting = (unsigned short)PG(ignore_user_abort);
2166 
2167 	if (!arg_is_null) {
2168 		zend_string *key = ZSTR_INIT_LITERAL("ignore_user_abort", 0);
2169 		zend_alter_ini_entry_chars(key, arg ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2170 		zend_string_release_ex(key, 0);
2171 	}
2172 
2173 	RETURN_LONG(old_setting);
2174 }
2175 /* }}} */
2176 
2177 #ifdef HAVE_GETSERVBYNAME
2178 /* {{{ Returns port associated with service. Protocol must be "tcp" or "udp" */
2179 PHP_FUNCTION(getservbyname)
2180 {
2181 	zend_string *name;
2182 	char *proto;
2183 	size_t proto_len;
2184 	struct servent *serv;
2185 
2186 	ZEND_PARSE_PARAMETERS_START(2, 2)
2187 		Z_PARAM_STR(name)
2188 		Z_PARAM_STRING(proto, proto_len)
2189 	ZEND_PARSE_PARAMETERS_END();
2190 
2191 
2192 /* empty string behaves like NULL on windows implementation of
2193    getservbyname. Let be portable instead. */
2194 #ifdef PHP_WIN32
2195 	if (proto_len == 0) {
2196 		RETURN_FALSE;
2197 	}
2198 #endif
2199 
2200 	serv = getservbyname(ZSTR_VAL(name), proto);
2201 
2202 #ifdef _AIX
2203 	/*
2204         On AIX, imap is only known as imap2 in /etc/services, while on Linux imap is an alias for imap2.
2205         If a request for imap gives no result, we try again with imap2.
2206         */
2207 	if (serv == NULL && zend_string_equals_literal(name, "imap")) {
2208 		serv = getservbyname("imap2", proto);
2209 	}
2210 #endif
2211 	if (serv == NULL) {
2212 		RETURN_FALSE;
2213 	}
2214 
2215 	RETURN_LONG(ntohs(serv->s_port));
2216 }
2217 /* }}} */
2218 #endif
2219 
2220 #ifdef HAVE_GETSERVBYPORT
2221 /* {{{ Returns service name associated with port. Protocol must be "tcp" or "udp" */
2222 PHP_FUNCTION(getservbyport)
2223 {
2224 	char *proto;
2225 	size_t proto_len;
2226 	zend_long port;
2227 	struct servent *serv;
2228 
2229 	ZEND_PARSE_PARAMETERS_START(2, 2)
2230 		Z_PARAM_LONG(port)
2231 		Z_PARAM_STRING(proto, proto_len)
2232 	ZEND_PARSE_PARAMETERS_END();
2233 
2234 	serv = getservbyport(htons((unsigned short) port), proto);
2235 
2236 	if (serv == NULL) {
2237 		RETURN_FALSE;
2238 	}
2239 
2240 	/* MSAN false positive, getservbyport() is not properly intercepted. */
2241 #if __has_feature(memory_sanitizer)
2242 	__msan_unpoison_string(serv->s_name);
2243 #endif
2244 	RETURN_STRING(serv->s_name);
2245 }
2246 /* }}} */
2247 #endif
2248 
2249 #ifdef HAVE_GETPROTOBYNAME
2250 /* {{{ Returns protocol number associated with name as per /etc/protocols */
2251 PHP_FUNCTION(getprotobyname)
2252 {
2253 	char *name;
2254 	size_t name_len;
2255 	struct protoent *ent;
2256 
2257 	ZEND_PARSE_PARAMETERS_START(1, 1)
2258 		Z_PARAM_STRING(name, name_len)
2259 	ZEND_PARSE_PARAMETERS_END();
2260 
2261 	ent = getprotobyname(name);
2262 
2263 	if (ent == NULL) {
2264 		RETURN_FALSE;
2265 	}
2266 
2267 	RETURN_LONG(ent->p_proto);
2268 }
2269 /* }}} */
2270 #endif
2271 
2272 #ifdef HAVE_GETPROTOBYNUMBER
2273 /* {{{ Returns protocol name associated with protocol number proto */
2274 PHP_FUNCTION(getprotobynumber)
2275 {
2276 	zend_long proto;
2277 	struct protoent *ent;
2278 
2279 	ZEND_PARSE_PARAMETERS_START(1, 1)
2280 		Z_PARAM_LONG(proto)
2281 	ZEND_PARSE_PARAMETERS_END();
2282 
2283 	ent = getprotobynumber((int)proto);
2284 
2285 	if (ent == NULL) {
2286 		RETURN_FALSE;
2287 	}
2288 
2289 	RETURN_STRING(ent->p_name);
2290 }
2291 /* }}} */
2292 #endif
2293 
2294 /* {{{ Registers a tick callback function */
2295 PHP_FUNCTION(register_tick_function)
2296 {
2297 	user_tick_function_entry tick_fe;
2298 	zval *params = NULL;
2299 	uint32_t param_count = 0;
2300 
2301 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &tick_fe.fci, &tick_fe.fci_cache, &params, &param_count) == FAILURE) {
2302 		RETURN_THROWS();
2303 	}
2304 
2305 	tick_fe.calling = false;
2306 	fci_addref(&tick_fe.fci, &tick_fe.fci_cache);
2307 	zend_fcall_info_argp(&tick_fe.fci, param_count, params);
2308 
2309 	if (!BG(user_tick_functions)) {
2310 		BG(user_tick_functions) = (zend_llist *) emalloc(sizeof(zend_llist));
2311 		zend_llist_init(BG(user_tick_functions),
2312 						sizeof(user_tick_function_entry),
2313 						(llist_dtor_func_t) user_tick_function_dtor, 0);
2314 		php_add_tick_function(run_user_tick_functions, NULL);
2315 	}
2316 
2317 	zend_llist_add_element(BG(user_tick_functions), &tick_fe);
2318 
2319 	RETURN_TRUE;
2320 }
2321 /* }}} */
2322 
2323 /* {{{ Unregisters a tick callback function */
2324 PHP_FUNCTION(unregister_tick_function)
2325 {
2326 	user_tick_function_entry tick_fe;
2327 
2328 	ZEND_PARSE_PARAMETERS_START(1, 1)
2329 		Z_PARAM_FUNC(tick_fe.fci, tick_fe.fci_cache)
2330 	ZEND_PARSE_PARAMETERS_END();
2331 
2332 	if (!BG(user_tick_functions)) {
2333 		return;
2334 	}
2335 
2336 	zend_llist_del_element(BG(user_tick_functions), &tick_fe, (int (*)(void *, void *)) user_tick_function_compare);
2337 }
2338 /* }}} */
2339 
2340 /* {{{ Check if file was created by rfc1867 upload */
2341 PHP_FUNCTION(is_uploaded_file)
2342 {
2343 	char *path;
2344 	size_t path_len;
2345 
2346 	ZEND_PARSE_PARAMETERS_START(1, 1)
2347 		Z_PARAM_PATH(path, path_len)
2348 	ZEND_PARSE_PARAMETERS_END();
2349 
2350 	if (!SG(rfc1867_uploaded_files)) {
2351 		RETURN_FALSE;
2352 	}
2353 
2354 	if (zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) {
2355 		RETURN_TRUE;
2356 	} else {
2357 		RETURN_FALSE;
2358 	}
2359 }
2360 /* }}} */
2361 
2362 /* {{{ Move a file if and only if it was created by an upload */
2363 PHP_FUNCTION(move_uploaded_file)
2364 {
2365 	char *path, *new_path;
2366 	size_t path_len, new_path_len;
2367 	bool successful = 0;
2368 
2369 #ifndef PHP_WIN32
2370 	int oldmask; int ret;
2371 #endif
2372 
2373 	ZEND_PARSE_PARAMETERS_START(2, 2)
2374 		Z_PARAM_STRING(path, path_len)
2375 		Z_PARAM_PATH(new_path, new_path_len)
2376 	ZEND_PARSE_PARAMETERS_END();
2377 
2378 	if (!SG(rfc1867_uploaded_files)) {
2379 		RETURN_FALSE;
2380 	}
2381 
2382 	if (!zend_hash_str_exists(SG(rfc1867_uploaded_files), path, path_len)) {
2383 		RETURN_FALSE;
2384 	}
2385 
2386 	if (php_check_open_basedir(new_path)) {
2387 		RETURN_FALSE;
2388 	}
2389 
2390 	if (VCWD_RENAME(path, new_path) == 0) {
2391 		successful = 1;
2392 #ifndef PHP_WIN32
2393 		oldmask = umask(077);
2394 		umask(oldmask);
2395 
2396 		ret = VCWD_CHMOD(new_path, 0666 & ~oldmask);
2397 
2398 		if (ret == -1) {
2399 			php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
2400 		}
2401 #endif
2402 	} else if (php_copy_file_ex(path, new_path, STREAM_DISABLE_OPEN_BASEDIR) == SUCCESS) {
2403 		VCWD_UNLINK(path);
2404 		successful = 1;
2405 	}
2406 
2407 	if (successful) {
2408 		zend_hash_str_del(SG(rfc1867_uploaded_files), path, path_len);
2409 	} else {
2410 		php_error_docref(NULL, E_WARNING, "Unable to move \"%s\" to \"%s\"", path, new_path);
2411 	}
2412 
2413 	RETURN_BOOL(successful);
2414 }
2415 /* }}} */
2416 
2417 /* {{{ php_simple_ini_parser_cb */
2418 static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr)
2419 {
2420 	switch (callback_type) {
2421 
2422 		case ZEND_INI_PARSER_ENTRY:
2423 			if (!arg2) {
2424 				/* bare string - nothing to do */
2425 				break;
2426 			}
2427 			Z_TRY_ADDREF_P(arg2);
2428 			zend_symtable_update(Z_ARRVAL_P(arr), Z_STR_P(arg1), arg2);
2429 			break;
2430 
2431 		case ZEND_INI_PARSER_POP_ENTRY:
2432 		{
2433 			zval hash, *find_hash;
2434 
2435 			if (!arg2) {
2436 				/* bare string - nothing to do */
2437 				break;
2438 			}
2439 
2440 			/* entry in the form x[a]=b where x might need to be an array index */
2441 			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) {
2442 				zend_ulong key = (zend_ulong) ZEND_STRTOUL(Z_STRVAL_P(arg1), NULL, 0);
2443 				if ((find_hash = zend_hash_index_find(Z_ARRVAL_P(arr), key)) == NULL) {
2444 					array_init(&hash);
2445 					find_hash = zend_hash_index_add_new(Z_ARRVAL_P(arr), key, &hash);
2446 				}
2447 			} else {
2448 				if ((find_hash = zend_hash_find(Z_ARRVAL_P(arr), Z_STR_P(arg1))) == NULL) {
2449 					array_init(&hash);
2450 					find_hash = zend_hash_add_new(Z_ARRVAL_P(arr), Z_STR_P(arg1), &hash);
2451 				}
2452 			}
2453 
2454 			if (Z_TYPE_P(find_hash) != IS_ARRAY) {
2455 				zval_ptr_dtor_nogc(find_hash);
2456 				array_init(find_hash);
2457 			}
2458 
2459 			if (!arg3 || (Z_TYPE_P(arg3) == IS_STRING && Z_STRLEN_P(arg3) == 0)) {
2460 				Z_TRY_ADDREF_P(arg2);
2461 				add_next_index_zval(find_hash, arg2);
2462 			} else {
2463 				array_set_zval_key(Z_ARRVAL_P(find_hash), arg3, arg2);
2464 			}
2465 		}
2466 		break;
2467 
2468 		case ZEND_INI_PARSER_SECTION:
2469 			break;
2470 	}
2471 }
2472 /* }}} */
2473 
2474 /* {{{ php_ini_parser_cb_with_sections */
2475 static void php_ini_parser_cb_with_sections(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr)
2476 {
2477 	if (callback_type == ZEND_INI_PARSER_SECTION) {
2478 		array_init(&BG(active_ini_file_section));
2479 		zend_symtable_update(Z_ARRVAL_P(arr), Z_STR_P(arg1), &BG(active_ini_file_section));
2480 	} else if (arg2) {
2481 		zval *active_arr;
2482 
2483 		if (Z_TYPE(BG(active_ini_file_section)) != IS_UNDEF) {
2484 			active_arr = &BG(active_ini_file_section);
2485 		} else {
2486 			active_arr = arr;
2487 		}
2488 
2489 		php_simple_ini_parser_cb(arg1, arg2, arg3, callback_type, active_arr);
2490 	}
2491 }
2492 /* }}} */
2493 
2494 /* {{{ Parse configuration file */
2495 PHP_FUNCTION(parse_ini_file)
2496 {
2497 	zend_string *filename = NULL;
2498 	bool process_sections = 0;
2499 	zend_long scanner_mode = ZEND_INI_SCANNER_NORMAL;
2500 	zend_file_handle fh;
2501 	zend_ini_parser_cb_t ini_parser_cb;
2502 
2503 	ZEND_PARSE_PARAMETERS_START(1, 3)
2504 		Z_PARAM_PATH_STR(filename)
2505 		Z_PARAM_OPTIONAL
2506 		Z_PARAM_BOOL(process_sections)
2507 		Z_PARAM_LONG(scanner_mode)
2508 	ZEND_PARSE_PARAMETERS_END();
2509 
2510 	if (ZSTR_LEN(filename) == 0) {
2511 		zend_argument_must_not_be_empty_error(1);
2512 		RETURN_THROWS();
2513 	}
2514 
2515 	/* Set callback function */
2516 	if (process_sections) {
2517 		ZVAL_UNDEF(&BG(active_ini_file_section));
2518 		ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
2519 	} else {
2520 		ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
2521 	}
2522 
2523 	/* Setup filehandle */
2524 	zend_stream_init_filename_ex(&fh, filename);
2525 
2526 	array_init(return_value);
2527 	if (zend_parse_ini_file(&fh, 0, (int)scanner_mode, ini_parser_cb, return_value) == FAILURE) {
2528 		zend_array_destroy(Z_ARR_P(return_value));
2529 		RETVAL_FALSE;
2530 	}
2531 	zend_destroy_file_handle(&fh);
2532 }
2533 /* }}} */
2534 
2535 /* {{{ Parse configuration string */
2536 PHP_FUNCTION(parse_ini_string)
2537 {
2538 	char *string = NULL, *str = NULL;
2539 	size_t str_len = 0;
2540 	bool process_sections = 0;
2541 	zend_long scanner_mode = ZEND_INI_SCANNER_NORMAL;
2542 	zend_ini_parser_cb_t ini_parser_cb;
2543 
2544 	ZEND_PARSE_PARAMETERS_START(1, 3)
2545 		Z_PARAM_STRING(str, str_len)
2546 		Z_PARAM_OPTIONAL
2547 		Z_PARAM_BOOL(process_sections)
2548 		Z_PARAM_LONG(scanner_mode)
2549 	ZEND_PARSE_PARAMETERS_END();
2550 
2551 	if (INT_MAX - str_len < ZEND_MMAP_AHEAD) {
2552 		RETVAL_FALSE;
2553 	}
2554 
2555 	/* Set callback function */
2556 	if (process_sections) {
2557 		ZVAL_UNDEF(&BG(active_ini_file_section));
2558 		ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
2559 	} else {
2560 		ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
2561 	}
2562 
2563 	/* Setup string */
2564 	string = (char *) emalloc(str_len + ZEND_MMAP_AHEAD);
2565 	memcpy(string, str, str_len);
2566 	memset(string + str_len, 0, ZEND_MMAP_AHEAD);
2567 
2568 	array_init(return_value);
2569 	if (zend_parse_ini_string(string, 0, (int)scanner_mode, ini_parser_cb, return_value) == FAILURE) {
2570 		zend_array_destroy(Z_ARR_P(return_value));
2571 		RETVAL_FALSE;
2572 	}
2573 	efree(string);
2574 }
2575 /* }}} */
2576 
2577 #if ZEND_DEBUG
2578 /* This function returns an array of ALL valid ini options with values and
2579  *  is not the same as ini_get_all() which returns only registered ini options. Only useful for devs to debug php.ini scanner/parser! */
2580 PHP_FUNCTION(config_get_hash) /* {{{ */
2581 {
2582 	ZEND_PARSE_PARAMETERS_NONE();
2583 
2584 	HashTable *hash = php_ini_get_configuration_hash();
2585 
2586 	array_init(return_value);
2587 	add_config_entries(hash, return_value);
2588 }
2589 /* }}} */
2590 #endif
2591 
2592 #ifdef HAVE_GETLOADAVG
2593 /* {{{ */
2594 PHP_FUNCTION(sys_getloadavg)
2595 {
2596 	double load[3];
2597 
2598 	ZEND_PARSE_PARAMETERS_NONE();
2599 
2600 	if (getloadavg(load, 3) == -1) {
2601 		RETURN_FALSE;
2602 	} else {
2603 		array_init(return_value);
2604 		add_index_double(return_value, 0, load[0]);
2605 		add_index_double(return_value, 1, load[1]);
2606 		add_index_double(return_value, 2, load[2]);
2607 	}
2608 }
2609 /* }}} */
2610 #endif
2611