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