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 MSAN_UNPOISON(php_rem);
1186 add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
1187 add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
1188 return;
1189 } else if (errno == EINVAL) {
1190 zend_value_error("Nanoseconds was not in the range 0 to 999 999 999 or seconds was negative");
1191 RETURN_THROWS();
1192 }
1193
1194 RETURN_FALSE;
1195 }
1196 /* }}} */
1197
1198 /* {{{ Make the script sleep until the specified time */
1199 PHP_FUNCTION(time_sleep_until)
1200 {
1201 double target_secs;
1202 struct timeval tm;
1203 struct timespec php_req, php_rem;
1204 uint64_t current_ns, target_ns, diff_ns;
1205 const uint64_t ns_per_sec = 1000000000;
1206 const double top_target_sec = (double)(UINT64_MAX / ns_per_sec);
1207
1208 ZEND_PARSE_PARAMETERS_START(1, 1)
1209 Z_PARAM_DOUBLE(target_secs)
1210 ZEND_PARSE_PARAMETERS_END();
1211
1212 if (gettimeofday((struct timeval *) &tm, NULL) != 0) {
1213 RETURN_FALSE;
1214 }
1215
1216 if (UNEXPECTED(!(target_secs >= 0 && target_secs <= top_target_sec))) {
1217 zend_argument_value_error(1, "must be between 0 and %" PRIu64, (uint64_t)top_target_sec);
1218 RETURN_THROWS();
1219 }
1220
1221 target_ns = (uint64_t) (target_secs * ns_per_sec);
1222 current_ns = ((uint64_t) tm.tv_sec) * ns_per_sec + ((uint64_t) tm.tv_usec) * 1000;
1223 if (target_ns < current_ns) {
1224 php_error_docref(NULL, E_WARNING, "Argument #1 ($timestamp) must be greater than or equal to the current time");
1225 RETURN_FALSE;
1226 }
1227
1228 diff_ns = target_ns - current_ns;
1229 php_req.tv_sec = (time_t) (diff_ns / ns_per_sec);
1230 php_req.tv_nsec = (long) (diff_ns % ns_per_sec);
1231
1232 while (nanosleep(&php_req, &php_rem)) {
1233 if (errno == EINTR) {
1234 php_req.tv_sec = php_rem.tv_sec;
1235 php_req.tv_nsec = php_rem.tv_nsec;
1236 } else {
1237 RETURN_FALSE;
1238 }
1239 }
1240
1241 RETURN_TRUE;
1242 }
1243 /* }}} */
1244 #endif
1245
1246 /* {{{ Get the name of the owner of the current PHP script */
1247 PHP_FUNCTION(get_current_user)
1248 {
1249 ZEND_PARSE_PARAMETERS_NONE();
1250
1251 RETURN_STRING(php_get_current_user());
1252 }
1253 /* }}} */
1254
1255 #define ZVAL_SET_INI_STR(zv, val) do { \
1256 if (ZSTR_IS_INTERNED(val)) { \
1257 ZVAL_INTERNED_STR(zv, val); \
1258 } else if (ZSTR_LEN(val) == 0) { \
1259 ZVAL_EMPTY_STRING(zv); \
1260 } else if (ZSTR_LEN(val) == 1) { \
1261 ZVAL_CHAR(zv, ZSTR_VAL(val)[0]); \
1262 } else if (!(GC_FLAGS(val) & GC_PERSISTENT)) { \
1263 ZVAL_NEW_STR(zv, zend_string_copy(val)); \
1264 } else { \
1265 ZVAL_NEW_STR(zv, zend_string_init(ZSTR_VAL(val), ZSTR_LEN(val), 0)); \
1266 } \
1267 } while (0)
1268
1269 static void add_config_entries(HashTable *hash, zval *return_value);
1270
1271 /* {{{ add_config_entry */
1272 static void add_config_entry(zend_ulong h, zend_string *key, zval *entry, zval *retval)
1273 {
1274 if (Z_TYPE_P(entry) == IS_STRING) {
1275 zval str_zv;
1276 ZVAL_SET_INI_STR(&str_zv, Z_STR_P(entry));
1277 if (key) {
1278 add_assoc_zval_ex(retval, ZSTR_VAL(key), ZSTR_LEN(key), &str_zv);
1279 } else {
1280 add_index_zval(retval, h, &str_zv);
1281 }
1282 } else if (Z_TYPE_P(entry) == IS_ARRAY) {
1283 zval tmp;
1284 array_init(&tmp);
1285 add_config_entries(Z_ARRVAL_P(entry), &tmp);
1286 zend_hash_update(Z_ARRVAL_P(retval), key, &tmp);
1287 }
1288 }
1289 /* }}} */
1290
1291 /* {{{ add_config_entries */
1292 static void add_config_entries(HashTable *hash, zval *return_value) /* {{{ */
1293 {
1294 zend_ulong h;
1295 zend_string *key;
1296 zval *zv;
1297
1298 ZEND_HASH_FOREACH_KEY_VAL(hash, h, key, zv)
1299 add_config_entry(h, key, zv, return_value);
1300 ZEND_HASH_FOREACH_END();
1301 }
1302 /* }}} */
1303
1304 /* {{{ Get the value of a PHP configuration option */
1305 PHP_FUNCTION(get_cfg_var)
1306 {
1307 zend_string *varname;
1308
1309 ZEND_PARSE_PARAMETERS_START(1, 1)
1310 Z_PARAM_STR(varname)
1311 ZEND_PARSE_PARAMETERS_END();
1312
1313 zval *retval = cfg_get_entry_ex(varname);
1314
1315 if (retval) {
1316 if (Z_TYPE_P(retval) == IS_ARRAY) {
1317 array_init(return_value);
1318 add_config_entries(Z_ARRVAL_P(retval), return_value);
1319 return;
1320 } else {
1321 ZVAL_SET_INI_STR(return_value, Z_STR_P(retval));
1322 }
1323 } else {
1324 RETURN_FALSE;
1325 }
1326 }
1327 /* }}} */
1328
1329 /*
1330 1st arg = error message
1331 2nd arg = error option
1332 3rd arg = optional parameters (email address or tcp address)
1333 4th arg = used for additional headers if email
1334
1335 error options:
1336 0 = send to php_error_log (uses syslog or file depending on ini setting)
1337 1 = send via email to 3rd parameter 4th option = additional headers
1338 2 = send via tcp/ip to 3rd parameter (name or ip:port)
1339 3 = save to file in 3rd parameter
1340 4 = send to SAPI logger directly
1341 */
1342
1343 /* {{{ Send an error message somewhere */
1344 PHP_FUNCTION(error_log)
1345 {
1346 char *message, *opt = NULL, *headers = NULL;
1347 size_t message_len, opt_len = 0, headers_len = 0;
1348 zend_long erropt = 0;
1349
1350 ZEND_PARSE_PARAMETERS_START(1, 4)
1351 Z_PARAM_STRING(message, message_len)
1352 Z_PARAM_OPTIONAL
1353 Z_PARAM_LONG(erropt)
1354 Z_PARAM_PATH_OR_NULL(opt, opt_len)
1355 Z_PARAM_STRING_OR_NULL(headers, headers_len)
1356 ZEND_PARSE_PARAMETERS_END();
1357
1358 if (_php_error_log_ex((int) erropt, message, message_len, opt, headers) == FAILURE) {
1359 RETURN_FALSE;
1360 }
1361
1362 RETURN_TRUE;
1363 }
1364 /* }}} */
1365
1366 /* For BC (not binary-safe!) */
1367 PHPAPI int _php_error_log(int opt_err, const char *message, const char *opt, const char *headers) /* {{{ */
1368 {
1369 return _php_error_log_ex(opt_err, message, (opt_err == 3) ? strlen(message) : 0, opt, headers);
1370 }
1371 /* }}} */
1372
1373 PHPAPI int _php_error_log_ex(int opt_err, const char *message, size_t message_len, const char *opt, const char *headers) /* {{{ */
1374 {
1375 php_stream *stream = NULL;
1376 size_t nbytes;
1377
1378 switch (opt_err)
1379 {
1380 case 1: /*send an email */
1381 if (!php_mail(opt, "PHP error_log message", message, headers, NULL)) {
1382 return FAILURE;
1383 }
1384 break;
1385
1386 case 2: /*send to an address */
1387 zend_value_error("TCP/IP option is not available for error logging");
1388 return FAILURE;
1389
1390 case 3: /*save to a file */
1391 stream = php_stream_open_wrapper(opt, "a", REPORT_ERRORS, NULL);
1392 if (!stream) {
1393 return FAILURE;
1394 }
1395 nbytes = php_stream_write(stream, message, message_len);
1396 php_stream_close(stream);
1397 if (nbytes != message_len) {
1398 return FAILURE;
1399 }
1400 break;
1401
1402 case 4: /* send to SAPI */
1403 if (sapi_module.log_message) {
1404 sapi_module.log_message(message, -1);
1405 } else {
1406 return FAILURE;
1407 }
1408 break;
1409
1410 default:
1411 php_log_err_with_severity(message, LOG_NOTICE);
1412 break;
1413 }
1414 return SUCCESS;
1415 }
1416 /* }}} */
1417
1418 /* {{{ Get the last occurred error as associative array. Returns NULL if there hasn't been an error yet. */
1419 PHP_FUNCTION(error_get_last)
1420 {
1421 ZEND_PARSE_PARAMETERS_NONE();
1422
1423 if (PG(last_error_message)) {
1424 zval tmp;
1425 array_init(return_value);
1426
1427 ZVAL_LONG(&tmp, PG(last_error_type));
1428 zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_TYPE), &tmp);
1429
1430 ZVAL_STR_COPY(&tmp, PG(last_error_message));
1431 zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
1432
1433 ZVAL_STR_COPY(&tmp, PG(last_error_file));
1434 zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
1435
1436 ZVAL_LONG(&tmp, PG(last_error_lineno));
1437 zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
1438 }
1439 }
1440 /* }}} */
1441
1442 /* {{{ Clear the last occurred error. */
1443 PHP_FUNCTION(error_clear_last)
1444 {
1445 ZEND_PARSE_PARAMETERS_NONE();
1446
1447 if (PG(last_error_message)) {
1448 PG(last_error_type) = 0;
1449 PG(last_error_lineno) = 0;
1450
1451 zend_string_release(PG(last_error_message));
1452 PG(last_error_message) = NULL;
1453
1454 if (PG(last_error_file)) {
1455 zend_string_release(PG(last_error_file));
1456 PG(last_error_file) = NULL;
1457 }
1458 }
1459 }
1460 /* }}} */
1461
1462 /* {{{ Call a user function which is the first parameter
1463 Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1464 PHP_FUNCTION(call_user_func)
1465 {
1466 zval retval;
1467 zend_fcall_info fci;
1468 zend_fcall_info_cache fci_cache;
1469
1470 ZEND_PARSE_PARAMETERS_START(1, -1)
1471 Z_PARAM_FUNC(fci, fci_cache)
1472 Z_PARAM_VARIADIC_WITH_NAMED(fci.params, fci.param_count, fci.named_params)
1473 ZEND_PARSE_PARAMETERS_END();
1474
1475 fci.retval = &retval;
1476
1477 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1478 if (Z_ISREF(retval)) {
1479 zend_unwrap_reference(&retval);
1480 }
1481 ZVAL_COPY_VALUE(return_value, &retval);
1482 }
1483 }
1484 /* }}} */
1485
1486 /* {{{ Call a user function which is the first parameter with the arguments contained in array
1487 Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
1488 PHP_FUNCTION(call_user_func_array)
1489 {
1490 zval retval;
1491 HashTable *params;
1492 zend_fcall_info fci;
1493 zend_fcall_info_cache fci_cache;
1494
1495 ZEND_PARSE_PARAMETERS_START(2, 2)
1496 Z_PARAM_FUNC(fci, fci_cache)
1497 Z_PARAM_ARRAY_HT(params)
1498 ZEND_PARSE_PARAMETERS_END();
1499
1500 fci.named_params = params;
1501 fci.retval = &retval;
1502
1503 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1504 if (Z_ISREF(retval)) {
1505 zend_unwrap_reference(&retval);
1506 }
1507 ZVAL_COPY_VALUE(return_value, &retval);
1508 }
1509 }
1510 /* }}} */
1511
1512 /* {{{ Call a user function which is the first parameter */
1513 PHP_FUNCTION(forward_static_call)
1514 {
1515 zval retval;
1516 zend_fcall_info fci;
1517 zend_fcall_info_cache fci_cache;
1518 zend_class_entry *called_scope;
1519
1520 ZEND_PARSE_PARAMETERS_START(1, -1)
1521 Z_PARAM_FUNC(fci, fci_cache)
1522 Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
1523 ZEND_PARSE_PARAMETERS_END();
1524
1525 if (!EX(prev_execute_data) || !EX(prev_execute_data)->func->common.scope) {
1526 zend_throw_error(NULL, "Cannot call forward_static_call() when no class scope is active");
1527 RETURN_THROWS();
1528 }
1529
1530 fci.retval = &retval;
1531
1532 called_scope = zend_get_called_scope(execute_data);
1533 if (called_scope && fci_cache.calling_scope &&
1534 instanceof_function(called_scope, fci_cache.calling_scope)) {
1535 fci_cache.called_scope = called_scope;
1536 }
1537
1538 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1539 if (Z_ISREF(retval)) {
1540 zend_unwrap_reference(&retval);
1541 }
1542 ZVAL_COPY_VALUE(return_value, &retval);
1543 }
1544 }
1545 /* }}} */
1546
1547 /* {{{ Call a static method which is the first parameter with the arguments contained in array */
1548 PHP_FUNCTION(forward_static_call_array)
1549 {
1550 zval retval;
1551 HashTable *params;
1552 zend_fcall_info fci;
1553 zend_fcall_info_cache fci_cache;
1554 zend_class_entry *called_scope;
1555
1556 ZEND_PARSE_PARAMETERS_START(2, 2)
1557 Z_PARAM_FUNC(fci, fci_cache)
1558 Z_PARAM_ARRAY_HT(params)
1559 ZEND_PARSE_PARAMETERS_END();
1560
1561 fci.retval = &retval;
1562 /* Add positional arguments */
1563 fci.named_params = params;
1564
1565 called_scope = zend_get_called_scope(execute_data);
1566 if (called_scope && fci_cache.calling_scope &&
1567 instanceof_function(called_scope, fci_cache.calling_scope)) {
1568 fci_cache.called_scope = called_scope;
1569 }
1570
1571 if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
1572 if (Z_ISREF(retval)) {
1573 zend_unwrap_reference(&retval);
1574 }
1575 ZVAL_COPY_VALUE(return_value, &retval);
1576 }
1577 }
1578 /* }}} */
1579
1580 static void fci_addref(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1581 {
1582 Z_TRY_ADDREF(fci->function_name);
1583 if (fci_cache->object) {
1584 GC_ADDREF(fci_cache->object);
1585 }
1586 }
1587
1588 static void fci_release(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
1589 {
1590 zval_ptr_dtor(&fci->function_name);
1591 if (fci_cache->object) {
1592 zend_object_release(fci_cache->object);
1593 }
1594 }
1595
1596 void user_shutdown_function_dtor(zval *zv) /* {{{ */
1597 {
1598 php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1599
1600 zend_fcall_info_args_clear(&shutdown_function_entry->fci, true);
1601 fci_release(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1602 efree(shutdown_function_entry);
1603 }
1604 /* }}} */
1605
1606 void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
1607 {
1608 zend_fcall_info_args_clear(&tick_function_entry->fci, true);
1609 fci_release(&tick_function_entry->fci, &tick_function_entry->fci_cache);
1610 }
1611 /* }}} */
1612
1613 static int user_shutdown_function_call(zval *zv) /* {{{ */
1614 {
1615 php_shutdown_function_entry *shutdown_function_entry = Z_PTR_P(zv);
1616 zval retval;
1617 zend_result call_status;
1618
1619 /* set retval zval for FCI struct */
1620 shutdown_function_entry->fci.retval = &retval;
1621 call_status = zend_call_function(&shutdown_function_entry->fci, &shutdown_function_entry->fci_cache);
1622 ZEND_ASSERT(call_status == SUCCESS);
1623 zval_ptr_dtor(&retval);
1624
1625 return 0;
1626 }
1627 /* }}} */
1628
1629 static void user_tick_function_call(user_tick_function_entry *tick_fe) /* {{{ */
1630 {
1631 /* Prevent re-entrant calls to the same user ticks function */
1632 if (!tick_fe->calling) {
1633 zval tmp;
1634
1635 /* set tmp zval */
1636 tick_fe->fci.retval = &tmp;
1637
1638 tick_fe->calling = true;
1639 zend_call_function(&tick_fe->fci, &tick_fe->fci_cache);
1640
1641 /* Destroy return value */
1642 zval_ptr_dtor(&tmp);
1643 tick_fe->calling = false;
1644 }
1645 }
1646 /* }}} */
1647
1648 static void run_user_tick_functions(int tick_count, void *arg) /* {{{ */
1649 {
1650 zend_llist_apply(BG(user_tick_functions), (llist_apply_func_t) user_tick_function_call);
1651 }
1652 /* }}} */
1653
1654 static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_tick_function_entry * tick_fe2) /* {{{ */
1655 {
1656 zval *func1 = &tick_fe1->fci.function_name;
1657 zval *func2 = &tick_fe2->fci.function_name;
1658 int ret;
1659
1660 if (Z_TYPE_P(func1) == IS_STRING && Z_TYPE_P(func2) == IS_STRING) {
1661 ret = zend_binary_zval_strcmp(func1, func2) == 0;
1662 } else if (Z_TYPE_P(func1) == IS_ARRAY && Z_TYPE_P(func2) == IS_ARRAY) {
1663 ret = zend_compare_arrays(func1, func2) == 0;
1664 } else if (Z_TYPE_P(func1) == IS_OBJECT && Z_TYPE_P(func2) == IS_OBJECT) {
1665 ret = zend_compare_objects(func1, func2) == 0;
1666 } else {
1667 ret = 0;
1668 }
1669
1670 if (ret && tick_fe1->calling) {
1671 zend_throw_error(NULL, "Registered tick function cannot be unregistered while it is being executed");
1672 return 0;
1673 }
1674 return ret;
1675 }
1676 /* }}} */
1677
1678 PHPAPI void php_call_shutdown_functions(void) /* {{{ */
1679 {
1680 if (BG(user_shutdown_function_names)) {
1681 zend_try {
1682 zend_hash_apply(BG(user_shutdown_function_names), user_shutdown_function_call);
1683 } zend_end_try();
1684 }
1685 }
1686 /* }}} */
1687
1688 PHPAPI void php_free_shutdown_functions(void) /* {{{ */
1689 {
1690 if (BG(user_shutdown_function_names))
1691 zend_try {
1692 zend_hash_destroy(BG(user_shutdown_function_names));
1693 FREE_HASHTABLE(BG(user_shutdown_function_names));
1694 BG(user_shutdown_function_names) = NULL;
1695 } zend_catch {
1696 /* maybe shutdown method call exit, we just ignore it */
1697 FREE_HASHTABLE(BG(user_shutdown_function_names));
1698 BG(user_shutdown_function_names) = NULL;
1699 } zend_end_try();
1700 }
1701 /* }}} */
1702
1703 /* {{{ Register a user-level function to be called on request termination */
1704 PHP_FUNCTION(register_shutdown_function)
1705 {
1706 php_shutdown_function_entry entry;
1707 zval *params = NULL;
1708 uint32_t param_count = 0;
1709 bool status;
1710
1711 if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &entry.fci, &entry.fci_cache, ¶ms, ¶m_count) == FAILURE) {
1712 RETURN_THROWS();
1713 }
1714
1715 fci_addref(&entry.fci, &entry.fci_cache);
1716 zend_fcall_info_argp(&entry.fci, param_count, params);
1717
1718 status = append_user_shutdown_function(&entry);
1719 ZEND_ASSERT(status);
1720 }
1721 /* }}} */
1722
1723 PHPAPI bool register_user_shutdown_function(const char *function_name, size_t function_len, php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1724 {
1725 if (!BG(user_shutdown_function_names)) {
1726 ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1727 zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1728 }
1729
1730 zend_hash_str_update_mem(BG(user_shutdown_function_names), function_name, function_len, shutdown_function_entry, sizeof(php_shutdown_function_entry));
1731 return 1;
1732 }
1733 /* }}} */
1734
1735 PHPAPI bool remove_user_shutdown_function(const char *function_name, size_t function_len) /* {{{ */
1736 {
1737 if (BG(user_shutdown_function_names)) {
1738 return zend_hash_str_del(BG(user_shutdown_function_names), function_name, function_len) != FAILURE;
1739 }
1740
1741 return 0;
1742 }
1743 /* }}} */
1744
1745 PHPAPI bool append_user_shutdown_function(php_shutdown_function_entry *shutdown_function_entry) /* {{{ */
1746 {
1747 if (!BG(user_shutdown_function_names)) {
1748 ALLOC_HASHTABLE(BG(user_shutdown_function_names));
1749 zend_hash_init(BG(user_shutdown_function_names), 0, NULL, user_shutdown_function_dtor, 0);
1750 }
1751
1752 return zend_hash_next_index_insert_mem(BG(user_shutdown_function_names), shutdown_function_entry, sizeof(php_shutdown_function_entry)) != NULL;
1753 }
1754 /* }}} */
1755
1756 ZEND_API void php_get_highlight_struct(zend_syntax_highlighter_ini *syntax_highlighter_ini) /* {{{ */
1757 {
1758 syntax_highlighter_ini->highlight_comment = INI_STR("highlight.comment");
1759 syntax_highlighter_ini->highlight_default = INI_STR("highlight.default");
1760 syntax_highlighter_ini->highlight_html = INI_STR("highlight.html");
1761 syntax_highlighter_ini->highlight_keyword = INI_STR("highlight.keyword");
1762 syntax_highlighter_ini->highlight_string = INI_STR("highlight.string");
1763 }
1764 /* }}} */
1765
1766 /* {{{ Syntax highlight a source file */
1767 PHP_FUNCTION(highlight_file)
1768 {
1769 char *filename;
1770 size_t filename_len;
1771 int ret;
1772 zend_syntax_highlighter_ini syntax_highlighter_ini;
1773 bool i = 0;
1774
1775 ZEND_PARSE_PARAMETERS_START(1, 2)
1776 Z_PARAM_PATH(filename, filename_len)
1777 Z_PARAM_OPTIONAL
1778 Z_PARAM_BOOL(i)
1779 ZEND_PARSE_PARAMETERS_END();
1780
1781 if (php_check_open_basedir(filename)) {
1782 RETURN_FALSE;
1783 }
1784
1785 if (i) {
1786 php_output_start_default();
1787 }
1788
1789 php_get_highlight_struct(&syntax_highlighter_ini);
1790
1791 ret = highlight_file(filename, &syntax_highlighter_ini);
1792
1793 if (ret == FAILURE) {
1794 if (i) {
1795 php_output_end();
1796 }
1797 RETURN_FALSE;
1798 }
1799
1800 if (i) {
1801 php_output_get_contents(return_value);
1802 php_output_discard();
1803 ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1804 } else {
1805 RETURN_TRUE;
1806 }
1807 }
1808 /* }}} */
1809
1810 /* {{{ Return source with stripped comments and whitespace */
1811 PHP_FUNCTION(php_strip_whitespace)
1812 {
1813 zend_string *filename;
1814 zend_lex_state original_lex_state;
1815 zend_file_handle file_handle;
1816
1817 ZEND_PARSE_PARAMETERS_START(1, 1)
1818 Z_PARAM_PATH_STR(filename)
1819 ZEND_PARSE_PARAMETERS_END();
1820
1821 php_output_start_default();
1822
1823 zend_stream_init_filename_ex(&file_handle, filename);
1824 zend_save_lexical_state(&original_lex_state);
1825 if (open_file_for_scanning(&file_handle) == FAILURE) {
1826 zend_restore_lexical_state(&original_lex_state);
1827 php_output_end();
1828 zend_destroy_file_handle(&file_handle);
1829 RETURN_EMPTY_STRING();
1830 }
1831
1832 zend_strip();
1833
1834 zend_restore_lexical_state(&original_lex_state);
1835
1836 php_output_get_contents(return_value);
1837 php_output_discard();
1838 zend_destroy_file_handle(&file_handle);
1839 }
1840 /* }}} */
1841
1842 /* {{{ Syntax highlight a string or optionally return it */
1843 PHP_FUNCTION(highlight_string)
1844 {
1845 zend_string *str;
1846 zend_syntax_highlighter_ini syntax_highlighter_ini;
1847 char *hicompiled_string_description;
1848 bool i = 0;
1849 int old_error_reporting = EG(error_reporting);
1850
1851 ZEND_PARSE_PARAMETERS_START(1, 2)
1852 Z_PARAM_STR(str)
1853 Z_PARAM_OPTIONAL
1854 Z_PARAM_BOOL(i)
1855 ZEND_PARSE_PARAMETERS_END();
1856
1857 if (i) {
1858 php_output_start_default();
1859 }
1860
1861 EG(error_reporting) = E_ERROR;
1862
1863 php_get_highlight_struct(&syntax_highlighter_ini);
1864
1865 hicompiled_string_description = zend_make_compiled_string_description("highlighted code");
1866
1867 highlight_string(str, &syntax_highlighter_ini, hicompiled_string_description);
1868 efree(hicompiled_string_description);
1869
1870 EG(error_reporting) = old_error_reporting;
1871
1872 if (i) {
1873 php_output_get_contents(return_value);
1874 php_output_discard();
1875 ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
1876 } else {
1877 // TODO Make this function void?
1878 RETURN_TRUE;
1879 }
1880 }
1881 /* }}} */
1882
1883 /* {{{ Get interpreted size from the ini shorthand syntax */
1884 PHP_FUNCTION(ini_parse_quantity)
1885 {
1886 zend_string *shorthand;
1887 zend_string *errstr;
1888
1889 ZEND_PARSE_PARAMETERS_START(1, 1)
1890 Z_PARAM_STR(shorthand)
1891 ZEND_PARSE_PARAMETERS_END();
1892
1893 RETVAL_LONG(zend_ini_parse_quantity(shorthand, &errstr));
1894
1895 if (errstr) {
1896 zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
1897 zend_string_release(errstr);
1898 }
1899 }
1900 /* }}} */
1901
1902 /* {{{ Get a configuration option */
1903 PHP_FUNCTION(ini_get)
1904 {
1905 zend_string *varname, *val;
1906
1907 ZEND_PARSE_PARAMETERS_START(1, 1)
1908 Z_PARAM_STR(varname)
1909 ZEND_PARSE_PARAMETERS_END();
1910
1911 val = zend_ini_get_value(varname);
1912
1913 if (!val) {
1914 RETURN_FALSE;
1915 }
1916
1917 ZVAL_SET_INI_STR(return_value, val);
1918 }
1919 /* }}} */
1920
1921 /* {{{ Get all configuration options */
1922 PHP_FUNCTION(ini_get_all)
1923 {
1924 char *extname = NULL;
1925 size_t extname_len = 0, module_number = 0;
1926 zend_module_entry *module;
1927 bool details = 1;
1928 zend_string *key;
1929 zend_ini_entry *ini_entry;
1930
1931
1932 ZEND_PARSE_PARAMETERS_START(0, 2)
1933 Z_PARAM_OPTIONAL
1934 Z_PARAM_STRING_OR_NULL(extname, extname_len)
1935 Z_PARAM_BOOL(details)
1936 ZEND_PARSE_PARAMETERS_END();
1937
1938 zend_ini_sort_entries();
1939
1940 if (extname) {
1941 if ((module = zend_hash_str_find_ptr(&module_registry, extname, extname_len)) == NULL) {
1942 php_error_docref(NULL, E_WARNING, "Extension \"%s\" cannot be found", extname);
1943 RETURN_FALSE;
1944 }
1945 module_number = module->module_number;
1946 }
1947
1948 array_init(return_value);
1949 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(ini_directives), key, ini_entry) {
1950 zval option;
1951
1952 if (module_number != 0 && ini_entry->module_number != module_number) {
1953 continue;
1954 }
1955
1956 if (key == NULL || ZSTR_VAL(key)[0] != 0) {
1957 if (details) {
1958 array_init(&option);
1959
1960 if (ini_entry->orig_value) {
1961 add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->orig_value));
1962 } else if (ini_entry->value) {
1963 add_assoc_str(&option, "global_value", zend_string_copy(ini_entry->value));
1964 } else {
1965 add_assoc_null(&option, "global_value");
1966 }
1967
1968 if (ini_entry->value) {
1969 add_assoc_str(&option, "local_value", zend_string_copy(ini_entry->value));
1970 } else {
1971 add_assoc_null(&option, "local_value");
1972 }
1973
1974 add_assoc_long(&option, "access", ini_entry->modifiable);
1975
1976 zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &option);
1977 } else {
1978 if (ini_entry->value) {
1979 zval zv;
1980
1981 ZVAL_STR_COPY(&zv, ini_entry->value);
1982 zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &zv);
1983 } else {
1984 zend_symtable_update(Z_ARRVAL_P(return_value), ini_entry->name, &EG(uninitialized_zval));
1985 }
1986 }
1987 }
1988 } ZEND_HASH_FOREACH_END();
1989 }
1990 /* }}} */
1991
1992 static int php_ini_check_path(char *option_name, size_t option_len, char *new_option_name, size_t new_option_len) /* {{{ */
1993 {
1994 if (option_len + 1 != new_option_len) {
1995 return 0;
1996 }
1997
1998 return !strncmp(option_name, new_option_name, option_len);
1999 }
2000 /* }}} */
2001
2002 /* {{{ Set a configuration option, returns false on error and the old value of the configuration option on success */
2003 PHP_FUNCTION(ini_set)
2004 {
2005 zend_string *varname;
2006 zval *new_value;
2007 zend_string *val;
2008
2009 ZEND_PARSE_PARAMETERS_START(2, 2)
2010 Z_PARAM_STR(varname)
2011 Z_PARAM_ZVAL(new_value)
2012 ZEND_PARSE_PARAMETERS_END();
2013
2014 if (Z_TYPE_P(new_value) > IS_STRING) {
2015 zend_argument_type_error(2, "must be of type string|int|float|bool|null");
2016 RETURN_THROWS();
2017 }
2018
2019 val = zend_ini_get_value(varname);
2020
2021 if (val) {
2022 ZVAL_SET_INI_STR(return_value, val);
2023 } else {
2024 RETVAL_FALSE;
2025 }
2026
2027 zend_string *new_value_tmp_str;
2028 zend_string *new_value_str = zval_get_tmp_string(new_value, &new_value_tmp_str);
2029
2030 #define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
2031 /* open basedir check */
2032 if (PG(open_basedir)) {
2033 if (_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "error_log") ||
2034 _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.class.path") ||
2035 _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.home") ||
2036 _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "mail.log") ||
2037 _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.library.path") ||
2038 _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "vpopmail.directory")) {
2039 if (php_check_open_basedir(ZSTR_VAL(new_value_str))) {
2040 zval_ptr_dtor_str(return_value);
2041 zend_tmp_string_release(new_value_tmp_str);
2042 RETURN_FALSE;
2043 }
2044 }
2045 }
2046 #undef _CHECK_PATH
2047
2048 if (zend_alter_ini_entry_ex(varname, new_value_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2049 zval_ptr_dtor_str(return_value);
2050 RETVAL_FALSE;
2051 }
2052 zend_tmp_string_release(new_value_tmp_str);
2053 }
2054 /* }}} */
2055
2056 /* {{{ Restore the value of a configuration option specified by varname */
2057 PHP_FUNCTION(ini_restore)
2058 {
2059 zend_string *varname;
2060
2061 ZEND_PARSE_PARAMETERS_START(1, 1)
2062 Z_PARAM_STR(varname)
2063 ZEND_PARSE_PARAMETERS_END();
2064
2065 zend_restore_ini_entry(varname, PHP_INI_STAGE_RUNTIME);
2066 }
2067 /* }}} */
2068
2069 /* {{{ Sets the include_path configuration option */
2070 PHP_FUNCTION(set_include_path)
2071 {
2072 zend_string *new_value;
2073 char *old_value;
2074 zend_string *key;
2075
2076 ZEND_PARSE_PARAMETERS_START(1, 1)
2077 Z_PARAM_PATH_STR(new_value)
2078 ZEND_PARSE_PARAMETERS_END();
2079
2080 old_value = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2081 /* copy to return here, because alter might free it! */
2082 if (old_value) {
2083 RETVAL_STRING(old_value);
2084 } else {
2085 RETVAL_FALSE;
2086 }
2087
2088 key = ZSTR_INIT_LITERAL("include_path", 0);
2089 if (zend_alter_ini_entry_ex(key, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0) == FAILURE) {
2090 zend_string_release_ex(key, 0);
2091 zval_ptr_dtor_str(return_value);
2092 RETURN_FALSE;
2093 }
2094 zend_string_release_ex(key, 0);
2095 }
2096 /* }}} */
2097
2098 /* {{{ Get the current include_path configuration option */
2099 PHP_FUNCTION(get_include_path)
2100 {
2101 char *str;
2102
2103 ZEND_PARSE_PARAMETERS_NONE();
2104
2105 str = zend_ini_string("include_path", sizeof("include_path") - 1, 0);
2106
2107 if (str == NULL) {
2108 RETURN_FALSE;
2109 }
2110
2111 RETURN_STRING(str);
2112 }
2113 /* }}} */
2114
2115 /* {{{ Prints out or returns information about the specified variable */
2116 PHP_FUNCTION(print_r)
2117 {
2118 zval *var;
2119 bool do_return = 0;
2120
2121 ZEND_PARSE_PARAMETERS_START(1, 2)
2122 Z_PARAM_ZVAL(var)
2123 Z_PARAM_OPTIONAL
2124 Z_PARAM_BOOL(do_return)
2125 ZEND_PARSE_PARAMETERS_END();
2126
2127 if (do_return) {
2128 RETURN_STR(zend_print_zval_r_to_str(var, 0));
2129 } else {
2130 zend_print_zval_r(var, 0);
2131 RETURN_TRUE;
2132 }
2133 }
2134 /* }}} */
2135
2136 /* {{{ Returns true if client disconnected */
2137 PHP_FUNCTION(connection_aborted)
2138 {
2139 ZEND_PARSE_PARAMETERS_NONE();
2140
2141 RETURN_LONG(PG(connection_status) & PHP_CONNECTION_ABORTED);
2142 }
2143 /* }}} */
2144
2145 /* {{{ Returns the connection status bitfield */
2146 PHP_FUNCTION(connection_status)
2147 {
2148 ZEND_PARSE_PARAMETERS_NONE();
2149
2150 RETURN_LONG(PG(connection_status));
2151 }
2152 /* }}} */
2153
2154 /* {{{ Set whether we want to ignore a user abort event or not */
2155 PHP_FUNCTION(ignore_user_abort)
2156 {
2157 bool arg = 0;
2158 bool arg_is_null = 1;
2159 int old_setting;
2160
2161 ZEND_PARSE_PARAMETERS_START(0, 1)
2162 Z_PARAM_OPTIONAL
2163 Z_PARAM_BOOL_OR_NULL(arg, arg_is_null)
2164 ZEND_PARSE_PARAMETERS_END();
2165
2166 old_setting = (unsigned short)PG(ignore_user_abort);
2167
2168 if (!arg_is_null) {
2169 zend_string *key = ZSTR_INIT_LITERAL("ignore_user_abort", 0);
2170 zend_alter_ini_entry_chars(key, arg ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2171 zend_string_release_ex(key, 0);
2172 }
2173
2174 RETURN_LONG(old_setting);
2175 }
2176 /* }}} */
2177
2178 #ifdef HAVE_GETSERVBYNAME
2179 /* {{{ Returns port associated with service. Protocol must be "tcp" or "udp" */
2180 PHP_FUNCTION(getservbyname)
2181 {
2182 zend_string *name;
2183 char *proto;
2184 size_t proto_len;
2185 struct servent *serv;
2186
2187 ZEND_PARSE_PARAMETERS_START(2, 2)
2188 Z_PARAM_STR(name)
2189 Z_PARAM_STRING(proto, proto_len)
2190 ZEND_PARSE_PARAMETERS_END();
2191
2192
2193 /* empty string behaves like NULL on windows implementation of
2194 getservbyname. Let be portable instead. */
2195 #ifdef PHP_WIN32
2196 if (proto_len == 0) {
2197 RETURN_FALSE;
2198 }
2199 #endif
2200
2201 serv = getservbyname(ZSTR_VAL(name), proto);
2202
2203 #ifdef _AIX
2204 /*
2205 On AIX, imap is only known as imap2 in /etc/services, while on Linux imap is an alias for imap2.
2206 If a request for imap gives no result, we try again with imap2.
2207 */
2208 if (serv == NULL && zend_string_equals_literal(name, "imap")) {
2209 serv = getservbyname("imap2", proto);
2210 }
2211 #endif
2212 if (serv == NULL) {
2213 RETURN_FALSE;
2214 }
2215
2216 RETURN_LONG(ntohs(serv->s_port));
2217 }
2218 /* }}} */
2219 #endif
2220
2221 #ifdef HAVE_GETSERVBYPORT
2222 /* {{{ Returns service name associated with port. Protocol must be "tcp" or "udp" */
2223 PHP_FUNCTION(getservbyport)
2224 {
2225 char *proto;
2226 size_t proto_len;
2227 zend_long port;
2228 struct servent *serv;
2229
2230 ZEND_PARSE_PARAMETERS_START(2, 2)
2231 Z_PARAM_LONG(port)
2232 Z_PARAM_STRING(proto, proto_len)
2233 ZEND_PARSE_PARAMETERS_END();
2234
2235 serv = getservbyport(htons((unsigned short) port), proto);
2236
2237 if (serv == NULL) {
2238 RETURN_FALSE;
2239 }
2240
2241 /* MSAN false positive, getservbyport() is not properly intercepted. */
2242 #if __has_feature(memory_sanitizer)
2243 __msan_unpoison_string(serv->s_name);
2244 #endif
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_must_not_be_empty_error(1);
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