1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Zeev Suraski <zeev@zend.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #include "php.h"
22 #include "ext/standard/info.h"
23 #include "zend_ini.h"
24 #include "zend_ini_scanner.h"
25 #include "php_ini.h"
26 #include "ext/standard/dl.h"
27 #include "zend_extensions.h"
28 #include "zend_highlight.h"
29 #include "SAPI.h"
30 #include "php_main.h"
31 #include "php_scandir.h"
32 #ifdef PHP_WIN32
33 #include "win32/php_registry.h"
34 #endif
35
36 #if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H
37 #include <dirent.h>
38 #endif
39
40 #ifdef PHP_WIN32
41 #define TRANSLATE_SLASHES_LOWER(path) \
42 { \
43 char *tmp = path; \
44 while (*tmp) { \
45 if (*tmp == '\\') *tmp = '/'; \
46 else *tmp = tolower(*tmp); \
47 tmp++; \
48 } \
49 }
50 #else
51 #define TRANSLATE_SLASHES_LOWER(path)
52 #endif
53
54
55 typedef struct _php_extension_lists {
56 zend_llist engine;
57 zend_llist functions;
58 } php_extension_lists;
59
60 /* True globals */
61 static int is_special_section = 0;
62 static HashTable *active_ini_hash;
63 static HashTable configuration_hash;
64 static int has_per_dir_config = 0;
65 static int has_per_host_config = 0;
66 PHPAPI char *php_ini_opened_path=NULL;
67 static php_extension_lists extension_lists;
68 PHPAPI char *php_ini_scanned_path=NULL;
69 PHPAPI char *php_ini_scanned_files=NULL;
70
71 /* {{{ php_ini_displayer_cb
72 */
php_ini_displayer_cb(zend_ini_entry * ini_entry,int type)73 static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type)
74 {
75 if (ini_entry->displayer) {
76 ini_entry->displayer(ini_entry, type);
77 } else {
78 char *display_string;
79 size_t display_string_length;
80 int esc_html=0;
81
82 if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
83 if (ini_entry->orig_value && ZSTR_VAL(ini_entry->orig_value)[0]) {
84 display_string = ZSTR_VAL(ini_entry->orig_value);
85 display_string_length = ZSTR_LEN(ini_entry->orig_value);
86 esc_html = !sapi_module.phpinfo_as_text;
87 } else {
88 if (!sapi_module.phpinfo_as_text) {
89 display_string = "<i>no value</i>";
90 display_string_length = sizeof("<i>no value</i>") - 1;
91 } else {
92 display_string = "no value";
93 display_string_length = sizeof("no value") - 1;
94 }
95 }
96 } else if (ini_entry->value && ZSTR_VAL(ini_entry->value)[0]) {
97 display_string = ZSTR_VAL(ini_entry->value);
98 display_string_length = ZSTR_LEN(ini_entry->value);
99 esc_html = !sapi_module.phpinfo_as_text;
100 } else {
101 if (!sapi_module.phpinfo_as_text) {
102 display_string = "<i>no value</i>";
103 display_string_length = sizeof("<i>no value</i>") - 1;
104 } else {
105 display_string = "no value";
106 display_string_length = sizeof("no value") - 1;
107 }
108 }
109
110 if (esc_html) {
111 php_html_puts(display_string, display_string_length);
112 } else {
113 PHPWRITE(display_string, display_string_length);
114 }
115 }
116 }
117 /* }}} */
118
119 /* {{{ php_ini_displayer
120 */
php_ini_displayer(zval * el,void * arg)121 static int php_ini_displayer(zval *el, void *arg)
122 {
123 zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el);
124 int module_number = *(int *)arg;
125
126 if (ini_entry->module_number != module_number) {
127 return 0;
128 }
129 if (!sapi_module.phpinfo_as_text) {
130 PUTS("<tr>");
131 PUTS("<td class=\"e\">");
132 PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
133 PUTS("</td><td class=\"v\">");
134 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
135 PUTS("</td><td class=\"v\">");
136 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
137 PUTS("</td></tr>\n");
138 } else {
139 PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
140 PUTS(" => ");
141 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
142 PUTS(" => ");
143 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
144 PUTS("\n");
145 }
146 return 0;
147 }
148 /* }}} */
149
150 /* {{{ php_ini_available
151 */
php_ini_available(zval * el,void * arg)152 static int php_ini_available(zval *el, void *arg)
153 {
154 zend_ini_entry *ini_entry = (zend_ini_entry *)Z_PTR_P(el);
155 int *module_number_available = (int *)arg;
156 if (ini_entry->module_number == *(int *)module_number_available) {
157 *(int *)module_number_available = -1;
158 return ZEND_HASH_APPLY_STOP;
159 } else {
160 return ZEND_HASH_APPLY_KEEP;
161 }
162 }
163 /* }}} */
164
165 /* {{{ display_ini_entries
166 */
display_ini_entries(zend_module_entry * module)167 PHPAPI void display_ini_entries(zend_module_entry *module)
168 {
169 int module_number, module_number_available;
170
171 if (module) {
172 module_number = module->module_number;
173 } else {
174 module_number = 0;
175 }
176 module_number_available = module_number;
177 zend_hash_apply_with_argument(EG(ini_directives), php_ini_available, &module_number_available);
178 if (module_number_available == -1) {
179 php_info_print_table_start();
180 php_info_print_table_header(3, "Directive", "Local Value", "Master Value");
181 zend_hash_apply_with_argument(EG(ini_directives), php_ini_displayer, (void *)&module_number);
182 php_info_print_table_end();
183 }
184 }
185 /* }}} */
186
187 /* php.ini support */
188 #define PHP_EXTENSION_TOKEN "extension"
189 #define ZEND_EXTENSION_TOKEN "zend_extension"
190
191 /* {{{ config_zval_dtor
192 */
config_zval_dtor(zval * zvalue)193 PHPAPI void config_zval_dtor(zval *zvalue)
194 {
195 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
196 zend_hash_destroy(Z_ARRVAL_P(zvalue));
197 free(Z_ARR_P(zvalue));
198 } else if (Z_TYPE_P(zvalue) == IS_STRING) {
199 zend_string_release(Z_STR_P(zvalue));
200 }
201 }
202 /* Reset / free active_ini_sectin global */
203 #define RESET_ACTIVE_INI_HASH() do { \
204 active_ini_hash = NULL; \
205 is_special_section = 0; \
206 } while (0)
207 /* }}} */
208
209 /* {{{ php_ini_parser_cb
210 */
php_ini_parser_cb(zval * arg1,zval * arg2,zval * arg3,int callback_type,HashTable * target_hash)211 static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, HashTable *target_hash)
212 {
213 zval *entry;
214 HashTable *active_hash;
215 char *extension_name;
216
217 if (active_ini_hash) {
218 active_hash = active_ini_hash;
219 } else {
220 active_hash = target_hash;
221 }
222
223 switch (callback_type) {
224 case ZEND_INI_PARSER_ENTRY: {
225 if (!arg2) {
226 /* bare string - nothing to do */
227 break;
228 }
229
230 /* PHP and Zend extensions are not added into configuration hash! */
231 if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), PHP_EXTENSION_TOKEN)) { /* load PHP extension */
232 extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
233 zend_llist_add_element(&extension_lists.functions, &extension_name);
234 } else if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */
235 extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
236 zend_llist_add_element(&extension_lists.engine, &extension_name);
237
238 /* All other entries are added into either configuration_hash or active ini section array */
239 } else {
240 /* Store in active hash */
241 entry = zend_hash_update(active_hash, Z_STR_P(arg1), arg2);
242 Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
243 }
244 }
245 break;
246
247 case ZEND_INI_PARSER_POP_ENTRY: {
248 zval option_arr;
249 zval *find_arr;
250
251 if (!arg2) {
252 /* bare string - nothing to do */
253 break;
254 }
255
256 /* fprintf(stdout, "ZEND_INI_PARSER_POP_ENTRY: %s[%s] = %s\n",Z_STRVAL_P(arg1), Z_STRVAL_P(arg3), Z_STRVAL_P(arg2)); */
257
258 /* If option not found in hash or is not an array -> create array, otherwise add to existing array */
259 if ((find_arr = zend_hash_find(active_hash, Z_STR_P(arg1))) == NULL || Z_TYPE_P(find_arr) != IS_ARRAY) {
260 ZVAL_NEW_PERSISTENT_ARR(&option_arr);
261 zend_hash_init(Z_ARRVAL(option_arr), 8, NULL, config_zval_dtor, 1);
262 find_arr = zend_hash_update(active_hash, Z_STR_P(arg1), &option_arr);
263 }
264
265 /* arg3 is possible option offset name */
266 if (arg3 && Z_STRLEN_P(arg3) > 0) {
267 entry = zend_symtable_update(Z_ARRVAL_P(find_arr), Z_STR_P(arg3), arg2);
268 } else {
269 entry = zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2);
270 }
271 Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
272 }
273 break;
274
275 case ZEND_INI_PARSER_SECTION: { /* Create an array of entries of each section */
276
277 /* fprintf(stdout, "ZEND_INI_PARSER_SECTION: %s\n",Z_STRVAL_P(arg1)); */
278
279 char *key = NULL;
280 size_t key_len;
281
282 /* PATH sections */
283 if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "PATH", sizeof("PATH") - 1, sizeof("PATH") - 1)) {
284 key = Z_STRVAL_P(arg1);
285 key = key + sizeof("PATH") - 1;
286 key_len = Z_STRLEN_P(arg1) - sizeof("PATH") + 1;
287 is_special_section = 1;
288 has_per_dir_config = 1;
289
290 /* make the path lowercase on Windows, for case insensitivity. Does nothing for other platforms */
291 TRANSLATE_SLASHES_LOWER(key);
292
293 /* HOST sections */
294 } else if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "HOST", sizeof("HOST") - 1, sizeof("HOST") - 1)) {
295 key = Z_STRVAL_P(arg1);
296 key = key + sizeof("HOST") - 1;
297 key_len = Z_STRLEN_P(arg1) - sizeof("HOST") + 1;
298 is_special_section = 1;
299 has_per_host_config = 1;
300 zend_str_tolower(key, key_len); /* host names are case-insensitive. */
301
302 } else {
303 is_special_section = 0;
304 }
305
306 if (key && key_len > 0) {
307 /* Strip any trailing slashes */
308 while (key_len > 0 && (key[key_len - 1] == '/' || key[key_len - 1] == '\\')) {
309 key_len--;
310 key[key_len] = 0;
311 }
312
313 /* Strip any leading whitespace and '=' */
314 while (*key && (
315 *key == '=' ||
316 *key == ' ' ||
317 *key == '\t'
318 )) {
319 key++;
320 key_len--;
321 }
322
323 /* Search for existing entry and if it does not exist create one */
324 if ((entry = zend_hash_str_find(target_hash, key, key_len)) == NULL) {
325 zval section_arr;
326
327 ZVAL_NEW_PERSISTENT_ARR(§ion_arr);
328 zend_hash_init(Z_ARRVAL(section_arr), 8, NULL, (dtor_func_t) config_zval_dtor, 1);
329 entry = zend_hash_str_update(target_hash, key, key_len, §ion_arr);
330 }
331 if (Z_TYPE_P(entry) == IS_ARRAY) {
332 active_ini_hash = Z_ARRVAL_P(entry);
333 }
334 }
335 }
336 break;
337 }
338 }
339 /* }}} */
340
341 /* {{{ php_load_php_extension_cb
342 */
php_load_php_extension_cb(void * arg)343 static void php_load_php_extension_cb(void *arg)
344 {
345 #ifdef HAVE_LIBDL
346 php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0);
347 #endif
348 }
349 /* }}} */
350
351 /* {{{ php_load_zend_extension_cb
352 */
353 #ifdef HAVE_LIBDL
php_load_zend_extension_cb(void * arg)354 static void php_load_zend_extension_cb(void *arg)
355 {
356 char *filename = *((char **) arg);
357 const size_t length = strlen(filename);
358
359 #ifndef PHP_WIN32
360 (void) length;
361 #endif
362
363 if (IS_ABSOLUTE_PATH(filename, length)) {
364 zend_load_extension(filename);
365 } else {
366 DL_HANDLE handle;
367 char *libpath;
368 char *extension_dir = INI_STR("extension_dir");
369 int slash_suffix = 0;
370 char *err1, *err2;
371
372 if (extension_dir && extension_dir[0]) {
373 slash_suffix = IS_SLASH(extension_dir[strlen(extension_dir)-1]);
374 }
375
376 /* Try as filename first */
377 if (slash_suffix) {
378 spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */
379 } else {
380 spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename); /* SAFE */
381 }
382
383 handle = (DL_HANDLE)php_load_shlib(libpath, &err1);
384 if (!handle) {
385 /* If file does not exist, consider as extension name and build file name */
386 char *orig_libpath = libpath;
387
388 if (slash_suffix) {
389 spprintf(&libpath, 0, "%s" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, filename); /* SAFE */
390 } else {
391 spprintf(&libpath, 0, "%s%c" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, DEFAULT_SLASH, filename); /* SAFE */
392 }
393
394 handle = (DL_HANDLE)php_load_shlib(libpath, &err2);
395 if (!handle) {
396 php_error(E_CORE_WARNING, "Failed loading Zend extension '%s' (tried: %s (%s), %s (%s))",
397 filename, orig_libpath, err1, libpath, err2);
398 efree(orig_libpath);
399 efree(err1);
400 efree(libpath);
401 efree(err2);
402 return;
403 }
404
405 efree(orig_libpath);
406 efree(err1);
407 }
408
409 zend_load_extension_handle(handle, libpath);
410 efree(libpath);
411 }
412 }
413 #else
php_load_zend_extension_cb(void * arg)414 static void php_load_zend_extension_cb(void *arg) { }
415 #endif
416 /* }}} */
417
418 /* {{{ php_init_config
419 */
php_init_config(void)420 int php_init_config(void)
421 {
422 char *php_ini_file_name = NULL;
423 char *php_ini_search_path = NULL;
424 int php_ini_scanned_path_len;
425 char *open_basedir;
426 int free_ini_search_path = 0;
427 zend_file_handle fh;
428 zend_string *opened_path = NULL;
429
430 zend_hash_init(&configuration_hash, 8, NULL, config_zval_dtor, 1);
431
432 if (sapi_module.ini_defaults) {
433 sapi_module.ini_defaults(&configuration_hash);
434 }
435
436 zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
437 zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
438
439 open_basedir = PG(open_basedir);
440
441 if (sapi_module.php_ini_path_override) {
442 php_ini_file_name = sapi_module.php_ini_path_override;
443 php_ini_search_path = sapi_module.php_ini_path_override;
444 free_ini_search_path = 0;
445 } else if (!sapi_module.php_ini_ignore) {
446 int search_path_size;
447 char *default_location;
448 char *env_location;
449 static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
450 #ifdef PHP_WIN32
451 char *reg_location;
452 char phprc_path[MAXPATHLEN];
453 #endif
454
455 env_location = getenv("PHPRC");
456
457 #ifdef PHP_WIN32
458 if (!env_location) {
459 char dummybuf;
460 int size;
461
462 SetLastError(0);
463
464 /*If the given buffer is not large enough to hold the data, the return value is
465 the buffer size, in characters, required to hold the string and its terminating
466 null character. We use this return value to alloc the final buffer. */
467 size = GetEnvironmentVariableA("PHPRC", &dummybuf, 0);
468 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
469 /* The environment variable doesn't exist. */
470 env_location = "";
471 } else {
472 if (size == 0) {
473 env_location = "";
474 } else {
475 size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
476 if (size == 0) {
477 env_location = "";
478 } else {
479 env_location = phprc_path;
480 }
481 }
482 }
483 }
484 #else
485 if (!env_location) {
486 env_location = "";
487 }
488 #endif
489 /*
490 * Prepare search path
491 */
492
493 search_path_size = MAXPATHLEN * 4 + (int)strlen(env_location) + 3 + 1;
494 php_ini_search_path = (char *) emalloc(search_path_size);
495 free_ini_search_path = 1;
496 php_ini_search_path[0] = 0;
497
498 /* Add environment location */
499 if (env_location[0]) {
500 if (*php_ini_search_path) {
501 strlcat(php_ini_search_path, paths_separator, search_path_size);
502 }
503 strlcat(php_ini_search_path, env_location, search_path_size);
504 php_ini_file_name = env_location;
505 }
506
507 #ifdef PHP_WIN32
508 /* Add registry location */
509 reg_location = GetIniPathFromRegistry();
510 if (reg_location != NULL) {
511 if (*php_ini_search_path) {
512 strlcat(php_ini_search_path, paths_separator, search_path_size);
513 }
514 strlcat(php_ini_search_path, reg_location, search_path_size);
515 efree(reg_location);
516 }
517 #endif
518
519 /* Add cwd (not with CLI) */
520 if (!sapi_module.php_ini_ignore_cwd) {
521 if (*php_ini_search_path) {
522 strlcat(php_ini_search_path, paths_separator, search_path_size);
523 }
524 strlcat(php_ini_search_path, ".", search_path_size);
525 }
526
527 if (PG(php_binary)) {
528 char *separator_location, *binary_location;
529
530 binary_location = estrdup(PG(php_binary));
531 separator_location = strrchr(binary_location, DEFAULT_SLASH);
532
533 if (separator_location && separator_location != binary_location) {
534 *(separator_location) = 0;
535 }
536 if (*php_ini_search_path) {
537 strlcat(php_ini_search_path, paths_separator, search_path_size);
538 }
539 strlcat(php_ini_search_path, binary_location, search_path_size);
540 efree(binary_location);
541 }
542
543 /* Add default location */
544 #ifdef PHP_WIN32
545 default_location = (char *) emalloc(MAXPATHLEN + 1);
546
547 if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) {
548 if (*php_ini_search_path) {
549 strlcat(php_ini_search_path, paths_separator, search_path_size);
550 }
551 strlcat(php_ini_search_path, default_location, search_path_size);
552 }
553
554 /* For people running under terminal services, GetWindowsDirectory will
555 * return their personal Windows directory, so lets add the system
556 * windows directory too */
557 if (0 < GetSystemWindowsDirectory(default_location, MAXPATHLEN)) {
558 if (*php_ini_search_path) {
559 strlcat(php_ini_search_path, paths_separator, search_path_size);
560 }
561 strlcat(php_ini_search_path, default_location, search_path_size);
562 }
563 efree(default_location);
564
565 #else
566 default_location = PHP_CONFIG_FILE_PATH;
567 if (*php_ini_search_path) {
568 strlcat(php_ini_search_path, paths_separator, search_path_size);
569 }
570 strlcat(php_ini_search_path, default_location, search_path_size);
571 #endif
572 }
573
574 PG(open_basedir) = NULL;
575
576 /*
577 * Find and open actual ini file
578 */
579
580 memset(&fh, 0, sizeof(fh));
581
582 /* If SAPI does not want to ignore all ini files OR an overriding file/path is given.
583 * This allows disabling scanning for ini files in the PHP_CONFIG_FILE_SCAN_DIR but still
584 * load an optional ini file. */
585 if (!sapi_module.php_ini_ignore || sapi_module.php_ini_path_override) {
586
587 /* Check if php_ini_file_name is a file and can be opened */
588 if (php_ini_file_name && php_ini_file_name[0]) {
589 zend_stat_t statbuf;
590
591 if (!VCWD_STAT(php_ini_file_name, &statbuf)) {
592 if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
593 fh.handle.fp = VCWD_FOPEN(php_ini_file_name, "r");
594 if (fh.handle.fp) {
595 fh.filename = expand_filepath(php_ini_file_name, NULL);
596 }
597 }
598 }
599 }
600
601 /* Otherwise search for php-%sapi-module-name%.ini file in search path */
602 if (!fh.handle.fp) {
603 const char *fmt = "php-%s.ini";
604 char *ini_fname;
605 spprintf(&ini_fname, 0, fmt, sapi_module.name);
606 fh.handle.fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &opened_path);
607 efree(ini_fname);
608 if (fh.handle.fp) {
609 fh.filename = ZSTR_VAL(opened_path);
610 }
611 }
612
613 /* If still no ini file found, search for php.ini file in search path */
614 if (!fh.handle.fp) {
615 fh.handle.fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &opened_path);
616 if (fh.handle.fp) {
617 fh.filename = ZSTR_VAL(opened_path);
618 }
619 }
620 }
621
622 if (free_ini_search_path) {
623 efree(php_ini_search_path);
624 }
625
626 PG(open_basedir) = open_basedir;
627
628 if (fh.handle.fp) {
629 fh.type = ZEND_HANDLE_FP;
630 RESET_ACTIVE_INI_HASH();
631
632 zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
633
634 {
635 zval tmp;
636
637 ZVAL_NEW_STR(&tmp, zend_string_init(fh.filename, strlen(fh.filename), 1));
638 zend_hash_str_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path")-1, &tmp);
639 if (opened_path) {
640 zend_string_release(opened_path);
641 } else {
642 efree((char *)fh.filename);
643 }
644 php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
645 }
646 }
647
648 /* Check for PHP_INI_SCAN_DIR environment variable to override/set config file scan directory */
649 php_ini_scanned_path = getenv("PHP_INI_SCAN_DIR");
650 if (!php_ini_scanned_path) {
651 /* Or fall back using possible --with-config-file-scan-dir setting (defaults to empty string!) */
652 php_ini_scanned_path = PHP_CONFIG_FILE_SCAN_DIR;
653 }
654 php_ini_scanned_path_len = (int)strlen(php_ini_scanned_path);
655
656 /* Scan and parse any .ini files found in scan path if path not empty. */
657 if (!sapi_module.php_ini_ignore && php_ini_scanned_path_len) {
658 struct dirent **namelist;
659 int ndir, i;
660 zend_stat_t sb;
661 char ini_file[MAXPATHLEN];
662 char *p;
663 zend_file_handle fh2;
664 zend_llist scanned_ini_list;
665 zend_llist_element *element;
666 int l, total_l = 0;
667 char *bufpath, *debpath, *endpath;
668 int lenpath;
669
670 zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
671 memset(&fh2, 0, sizeof(fh2));
672
673 bufpath = estrdup(php_ini_scanned_path);
674 for (debpath = bufpath ; debpath ; debpath=endpath) {
675 endpath = strchr(debpath, DEFAULT_DIR_SEPARATOR);
676 if (endpath) {
677 *(endpath++) = 0;
678 }
679 if (!debpath[0]) {
680 /* empty string means default builtin value
681 to allow "/foo/php.d:" or ":/foo/php.d" */
682 debpath = PHP_CONFIG_FILE_SCAN_DIR;
683 }
684 lenpath = (int)strlen(debpath);
685
686 if (lenpath > 0 && (ndir = php_scandir(debpath, &namelist, 0, php_alphasort)) > 0) {
687
688 for (i = 0; i < ndir; i++) {
689
690 /* check for any file with .ini extension */
691 if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) {
692 free(namelist[i]);
693 continue;
694 }
695 /* Reset active ini section */
696 RESET_ACTIVE_INI_HASH();
697
698 if (IS_SLASH(debpath[lenpath - 1])) {
699 snprintf(ini_file, MAXPATHLEN, "%s%s", debpath, namelist[i]->d_name);
700 } else {
701 snprintf(ini_file, MAXPATHLEN, "%s%c%s", debpath, DEFAULT_SLASH, namelist[i]->d_name);
702 }
703 if (VCWD_STAT(ini_file, &sb) == 0) {
704 if (S_ISREG(sb.st_mode)) {
705 if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
706 fh2.filename = ini_file;
707 fh2.type = ZEND_HANDLE_FP;
708
709 if (zend_parse_ini_file(&fh2, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash) == SUCCESS) {
710 /* Here, add it to the list of ini files read */
711 l = (int)strlen(ini_file);
712 total_l += l + 2;
713 p = estrndup(ini_file, l);
714 zend_llist_add_element(&scanned_ini_list, &p);
715 }
716 }
717 }
718 }
719 free(namelist[i]);
720 }
721 free(namelist);
722 }
723 }
724 efree(bufpath);
725
726 if (total_l) {
727 int php_ini_scanned_files_len = (php_ini_scanned_files) ? (int)strlen(php_ini_scanned_files) + 1 : 0;
728 php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
729 if (!php_ini_scanned_files_len) {
730 *php_ini_scanned_files = '\0';
731 }
732 total_l += php_ini_scanned_files_len;
733 for (element = scanned_ini_list.head; element; element = element->next) {
734 if (php_ini_scanned_files_len) {
735 strlcat(php_ini_scanned_files, ",\n", total_l);
736 }
737 strlcat(php_ini_scanned_files, *(char **)element->data, total_l);
738 strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l);
739 }
740 }
741 zend_llist_destroy(&scanned_ini_list);
742 } else {
743 /* Make sure an empty php_ini_scanned_path ends up as NULL */
744 php_ini_scanned_path = NULL;
745 }
746
747 if (sapi_module.ini_entries) {
748 /* Reset active ini section */
749 RESET_ACTIVE_INI_HASH();
750 zend_parse_ini_string(sapi_module.ini_entries, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
751 }
752
753 return SUCCESS;
754 }
755 /* }}} */
756
757 /* {{{ php_shutdown_config
758 */
php_shutdown_config(void)759 int php_shutdown_config(void)
760 {
761 zend_hash_destroy(&configuration_hash);
762 if (php_ini_opened_path) {
763 free(php_ini_opened_path);
764 php_ini_opened_path = NULL;
765 }
766 if (php_ini_scanned_files) {
767 free(php_ini_scanned_files);
768 php_ini_scanned_files = NULL;
769 }
770 return SUCCESS;
771 }
772 /* }}} */
773
774 /* {{{ php_ini_register_extensions
775 */
php_ini_register_extensions(void)776 void php_ini_register_extensions(void)
777 {
778 zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb);
779 zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
780
781 zend_llist_destroy(&extension_lists.engine);
782 zend_llist_destroy(&extension_lists.functions);
783 }
784 /* }}} */
785
786 /* {{{ php_parse_user_ini_file
787 */
php_parse_user_ini_file(const char * dirname,char * ini_filename,HashTable * target_hash)788 PHPAPI int php_parse_user_ini_file(const char *dirname, char *ini_filename, HashTable *target_hash)
789 {
790 zend_stat_t sb;
791 char ini_file[MAXPATHLEN];
792 zend_file_handle fh;
793
794 snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename);
795
796 if (VCWD_STAT(ini_file, &sb) == 0) {
797 if (S_ISREG(sb.st_mode)) {
798 memset(&fh, 0, sizeof(fh));
799 if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
800 fh.filename = ini_file;
801 fh.type = ZEND_HANDLE_FP;
802
803 /* Reset active ini section */
804 RESET_ACTIVE_INI_HASH();
805
806 if (zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, target_hash) == SUCCESS) {
807 /* FIXME: Add parsed file to the list of user files read? */
808 return SUCCESS;
809 }
810 return FAILURE;
811 }
812 }
813 }
814 return FAILURE;
815 }
816 /* }}} */
817
818 /* {{{ php_ini_activate_config
819 */
php_ini_activate_config(HashTable * source_hash,int modify_type,int stage)820 PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage)
821 {
822 zend_string *str;
823 zval *data;
824
825 /* Walk through config hash and alter matching ini entries using the values found in the hash */
826 ZEND_HASH_FOREACH_STR_KEY_VAL(source_hash, str, data) {
827 zend_alter_ini_entry_ex(str, Z_STR_P(data), modify_type, stage, 0);
828 } ZEND_HASH_FOREACH_END();
829 }
830 /* }}} */
831
832 /* {{{ php_ini_has_per_dir_config
833 */
php_ini_has_per_dir_config(void)834 PHPAPI int php_ini_has_per_dir_config(void)
835 {
836 return has_per_dir_config;
837 }
838 /* }}} */
839
840 /* {{{ php_ini_activate_per_dir_config
841 */
php_ini_activate_per_dir_config(char * path,size_t path_len)842 PHPAPI void php_ini_activate_per_dir_config(char *path, size_t path_len)
843 {
844 zval *tmp2;
845 char *ptr;
846
847 #ifdef PHP_WIN32
848 char path_bak[MAXPATHLEN];
849 #endif
850
851 #ifdef PHP_WIN32
852 /* MAX_PATH is \0-terminated, path_len == MAXPATHLEN would overrun path_bak */
853 if (path_len >= MAXPATHLEN) {
854 #else
855 if (path_len > MAXPATHLEN) {
856 #endif
857 return;
858 }
859
860 #ifdef PHP_WIN32
861 memcpy(path_bak, path, path_len);
862 path_bak[path_len] = 0;
863 TRANSLATE_SLASHES_LOWER(path_bak);
864 path = path_bak;
865 #endif
866
867 /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */
868 if (has_per_dir_config && path && path_len) {
869 ptr = path + 1;
870 while ((ptr = strchr(ptr, '/')) != NULL) {
871 *ptr = 0;
872 /* Search for source array matching the path from configuration_hash */
873 if ((tmp2 = zend_hash_str_find(&configuration_hash, path, strlen(path))) != NULL) {
874 php_ini_activate_config(Z_ARRVAL_P(tmp2), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
875 }
876 *ptr = '/';
877 ptr++;
878 }
879 }
880 }
881 /* }}} */
882
883 /* {{{ php_ini_has_per_host_config
884 */
885 PHPAPI int php_ini_has_per_host_config(void)
886 {
887 return has_per_host_config;
888 }
889 /* }}} */
890
891 /* {{{ php_ini_activate_per_host_config
892 */
893 PHPAPI void php_ini_activate_per_host_config(const char *host, size_t host_len)
894 {
895 zval *tmp;
896
897 if (has_per_host_config && host && host_len) {
898 /* Search for source array matching the host from configuration_hash */
899 if ((tmp = zend_hash_str_find(&configuration_hash, host, host_len)) != NULL) {
900 php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
901 }
902 }
903 }
904 /* }}} */
905
906 /* {{{ cfg_get_entry
907 */
908 PHPAPI zval *cfg_get_entry_ex(zend_string *name)
909 {
910 return zend_hash_find(&configuration_hash, name);
911 }
912 /* }}} */
913
914 /* {{{ cfg_get_entry
915 */
916 PHPAPI zval *cfg_get_entry(const char *name, size_t name_length)
917 {
918 return zend_hash_str_find(&configuration_hash, name, name_length);
919 }
920 /* }}} */
921
922 /* {{{ cfg_get_long
923 */
924 PHPAPI int cfg_get_long(const char *varname, zend_long *result)
925 {
926 zval *tmp;
927
928 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
929 *result = 0;
930 return FAILURE;
931 }
932 *result = zval_get_long(tmp);
933 return SUCCESS;
934 }
935 /* }}} */
936
937 /* {{{ cfg_get_double
938 */
939 PHPAPI int cfg_get_double(const char *varname, double *result)
940 {
941 zval *tmp;
942
943 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
944 *result = (double) 0;
945 return FAILURE;
946 }
947 *result = zval_get_double(tmp);
948 return SUCCESS;
949 }
950 /* }}} */
951
952 /* {{{ cfg_get_string
953 */
954 PHPAPI int cfg_get_string(const char *varname, char **result)
955 {
956 zval *tmp;
957
958 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
959 *result = NULL;
960 return FAILURE;
961 }
962 *result = Z_STRVAL_P(tmp);
963 return SUCCESS;
964 }
965 /* }}} */
966
967 PHPAPI HashTable* php_ini_get_configuration_hash(void) /* {{{ */
968 {
969 return &configuration_hash;
970 } /* }}} */
971
972 /*
973 * Local variables:
974 * tab-width: 4
975 * c-basic-offset: 4
976 * indent-tabs-mode: t
977 * End:
978 * vim600: sw=4 ts=4 fdm=marker
979 * vim<600: sw=4 ts=4
980 */
981