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