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