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
59typedef struct _php_extension_lists {
60 zend_llist engine;
61 zend_llist functions;
62} php_extension_lists;
63
64/* True globals */
65static int is_special_section = 0;
66static HashTable *active_ini_hash;
67static HashTable configuration_hash;
68static int has_per_dir_config = 0;
69static int has_per_host_config = 0;
70PHPAPI char *php_ini_opened_path=NULL;
71static php_extension_lists extension_lists;
72PHPAPI char *php_ini_scanned_path=NULL;
73PHPAPI char *php_ini_scanned_files=NULL;
74
75/* {{{ php_ini_displayer_cb
76 */
77static 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 */
124static 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 */
152static 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 */
165PHPAPI 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 */
192PHPAPI 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 */
210static 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 */
348static 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 */
358static 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 */
383int 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 */
725int 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 */
742void 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 */
754PHPAPI 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 */
786PHPAPI 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 */
806PHPAPI 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 */
814PHPAPI 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 */
857PHPAPI 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 */
865PHPAPI 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 */
880PHPAPI 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 */
894PHPAPI 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 */
912PHPAPI 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 */
930PHPAPI 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
943PHPAPI 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