1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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 */
php_ini_displayer_cb(zend_ini_entry * ini_entry,int type TSRMLS_DC)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 */
php_ini_displayer(zend_ini_entry * ini_entry,int module_number TSRMLS_DC)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 */
php_ini_available(zend_ini_entry * ini_entry,int * module_number_available TSRMLS_DC)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 */
display_ini_entries(zend_module_entry * module)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 */
config_zval_dtor(zval * zvalue)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 */
php_ini_parser_cb(zval * arg1,zval * arg2,zval * arg3,int callback_type,HashTable * target_hash)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 insensitivty. Does nothign 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 */
php_load_php_extension_cb(void * arg TSRMLS_DC)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 */
php_load_zend_extension_cb(void * arg TSRMLS_DC)358 static void php_load_zend_extension_cb(void *arg TSRMLS_DC)
359 {
360 zend_load_extension(*((char **) arg));
361 }
362 /* }}} */
363
364 /* {{{ php_init_config
365 */
php_init_config(TSRMLS_D)366 int php_init_config(TSRMLS_D)
367 {
368 char *php_ini_file_name = NULL;
369 char *php_ini_search_path = NULL;
370 int php_ini_scanned_path_len;
371 int safe_mode_state;
372 char *open_basedir;
373 int free_ini_search_path = 0;
374 zend_file_handle fh;
375
376 if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) config_zval_dtor, 1) == FAILURE) {
377 return FAILURE;
378 }
379
380 if (sapi_module.ini_defaults) {
381 sapi_module.ini_defaults(&configuration_hash);
382 }
383
384 zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
385 zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
386
387 safe_mode_state = PG(safe_mode);
388 open_basedir = PG(open_basedir);
389
390 if (sapi_module.php_ini_path_override) {
391 php_ini_file_name = sapi_module.php_ini_path_override;
392 php_ini_search_path = sapi_module.php_ini_path_override;
393 free_ini_search_path = 0;
394 } else if (!sapi_module.php_ini_ignore) {
395 int search_path_size;
396 char *default_location;
397 char *env_location;
398 char *binary_location;
399 static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
400 #ifdef PHP_WIN32
401 char *reg_location;
402 char phprc_path[MAXPATHLEN];
403 #endif
404
405 env_location = getenv("PHPRC");
406
407 #ifdef PHP_WIN32
408 if (!env_location) {
409 char dummybuf;
410 int size;
411
412 SetLastError(0);
413
414 /*If the given bugger is not large enough to hold the data, the return value is
415 the buffer size, in characters, required to hold the string and its terminating
416 null character. We use this return value to alloc the final buffer. */
417 size = GetEnvironmentVariableA("PHPRC", &dummybuf, 0);
418 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
419 /* The environment variable doesn't exist. */
420 env_location = "";
421 } else {
422 if (size == 0) {
423 env_location = "";
424 } else {
425 size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
426 env_location = phprc_path;
427 }
428 }
429 }
430 #else
431 if (!env_location) {
432 env_location = "";
433 }
434 #endif
435 /*
436 * Prepare search path
437 */
438
439 search_path_size = MAXPATHLEN * 4 + strlen(env_location) + 3 + 1;
440 php_ini_search_path = (char *) emalloc(search_path_size);
441 free_ini_search_path = 1;
442 php_ini_search_path[0] = 0;
443
444 /* Add environment location */
445 if (env_location[0]) {
446 if (*php_ini_search_path) {
447 strlcat(php_ini_search_path, paths_separator, search_path_size);
448 }
449 strlcat(php_ini_search_path, env_location, search_path_size);
450 php_ini_file_name = env_location;
451 }
452
453 #ifdef PHP_WIN32
454 /* Add registry location */
455 reg_location = GetIniPathFromRegistry();
456 if (reg_location != NULL) {
457 if (*php_ini_search_path) {
458 strlcat(php_ini_search_path, paths_separator, search_path_size);
459 }
460 strlcat(php_ini_search_path, reg_location, search_path_size);
461 efree(reg_location);
462 }
463 #endif
464
465 /* Add cwd (not with CLI) */
466 if (strcmp(sapi_module.name, "cli") != 0) {
467 if (*php_ini_search_path) {
468 strlcat(php_ini_search_path, paths_separator, search_path_size);
469 }
470 strlcat(php_ini_search_path, ".", search_path_size);
471 }
472
473 /* Add binary directory */
474 #ifdef PHP_WIN32
475 binary_location = (char *) emalloc(MAXPATHLEN);
476 if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
477 efree(binary_location);
478 binary_location = NULL;
479 }
480 #else
481 if (sapi_module.executable_location) {
482 binary_location = (char *)emalloc(MAXPATHLEN);
483 if (!strchr(sapi_module.executable_location, '/')) {
484 char *envpath, *path;
485 int found = 0;
486
487 if ((envpath = getenv("PATH")) != NULL) {
488 char *search_dir, search_path[MAXPATHLEN];
489 char *last = NULL;
490
491 path = estrdup(envpath);
492 search_dir = php_strtok_r(path, ":", &last);
493
494 while (search_dir) {
495 snprintf(search_path, MAXPATHLEN, "%s/%s", search_dir, sapi_module.executable_location);
496 if (VCWD_REALPATH(search_path, binary_location) && !VCWD_ACCESS(binary_location, X_OK)) {
497 found = 1;
498 break;
499 }
500 search_dir = php_strtok_r(NULL, ":", &last);
501 }
502 efree(path);
503 }
504 if (!found) {
505 efree(binary_location);
506 binary_location = NULL;
507 }
508 } else if (!VCWD_REALPATH(sapi_module.executable_location, binary_location) || VCWD_ACCESS(binary_location, X_OK)) {
509 efree(binary_location);
510 binary_location = NULL;
511 }
512 } else {
513 binary_location = NULL;
514 }
515 #endif
516 if (binary_location) {
517 char *separator_location = strrchr(binary_location, DEFAULT_SLASH);
518
519 if (separator_location && separator_location != binary_location) {
520 *(separator_location) = 0;
521 }
522 if (*php_ini_search_path) {
523 strlcat(php_ini_search_path, paths_separator, search_path_size);
524 }
525 strlcat(php_ini_search_path, binary_location, search_path_size);
526 efree(binary_location);
527 }
528
529 /* Add default location */
530 #ifdef PHP_WIN32
531 default_location = (char *) emalloc(MAXPATHLEN + 1);
532
533 if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) {
534 if (*php_ini_search_path) {
535 strlcat(php_ini_search_path, paths_separator, search_path_size);
536 }
537 strlcat(php_ini_search_path, default_location, search_path_size);
538 }
539
540 /* For people running under terminal services, GetWindowsDirectory will
541 * return their personal Windows directory, so lets add the system
542 * windows directory too */
543 if (0 < GetSystemWindowsDirectory(default_location, MAXPATHLEN)) {
544 if (*php_ini_search_path) {
545 strlcat(php_ini_search_path, paths_separator, search_path_size);
546 }
547 strlcat(php_ini_search_path, default_location, search_path_size);
548 }
549 efree(default_location);
550
551 #else
552 default_location = PHP_CONFIG_FILE_PATH;
553 if (*php_ini_search_path) {
554 strlcat(php_ini_search_path, paths_separator, search_path_size);
555 }
556 strlcat(php_ini_search_path, default_location, search_path_size);
557 #endif
558 }
559
560 PG(safe_mode) = 0;
561 PG(open_basedir) = NULL;
562
563 /*
564 * Find and open actual ini file
565 */
566
567 memset(&fh, 0, sizeof(fh));
568
569 /* If SAPI does not want to ignore all ini files OR an overriding file/path is given.
570 * This allows disabling scanning for ini files in the PHP_CONFIG_FILE_SCAN_DIR but still
571 * load an optional ini file. */
572 if (!sapi_module.php_ini_ignore || sapi_module.php_ini_path_override) {
573
574 /* Check if php_ini_file_name is a file and can be opened */
575 if (php_ini_file_name && php_ini_file_name[0]) {
576 struct stat statbuf;
577
578 if (!VCWD_STAT(php_ini_file_name, &statbuf)) {
579 if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
580 fh.handle.fp = VCWD_FOPEN(php_ini_file_name, "r");
581 if (fh.handle.fp) {
582 fh.filename = php_ini_opened_path = expand_filepath(php_ini_file_name, NULL TSRMLS_CC);
583 }
584 }
585 }
586 }
587
588 /* Otherwise search for php-%sapi-module-name%.ini file in search path */
589 if (!fh.handle.fp) {
590 const char *fmt = "php-%s.ini";
591 char *ini_fname;
592 spprintf(&ini_fname, 0, fmt, sapi_module.name);
593 fh.handle.fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC);
594 efree(ini_fname);
595 if (fh.handle.fp) {
596 fh.filename = php_ini_opened_path;
597 }
598 }
599
600 /* If still no ini file found, search for php.ini file in search path */
601 if (!fh.handle.fp) {
602 fh.handle.fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC);
603 if (fh.handle.fp) {
604 fh.filename = php_ini_opened_path;
605 }
606 }
607 }
608
609 if (free_ini_search_path) {
610 efree(php_ini_search_path);
611 }
612
613 PG(safe_mode) = safe_mode_state;
614 PG(open_basedir) = open_basedir;
615
616 if (fh.handle.fp) {
617 fh.type = ZEND_HANDLE_FP;
618 RESET_ACTIVE_INI_HASH();
619
620 zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC);
621
622 {
623 zval tmp;
624
625 Z_STRLEN(tmp) = strlen(fh.filename);
626 Z_STRVAL(tmp) = zend_strndup(fh.filename, Z_STRLEN(tmp));
627 Z_TYPE(tmp) = IS_STRING;
628 Z_SET_REFCOUNT(tmp, 0);
629
630 zend_hash_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path"), (void *) &tmp, sizeof(zval), NULL);
631 if (php_ini_opened_path) {
632 efree(php_ini_opened_path);
633 }
634 php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
635 }
636 }
637
638 /* Check for PHP_INI_SCAN_DIR environment variable to override/set config file scan directory */
639 php_ini_scanned_path = getenv("PHP_INI_SCAN_DIR");
640 if (!php_ini_scanned_path) {
641 /* Or fall back using possible --with-config-file-scan-dir setting (defaults to empty string!) */
642 php_ini_scanned_path = PHP_CONFIG_FILE_SCAN_DIR;
643 }
644 php_ini_scanned_path_len = strlen(php_ini_scanned_path);
645
646 /* Scan and parse any .ini files found in scan path if path not empty. */
647 if (!sapi_module.php_ini_ignore && php_ini_scanned_path_len) {
648 struct dirent **namelist;
649 int ndir, i;
650 struct stat sb;
651 char ini_file[MAXPATHLEN];
652 char *p;
653 zend_file_handle fh2;
654 zend_llist scanned_ini_list;
655 zend_llist_element *element;
656 int l, total_l = 0;
657
658 if ((ndir = php_scandir(php_ini_scanned_path, &namelist, 0, php_alphasort)) > 0) {
659 zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
660 memset(&fh2, 0, sizeof(fh2));
661
662 for (i = 0; i < ndir; i++) {
663
664 /* check for any file with .ini extension */
665 if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) {
666 free(namelist[i]);
667 continue;
668 }
669 /* Reset active ini section */
670 RESET_ACTIVE_INI_HASH();
671
672 if (IS_SLASH(php_ini_scanned_path[php_ini_scanned_path_len - 1])) {
673 snprintf(ini_file, MAXPATHLEN, "%s%s", php_ini_scanned_path, namelist[i]->d_name);
674 } else {
675 snprintf(ini_file, MAXPATHLEN, "%s%c%s", php_ini_scanned_path, DEFAULT_SLASH, namelist[i]->d_name);
676 }
677 if (VCWD_STAT(ini_file, &sb) == 0) {
678 if (S_ISREG(sb.st_mode)) {
679 if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
680 fh2.filename = ini_file;
681 fh2.type = ZEND_HANDLE_FP;
682
683 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) {
684 /* Here, add it to the list of ini files read */
685 l = strlen(ini_file);
686 total_l += l + 2;
687 p = estrndup(ini_file, l);
688 zend_llist_add_element(&scanned_ini_list, &p);
689 }
690 }
691 }
692 }
693 free(namelist[i]);
694 }
695 free(namelist);
696
697 if (total_l) {
698 int php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0;
699 php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
700 if (!php_ini_scanned_files_len) {
701 *php_ini_scanned_files = '\0';
702 }
703 total_l += php_ini_scanned_files_len;
704 for (element = scanned_ini_list.head; element; element = element->next) {
705 if (php_ini_scanned_files_len) {
706 strlcat(php_ini_scanned_files, ",\n", total_l);
707 }
708 strlcat(php_ini_scanned_files, *(char **)element->data, total_l);
709 strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l);
710 }
711 }
712 zend_llist_destroy(&scanned_ini_list);
713 }
714 } else {
715 /* Make sure an empty php_ini_scanned_path ends up as NULL */
716 php_ini_scanned_path = NULL;
717 }
718
719 if (sapi_module.ini_entries) {
720 /* Reset active ini section */
721 RESET_ACTIVE_INI_HASH();
722 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);
723 }
724
725 return SUCCESS;
726 }
727 /* }}} */
728
729 /* {{{ php_shutdown_config
730 */
php_shutdown_config(void)731 int php_shutdown_config(void)
732 {
733 zend_hash_destroy(&configuration_hash);
734 if (php_ini_opened_path) {
735 free(php_ini_opened_path);
736 php_ini_opened_path = NULL;
737 }
738 if (php_ini_scanned_files) {
739 free(php_ini_scanned_files);
740 php_ini_scanned_files = NULL;
741 }
742 return SUCCESS;
743 }
744 /* }}} */
745
746 /* {{{ php_ini_register_extensions
747 */
php_ini_register_extensions(TSRMLS_D)748 void php_ini_register_extensions(TSRMLS_D)
749 {
750 zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);
751 zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);
752
753 zend_llist_destroy(&extension_lists.engine);
754 zend_llist_destroy(&extension_lists.functions);
755 }
756 /* }}} */
757
758 /* {{{ php_parse_user_ini_file
759 */
php_parse_user_ini_file(const char * dirname,char * ini_filename,HashTable * target_hash TSRMLS_DC)760 PHPAPI int php_parse_user_ini_file(const char *dirname, char *ini_filename, HashTable *target_hash TSRMLS_DC)
761 {
762 struct stat sb;
763 char ini_file[MAXPATHLEN];
764 zend_file_handle fh;
765
766 snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename);
767
768 if (VCWD_STAT(ini_file, &sb) == 0) {
769 if (S_ISREG(sb.st_mode)) {
770 memset(&fh, 0, sizeof(fh));
771 if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
772 fh.filename = ini_file;
773 fh.type = ZEND_HANDLE_FP;
774
775 /* Reset active ini section */
776 RESET_ACTIVE_INI_HASH();
777
778 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) {
779 /* FIXME: Add parsed file to the list of user files read? */
780 return SUCCESS;
781 }
782 return FAILURE;
783 }
784 }
785 }
786 return FAILURE;
787 }
788 /* }}} */
789
790 /* {{{ php_ini_activate_config
791 */
php_ini_activate_config(HashTable * source_hash,int modify_type,int stage TSRMLS_DC)792 PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage TSRMLS_DC)
793 {
794 char *str;
795 zval *data;
796 uint str_len;
797 ulong num_index;
798
799 /* Walk through config hash and alter matching ini entries using the values found in the hash */
800 for (zend_hash_internal_pointer_reset(source_hash);
801 zend_hash_get_current_key_ex(source_hash, &str, &str_len, &num_index, 0, NULL) == HASH_KEY_IS_STRING;
802 zend_hash_move_forward(source_hash)
803 ) {
804 zend_hash_get_current_data(source_hash, (void **) &data);
805 zend_alter_ini_entry_ex(str, str_len, Z_STRVAL_P(data), Z_STRLEN_P(data), modify_type, stage, 0 TSRMLS_CC);
806 }
807 }
808 /* }}} */
809
810 /* {{{ php_ini_has_per_dir_config
811 */
php_ini_has_per_dir_config(void)812 PHPAPI int php_ini_has_per_dir_config(void)
813 {
814 return has_per_dir_config;
815 }
816 /* }}} */
817
818 /* {{{ php_ini_activate_per_dir_config
819 */
php_ini_activate_per_dir_config(char * path,uint path_len TSRMLS_DC)820 PHPAPI void php_ini_activate_per_dir_config(char *path, uint path_len TSRMLS_DC)
821 {
822 zval *tmp2;
823 char *ptr;
824
825 #if PHP_WIN32
826 char path_bak[MAXPATHLEN];
827 #endif
828
829 if (path_len > MAXPATHLEN) {
830 return;
831 }
832
833 #if PHP_WIN32
834 memcpy(path_bak, path, path_len);
835 path_bak[path_len] = 0;
836 TRANSLATE_SLASHES_LOWER(path_bak);
837 path = path_bak;
838 #endif
839
840 /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */
841 if (has_per_dir_config && path && path_len) {
842 ptr = path + 1;
843 while ((ptr = strchr(ptr, '/')) != NULL) {
844 *ptr = 0;
845 /* Search for source array matching the path from configuration_hash */
846 if (zend_hash_find(&configuration_hash, path, strlen(path) + 1, (void **) &tmp2) == SUCCESS) {
847 php_ini_activate_config(Z_ARRVAL_P(tmp2), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
848 }
849 *ptr = '/';
850 ptr++;
851 }
852 }
853 }
854 /* }}} */
855
856 /* {{{ php_ini_has_per_host_config
857 */
php_ini_has_per_host_config(void)858 PHPAPI int php_ini_has_per_host_config(void)
859 {
860 return has_per_host_config;
861 }
862 /* }}} */
863
864 /* {{{ php_ini_activate_per_host_config
865 */
php_ini_activate_per_host_config(const char * host,uint host_len TSRMLS_DC)866 PHPAPI void php_ini_activate_per_host_config(const char *host, uint host_len TSRMLS_DC)
867 {
868 zval *tmp;
869
870 if (has_per_host_config && host && host_len) {
871 /* Search for source array matching the host from configuration_hash */
872 if (zend_hash_find(&configuration_hash, host, host_len, (void **) &tmp) == SUCCESS) {
873 php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
874 }
875 }
876 }
877 /* }}} */
878
879 /* {{{ cfg_get_entry
880 */
cfg_get_entry(const char * name,uint name_length)881 PHPAPI zval *cfg_get_entry(const char *name, uint name_length)
882 {
883 zval *tmp;
884
885 if (zend_hash_find(&configuration_hash, name, name_length, (void **) &tmp) == SUCCESS) {
886 return tmp;
887 } else {
888 return NULL;
889 }
890 }
891 /* }}} */
892
893 /* {{{ cfg_get_long
894 */
cfg_get_long(const char * varname,long * result)895 PHPAPI int cfg_get_long(const char *varname, long *result)
896 {
897 zval *tmp, var;
898
899 if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) {
900 *result = 0;
901 return FAILURE;
902 }
903 var = *tmp;
904 zval_copy_ctor(&var);
905 convert_to_long(&var);
906 *result = Z_LVAL(var);
907 return SUCCESS;
908 }
909 /* }}} */
910
911 /* {{{ cfg_get_double
912 */
cfg_get_double(const char * varname,double * result)913 PHPAPI int cfg_get_double(const char *varname, double *result)
914 {
915 zval *tmp, var;
916
917 if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) {
918 *result = (double) 0;
919 return FAILURE;
920 }
921 var = *tmp;
922 zval_copy_ctor(&var);
923 convert_to_double(&var);
924 *result = Z_DVAL(var);
925 return SUCCESS;
926 }
927 /* }}} */
928
929 /* {{{ cfg_get_string
930 */
cfg_get_string(const char * varname,char ** result)931 PHPAPI int cfg_get_string(const char *varname, char **result)
932 {
933 zval *tmp;
934
935 if (zend_hash_find(&configuration_hash, varname, strlen(varname)+1, (void **) &tmp) == FAILURE) {
936 *result = NULL;
937 return FAILURE;
938 }
939 *result = Z_STRVAL_P(tmp);
940 return SUCCESS;
941 }
942 /* }}} */
943
php_ini_get_configuration_hash(void)944 PHPAPI HashTable* php_ini_get_configuration_hash(void) /* {{{ */
945 {
946 return &configuration_hash;
947 } /* }}} */
948
949 /*
950 * Local variables:
951 * tab-width: 4
952 * c-basic-offset: 4
953 * indent-tabs-mode: t
954 * End:
955 * vim600: sw=4 ts=4 fdm=marker
956 * vim<600: sw=4 ts=4
957 */
958