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