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