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