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