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