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