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