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