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