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