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