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