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