diff options
author | Jani Taskinen <jani@php.net> | 2007-09-28 02:05:10 +0000 |
---|---|---|
committer | Jani Taskinen <jani@php.net> | 2007-09-28 02:05:10 +0000 |
commit | 09b6f37f20b239dd021c21a1756629c4a64dc2da (patch) | |
tree | 635d42eb3591448faedff41f62ce0fff087ea467 /main/php_ini.c | |
parent | 0d3bdf23d24ede05b07d613d030514861ab475e5 (diff) | |
download | php-git-09b6f37f20b239dd021c21a1756629c4a64dc2da.tar.gz |
MFH:
- Added ".htaccess" style user-defined php.ini files support for
CGI/FastCGI.
- Added support for special [PATH=/opt/httpd/www.example.com/] sections
in php.ini. All directives set in these sections will not be able to be
overridden in user-defined ini-files or during runtime in the specified
path.
- Improved php.ini handling:
. Added better error reporting for syntax errors in php.ini files
. Allowed "ini-variables" to be used almost everywhere ini php.ini files
. Allowed using alphanumeric/variable indexes in "array" ini options
. Fixed get_cfg_var() to be able to return "array" ini options
- Fixed bug #27372 (parse error loading browscap.ini at apache startup)
- Fixed bug #42069 (parse_ini_file() allows using some non-alpha numeric
characters)
Diffstat (limited to 'main/php_ini.c')
-rw-r--r-- | main/php_ini.c | 300 |
1 files changed, 239 insertions, 61 deletions
diff --git a/main/php_ini.c b/main/php_ini.c index 390883da45..fd0e560de1 100644 --- a/main/php_ini.c +++ b/main/php_ini.c @@ -21,6 +21,7 @@ #include "php.h" #include "ext/standard/info.h" #include "zend_ini.h" +#include "zend_ini_scanner.h" #include "php_ini.h" #include "ext/standard/dl.h" #include "zend_extensions.h" @@ -45,8 +46,8 @@ typedef struct _php_extension_lists { zend_llist functions; } php_extension_lists; - /* True globals */ +static HashTable *active_ini_hash; static HashTable configuration_hash; PHPAPI char *php_ini_opened_path=NULL; static php_extension_lists extension_lists; @@ -54,14 +55,13 @@ PHPAPI char *php_ini_scanned_files=NULL; /* {{{ php_ini_displayer_cb */ -static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type) +static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type TSRMLS_DC) { if (ini_entry->displayer) { ini_entry->displayer(ini_entry, type); } else { char *display_string; uint display_string_length, esc_html=0; - TSRMLS_FETCH(); if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { if (ini_entry->orig_value && ini_entry->orig_value[0]) { @@ -112,16 +112,16 @@ static int php_ini_displayer(zend_ini_entry *ini_entry, int module_number TSRMLS PUTS("<td class=\"e\">"); PHPWRITE(ini_entry->name, ini_entry->name_length - 1); PUTS("</td><td class=\"v\">"); - php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE); + php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE TSRMLS_CC); PUTS("</td><td class=\"v\">"); - php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG); + php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG TSRMLS_CC); PUTS("</td></tr>\n"); } else { PHPWRITE(ini_entry->name, ini_entry->name_length - 1); PUTS(" => "); - php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE); + php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE TSRMLS_CC); PUTS(" => "); - php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG); + php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG TSRMLS_CC); PUTS("\n"); } return 0; @@ -148,7 +148,6 @@ PHPAPI void display_ini_entries(zend_module_entry *module) /* }}} */ /* php.ini support */ - #ifdef ZTS # if (ZEND_DEBUG) # define ZEND_EXTENSION_TOKEN "zend_extension_debug_ts" @@ -163,17 +162,46 @@ PHPAPI void display_ini_entries(zend_module_entry *module) # endif #endif -/* {{{ php_config_ini_parser_cb +/* {{{ config_zval_dtor */ -static void php_config_ini_parser_cb(zval *arg1, zval *arg2, int callback_type, void *arg) +void config_zval_dtor(zval *zvalue) { + if (Z_TYPE_P(zvalue) == IS_ARRAY) { + zend_hash_destroy(Z_ARRVAL_P(zvalue)); + free(Z_ARRVAL_P(zvalue)); + } else if (Z_TYPE_P(zvalue) == IS_STRING) { + free(Z_STRVAL_P(zvalue)); + } +} +/* Reset / free active_ini_sectin global */ +#define RESET_ACTIVE_INI_HASH() do { \ + active_ini_hash = NULL; \ +} while (0) +/* }}} */ + +/* {{{ php_ini_parser_cb + */ +static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, HashTable *target_hash) +{ + zval *entry; + HashTable *active_hash; + + if (active_ini_hash) { + active_hash = active_ini_hash; + } else { + active_hash = target_hash; + } + switch (callback_type) { case ZEND_INI_PARSER_ENTRY: { - zval *entry; - if (!arg2) { + /* bare string - nothing to do */ break; } + +/* FIXME: Should the extension loading be disabled for PATH sections? */ + + /* PHP and Zend extensions are not added into configuration hash! */ if (!strcasecmp(Z_STRVAL_P(arg1), "extension")) { /* load function module */ zval copy; @@ -185,41 +213,101 @@ static void php_config_ini_parser_cb(zval *arg1, zval *arg2, int callback_type, char *extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2)); zend_llist_add_element(&extension_lists.engine, &extension_name); + + /* All other entries are added into either configuration_hash or active ini section array */ } else { - zend_hash_update(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, arg2, sizeof(zval), (void **) &entry); + /* Store in active hash */ + zend_hash_update(active_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, arg2, sizeof(zval), (void **) &entry); Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry)); } } break; case ZEND_INI_PARSER_POP_ENTRY: { - zval *hash; - zval **find_hash; - zval *element; + zval *option_arr; + zval *find_arr; if (!arg2) { /* bare string - nothing to do */ break; } - if (zend_hash_find(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, (void **) &find_hash) == FAILURE) { - ALLOC_ZVAL(hash); - array_init(hash); +/* fprintf(stdout, "ZEND_INI_PARSER_POP_ENTRY: %s[%s] = %s\n",Z_STRVAL_P(arg1), Z_STRVAL_P(arg3), Z_STRVAL_P(arg2)); */ + + /* If option not found in hash or is not an array -> create array, otherwise add to existing array */ + 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) { + option_arr = (zval *) pemalloc(sizeof(zval), 1); + INIT_PZVAL(option_arr); + Z_TYPE_P(option_arr) = IS_ARRAY; + Z_ARRVAL_P(option_arr) = (HashTable *) pemalloc(sizeof(HashTable), 1); + zend_hash_init(Z_ARRVAL_P(option_arr), 0, NULL, (dtor_func_t) config_zval_dtor, 1); + zend_hash_update(active_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, option_arr, sizeof(zval), (void **) &find_arr); + free(option_arr); + } - zend_hash_update(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, &hash, sizeof(zval *), NULL); + /* arg3 is possible option offset name */ + if (arg3 && Z_STRLEN_P(arg3) > 0) { + zend_symtable_update(Z_ARRVAL_P(find_arr), Z_STRVAL_P(arg3), Z_STRLEN_P(arg3) + 1, arg2, sizeof(zval), (void **) &entry); } else { - hash = *find_hash; + zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2, sizeof(zval), (void **) &entry); } - - ALLOC_ZVAL(element); - *element = *arg2; - zval_copy_ctor(element); - INIT_PZVAL(element); - add_next_index_zval(hash, element); + Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry)); } break; - case ZEND_INI_PARSER_SECTION: + case ZEND_INI_PARSER_SECTION: { /* Create an array of entries of each section */ + +/* fprintf(stdout, "ZEND_INI_PARSER_SECTION: %s\n",Z_STRVAL_P(arg1)); */ + + char *key = NULL; + uint key_len; + + /* Only PATH sections are handled here! */ + if (!strncasecmp(Z_STRVAL_P(arg1), "PATH", sizeof("PATH") - 1)) { + key = Z_STRVAL_P(arg1); + key = key + sizeof("PATH") - 1; + key_len = Z_STRLEN_P(arg1) - sizeof("PATH") + 1; + +#if 0 /* Disable HOST sections for now. If someone can come up with some good usage case, then I can reconsider :) */ + } else if (!strncasecmp(Z_STRVAL_P(arg1), "HOST", sizeof("HOST") - 1)) { + key = Z_STRVAL_P(arg1); + key = key + sizeof("HOST") - 1; + key_len = Z_STRLEN_P(arg1) - sizeof("HOST") + 1; +#endif + } + + if (key && key_len > 0) { + /* Strip any trailing slashes */ + while (key_len > 0 && (key[key_len - 1] == '/' || key[key_len - 1] == '\\')) { + key_len--; + key[key_len] = 0; + } + + /* Strip any leading whitespace and '=' */ + while (*key && ( + *key == '=' || + *key == ' ' || + *key == '\t' + )) { + key++; + key_len--; + } + + /* Search for existing entry and if it does not exist create one */ + if (zend_hash_find(target_hash, key, key_len + 1, (void **) &entry) == FAILURE) { + zval *section_arr; + + section_arr = (zval *) pemalloc(sizeof(zval), 1); + INIT_PZVAL(section_arr); + Z_TYPE_P(section_arr) = IS_ARRAY; + Z_ARRVAL_P(section_arr) = (HashTable *) pemalloc(sizeof(HashTable), 1); + zend_hash_init(Z_ARRVAL_P(section_arr), 0, NULL, (dtor_func_t) config_zval_dtor, 1); + zend_hash_update(target_hash, key, key_len + 1, section_arr, sizeof(zval), (void **) &entry); + free(section_arr); + } + active_ini_hash = Z_ARRVAL_P(entry); + } + } break; } } @@ -244,16 +332,6 @@ static void php_load_zend_extension_cb(void *arg TSRMLS_DC) } /* }}} */ -/* {{{ pvalue_config_destructor - */ -static void pvalue_config_destructor(zval *pvalue) -{ - if (Z_TYPE_P(pvalue) == IS_STRING) { - free(Z_STRVAL_P(pvalue)); - } -} -/* }}} */ - /* {{{ php_init_config */ int php_init_config(TSRMLS_D) @@ -264,14 +342,8 @@ int php_init_config(TSRMLS_D) char *open_basedir; int free_ini_search_path = 0; zend_file_handle fh; - struct stat sb; - char ini_file[MAXPATHLEN]; - char *p; - zend_llist scanned_ini_list; - int l, total_l=0; - zend_llist_element *element; - if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) pvalue_config_destructor, 1) == FAILURE) { + if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) config_zval_dtor, 1) == FAILURE) { return FAILURE; } @@ -281,7 +353,6 @@ int php_init_config(TSRMLS_D) zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1); zend_llist_init(&extension_lists.functions, sizeof(zval), (llist_dtor_func_t) ZVAL_DESTRUCTOR, 1); - zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1); safe_mode_state = PG(safe_mode); open_basedir = PG(open_basedir); @@ -492,8 +563,9 @@ int php_init_config(TSRMLS_D) if (fh.handle.fp) { fh.type = ZEND_HANDLE_FP; + RESET_ACTIVE_INI_HASH(); - zend_parse_ini_file(&fh, 1, php_config_ini_parser_cb, &extension_lists); + zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC); { zval tmp; @@ -501,6 +573,8 @@ int php_init_config(TSRMLS_D) Z_STRLEN(tmp) = strlen(fh.filename); Z_STRVAL(tmp) = zend_strndup(fh.filename, Z_STRLEN(tmp)); Z_TYPE(tmp) = IS_STRING; + tmp.refcount = 0; + zend_hash_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path"), (void *) &tmp, sizeof(zval), NULL); if (php_ini_opened_path) { efree(php_ini_opened_path); @@ -514,10 +588,24 @@ int php_init_config(TSRMLS_D) if (!sapi_module.php_ini_ignore && strlen(PHP_CONFIG_FILE_SCAN_DIR)) { struct dirent **namelist; int ndir, i; + struct stat sb; + char ini_file[MAXPATHLEN]; + char *p; + zend_file_handle fh; + zend_llist scanned_ini_list; + zend_llist_element *element; + int l, total_l = 0; + + /* Reset active ini section */ + RESET_ACTIVE_INI_HASH(); if ((ndir = php_scandir(PHP_CONFIG_FILE_SCAN_DIR, &namelist, 0, php_alphasort)) > 0) { + zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1); + memset(&fh, 0, sizeof(fh)); + for (i = 0; i < ndir; i++) { - /* check for a .ini extension */ + + /* check for any file with .ini extension */ if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) { free(namelist[i]); continue; @@ -528,12 +616,14 @@ int php_init_config(TSRMLS_D) if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) { fh.filename = ini_file; fh.type = ZEND_HANDLE_FP; - zend_parse_ini_file(&fh, 1, php_config_ini_parser_cb, &extension_lists); - /* Here, add it to the list of ini files read */ - l = strlen(ini_file); - total_l += l + 2; - p = estrndup(ini_file, l); - zend_llist_add_element(&scanned_ini_list, &p); + + if (zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC) == SUCCESS) { + /* Here, add it to the list of ini files read */ + l = strlen(ini_file); + total_l += l + 2; + p = estrndup(ini_file, l); + zend_llist_add_element(&scanned_ini_list, &p); + } } } } @@ -541,14 +631,17 @@ int php_init_config(TSRMLS_D) } free(namelist); - /* - * Don't need an extra byte for the \0 in this malloc as the last - * element will not get a trailing , which gives us the byte for the \0 - */ if (total_l) { - php_ini_scanned_files = (char *) malloc(total_l); - *php_ini_scanned_files = '\0'; + int php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0; + php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1); + if (!php_ini_scanned_files_len) { + *php_ini_scanned_files = '\0'; + } + total_l += php_ini_scanned_files_len; for (element = scanned_ini_list.head; element; element = element->next) { + if (php_ini_scanned_files_len) { + strlcat(php_ini_scanned_files, ",\n", total_l); + } strlcat(php_ini_scanned_files, *(char **)element->data, total_l); strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l); } @@ -558,7 +651,9 @@ int php_init_config(TSRMLS_D) } if (sapi_module.ini_entries) { - zend_parse_ini_string(sapi_module.ini_entries, 1, php_config_ini_parser_cb, &extension_lists); + /* Reset active ini section */ + RESET_ACTIVE_INI_HASH(); + 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); } return SUCCESS; @@ -594,6 +689,81 @@ void php_ini_register_extensions(TSRMLS_D) } /* }}} */ +/* {{{ php_parse_user_ini_file + */ +PHPAPI int php_parse_user_ini_file(char *dirname, char *ini_filename, HashTable *target_hash TSRMLS_DC) +{ + struct stat sb; + char ini_file[MAXPATHLEN]; + zend_file_handle fh; + + snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename); + + if (VCWD_STAT(ini_file, &sb) == 0) { + if (S_ISREG(sb.st_mode)) { + memset(&fh, 0, sizeof(fh)); + if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) { + fh.filename = ini_file; + fh.type = ZEND_HANDLE_FP; + + /* Reset active ini section */ + RESET_ACTIVE_INI_HASH(); + + 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) { + /* FIXME: Add parsed file to the list of user files read? */ + return SUCCESS; + } + return FAILURE; + } + } + } + return FAILURE; +} +/* }}} */ + +/* {{{ php_ini_activate_config + */ +PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage TSRMLS_DC) +{ + char *str; + zval *data; + uint str_len; + ulong num_index; + + /* Walk through config hash and alter matching ini entries using the values found in the hash */ + for (zend_hash_internal_pointer_reset(source_hash); + zend_hash_get_current_key_ex(source_hash, &str, &str_len, &num_index, 0, NULL) == HASH_KEY_IS_STRING; + zend_hash_move_forward(source_hash) + ) { + zend_hash_get_current_data(source_hash, (void **) &data); + zend_alter_ini_entry_ex(str, str_len, Z_STRVAL_P(data), Z_STRLEN_P(data), modify_type, stage, 0 TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ php_ini_activate_per_dir_config + */ +PHPAPI void php_ini_activate_per_dir_config(char *path, uint path_len TSRMLS_DC) +{ + zval *tmp; + char *ptr; + + /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */ + if (path && path_len) { + ptr = path + 1; + while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) { + *ptr = 0; + /* Search for source array matching the path from configuration_hash */ + if (zend_hash_find(&configuration_hash, path, path_len, (void **) &tmp) == SUCCESS) { + php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE TSRMLS_CC); + } + *ptr = '/'; + ptr++; + } + } +} +/* }}} */ + /* {{{ cfg_get_entry */ PHPAPI zval *cfg_get_entry(char *name, uint name_length) @@ -659,6 +829,14 @@ PHPAPI int cfg_get_string(char *varname, char **result) } /* }}} */ +#if ZEND_DEBUG +#include "php_ini.h" +PHPAPI HashTable get_configuration_hash(void) +{ + return configuration_hash; +} +#endif + /* * Local variables: * tab-width: 4 |