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