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