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