- 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)
This commit is contained in:
Jani Taskinen 2007-09-28 02:05:10 +00:00
parent 0d3bdf23d2
commit 09b6f37f20
21 changed files with 1734 additions and 577 deletions

View file

@ -265,6 +265,9 @@ struct _zend_scanner_globals {
int yy_start_stack_depth;
int *yy_start_stack;
/* For ini scanner. Modes are: ZEND_INI_SCANNER_NORMAL, ZEND_INI_SCANNER_RAW */
int scanner_mode;
#ifdef ZEND_MULTIBYTE
/* original (unfiltered) script */
char *script_org;

View file

@ -164,7 +164,6 @@ END_EXTERN_C()
#define INI_ORIG_STR(name) zend_ini_string((name), sizeof(name), 1)
#define INI_ORIG_BOOL(name) ((zend_bool) INI_ORIG_INT(name))
#define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries, module_number TSRMLS_CC)
#define UNREGISTER_INI_ENTRIES() zend_unregister_ini_entries(module_number TSRMLS_CC)
#define DISPLAY_INI_ENTRIES() display_ini_entries(zend_module)
@ -193,15 +192,16 @@ END_EXTERN_C()
#define ZEND_INI_STAGE_HTACCESS (1<<5)
/* INI parsing engine */
typedef void (*zend_ini_parser_cb_t)(zval *arg1, zval *arg2, int callback_type, void *arg);
typedef void (*zend_ini_parser_cb_t)(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC);
BEGIN_EXTERN_C()
ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_errors, zend_ini_parser_cb_t ini_parser_cb, void *arg);
ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, zend_ini_parser_cb_t ini_parser_cb, void *arg);
ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC);
ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC);
END_EXTERN_C()
#define ZEND_INI_PARSER_ENTRY 1
#define ZEND_INI_PARSER_SECTION 2
#define ZEND_INI_PARSER_POP_ENTRY 3
/* INI entries */
#define ZEND_INI_PARSER_ENTRY 1 /* Normal entry: foo = bar */
#define ZEND_INI_PARSER_SECTION 2 /* Section: [foobar] */
#define ZEND_INI_PARSER_POP_ENTRY 3 /* Offset entry: foo[] = bar */
typedef struct _zend_ini_parser_param {
zend_ini_parser_cb_t ini_parser_cb;

View file

@ -13,13 +13,15 @@
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Zeev Suraski <zeev@zend.com> |
| Authors: Zeev Suraski <zeev@zend.com> |
| Jani Taskinen <jani@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#define DEBUG_CFG_PARSER 0
#include "zend.h"
#include "zend_API.h"
#include "zend_ini.h"
@ -27,32 +29,23 @@
#include "zend_ini_scanner.h"
#include "zend_extensions.h"
#define YYERROR_VERBOSE
#define YYSTYPE zval
#ifdef ZTS
#define YYPARSE_PARAM tsrm_ls
#define YYLEX_PARAM tsrm_ls
#endif
#define ZEND_INI_PARSER_CB (CG(ini_parser_param))->ini_parser_cb
#define ZEND_INI_PARSER_ARG (CG(ini_parser_param))->arg
int ini_lex(zval *ini_lval TSRMLS_DC);
#ifdef ZTS
int ini_parse(void *arg);
#else
int ini_parse(void);
#endif
zval yylval;
#define ZEND_INI_PARSER_CB (CG(ini_parser_param))->ini_parser_cb
#define ZEND_INI_PARSER_ARG (CG(ini_parser_param))->arg
#ifndef ZTS
extern int ini_lex(zval *ini_lval TSRMLS_DC);
extern FILE *ini_in;
extern void init_cfg_scanner(void);
#endif
void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
/* {{{ zend_ini_do_op()
*/
static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
{
int i_result;
int i_op1, i_op2;
@ -91,16 +84,22 @@ void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2)
Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
Z_TYPE_P(result) = IS_STRING;
}
/* }}} */
void zend_ini_init_string(zval *result)
/* {{{ zend_ini_init_string()
*/
static void zend_ini_init_string(zval *result)
{
Z_STRVAL_P(result) = malloc(1);
Z_STRVAL_P(result)[0] = 0;
Z_STRLEN_P(result) = 0;
Z_TYPE_P(result) = IS_STRING;
}
/* }}} */
void zend_ini_add_string(zval *result, zval *op1, zval *op2)
/* {{{ zend_ini_add_string()
*/
static void zend_ini_add_string(zval *result, zval *op1, zval *op2)
{
int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
@ -110,12 +109,15 @@ void zend_ini_add_string(zval *result, zval *op1, zval *op2)
Z_STRLEN_P(result) = length;
Z_TYPE_P(result) = IS_STRING;
}
/* }}} */
void zend_ini_get_constant(zval *result, zval *name)
/* {{{ zend_ini_get_constant()
*/
static void zend_ini_get_constant(zval *result, zval *name TSRMLS_DC)
{
zval z_constant;
TSRMLS_FETCH();
/* If name contains ':' it is not a constant. Bug #26893. */
if (!memchr(Z_STRVAL_P(name), ':', Z_STRLEN_P(name))
&& zend_get_constant(Z_STRVAL_P(name), Z_STRLEN_P(name), &z_constant TSRMLS_CC)) {
/* z_constant is emalloc()'d */
@ -129,16 +131,20 @@ void zend_ini_get_constant(zval *result, zval *name)
*result = *name;
}
}
/* }}} */
void zend_ini_get_var(zval *result, zval *name)
/* {{{ zend_ini_get_var()
*/
static void zend_ini_get_var(zval *result, zval *name TSRMLS_DC)
{
zval curval;
char *envvar;
TSRMLS_FETCH();
/* Fetch configuration option value */
if (zend_get_configuration_directive(Z_STRVAL_P(name), Z_STRLEN_P(name)+1, &curval) == SUCCESS) {
Z_STRVAL_P(result) = zend_strndup(Z_STRVAL(curval), Z_STRLEN(curval));
Z_STRLEN_P(result) = Z_STRLEN(curval);
/* ..or if not found, try ENV */
} else if ((envvar = zend_getenv(Z_STRVAL_P(name), Z_STRLEN_P(name) TSRMLS_CC)) != NULL ||
(envvar = getenv(Z_STRVAL_P(name))) != NULL) {
Z_STRVAL_P(result) = strdup(envvar);
@ -147,9 +153,11 @@ void zend_ini_get_var(zval *result, zval *name)
zend_ini_init_string(result);
}
}
/* }}} */
static void ini_error(char *str)
/* {{{ ini_error()
*/
static void ini_error(char *msg)
{
char *error_buf;
int error_buf_len;
@ -158,10 +166,10 @@ static void ini_error(char *str)
currently_parsed_filename = zend_ini_scanner_get_filename(TSRMLS_C);
if (currently_parsed_filename) {
error_buf_len = 128+strlen(currently_parsed_filename); /* should be more than enough */
error_buf_len = 128 + strlen(msg) + strlen(currently_parsed_filename); /* should be more than enough */
error_buf = (char *) emalloc(error_buf_len);
sprintf(error_buf, "Error parsing %s on line %d\n", currently_parsed_filename, zend_ini_scanner_get_lineno(TSRMLS_C));
sprintf(error_buf, "%s in %s on line %d\n", msg, currently_parsed_filename, zend_ini_scanner_get_lineno(TSRMLS_C));
} else {
error_buf = estrdup("Invalid configuration directive\n");
}
@ -177,71 +185,87 @@ static void ini_error(char *str)
}
efree(error_buf);
}
/* }}} */
ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_errors, zend_ini_parser_cb_t ini_parser_cb, void *arg)
/* {{{ zend_parse_ini_file()
*/
ZEND_API int zend_parse_ini_file(zend_file_handle *fh, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC)
{
int retval;
zend_ini_parser_param ini_parser_param;
TSRMLS_FETCH();
ini_parser_param.ini_parser_cb = ini_parser_cb;
ini_parser_param.arg = arg;
CG(ini_parser_param) = &ini_parser_param;
if (zend_ini_open_file_for_scanning(fh TSRMLS_CC)==FAILURE) {
if (zend_ini_open_file_for_scanning(fh, scanner_mode TSRMLS_CC) == FAILURE) {
return FAILURE;
}
CG(ini_parser_unbuffered_errors) = unbuffered_errors;
retval = ini_parse(TSRMLS_C);
zend_ini_close_file(fh TSRMLS_CC);
shutdown_ini_scanner(TSRMLS_C);
if (retval == 0) {
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
/* {{{ zend_parse_ini_string()
*/
ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg TSRMLS_DC)
{
int retval;
zend_ini_parser_param ini_parser_param;
ini_parser_param.ini_parser_cb = ini_parser_cb;
ini_parser_param.arg = arg;
CG(ini_parser_param) = &ini_parser_param;
if (zend_ini_prepare_string_for_scanning(str, scanner_mode TSRMLS_CC) == FAILURE) {
return FAILURE;
}
CG(ini_parser_unbuffered_errors) = unbuffered_errors;
retval = ini_parse(TSRMLS_C);
zend_ini_close_file(fh TSRMLS_CC);
shutdown_ini_scanner(TSRMLS_C);
if (retval==0) {
if (retval == 0) {
return SUCCESS;
} else {
return FAILURE;
}
}
ZEND_API int zend_parse_ini_string(char *str, zend_bool unbuffered_errors, zend_ini_parser_cb_t ini_parser_cb, void *arg)
{
zend_ini_parser_param ini_parser_param;
TSRMLS_FETCH();
ini_parser_param.ini_parser_cb = ini_parser_cb;
ini_parser_param.arg = arg;
CG(ini_parser_param) = &ini_parser_param;
if (zend_ini_prepare_string_for_scanning(str TSRMLS_CC)==FAILURE) {
return FAILURE;
}
CG(ini_parser_unbuffered_errors) = unbuffered_errors;
if (ini_parse(TSRMLS_C)) {
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
%}
%expect 1
%pure_parser
%token TC_SECTION
%token TC_RAW
%token TC_NUMBER
%token TC_STRING
%token TC_ENCAPSULATED_STRING
%token BRACK
%token SECTION
%token CFG_TRUE
%token CFG_FALSE
%token TC_OFFSET
%token TC_DOLLAR_CURLY
%token TC_VARNAME
%token TC_QUOTED_STRING
%token BOOL_TRUE
%token BOOL_FALSE
%token END_OF_LINE
%token '=' ':' ',' '.' '"' '\'' '^' '+' '-' '/' '*' '%' '$' '~' '<' '>' '?' '@'
%left '|' '&'
%right '~' '!'
%destructor { free(Z_STRVAL($$)); } TC_RAW TC_NUMBER TC_STRING TC_OFFSET TC_VARNAME TC_QUOTED_STRING BOOL_TRUE BOOL_FALSE
%%
statement_list:
@ -250,61 +274,94 @@ statement_list:
;
statement:
TC_STRING '=' string_or_value {
TC_SECTION section_string_or_value ']' {
#if DEBUG_CFG_PARSER
printf("'%s' = '%s'\n", Z_STRVAL($1), Z_STRVAL($3));
printf("SECTION: [%s]\n", Z_STRVAL($2));
#endif
ZEND_INI_PARSER_CB(&$1, &$3, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG);
ZEND_INI_PARSER_CB(&$2, NULL, NULL, ZEND_INI_PARSER_SECTION, ZEND_INI_PARSER_ARG TSRMLS_CC);
free(Z_STRVAL($2));
}
| TC_STRING '=' string_or_value {
#if DEBUG_CFG_PARSER
printf("NORMAL: '%s' = '%s'\n", Z_STRVAL($1), Z_STRVAL($3));
#endif
ZEND_INI_PARSER_CB(&$1, &$3, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
free(Z_STRVAL($1));
free(Z_STRVAL($3));
}
| TC_STRING BRACK '=' string_or_value {
| TC_OFFSET option_offset ']' '=' string_or_value {
#if DEBUG_CFG_PARSER
printf("'%s'[ ] = '%s'\n", Z_STRVAL($1), Z_STRVAL($4));
printf("OFFSET: '%s'[%s] = '%s'\n", Z_STRVAL($1), Z_STRVAL($2), Z_STRVAL($5));
#endif
ZEND_INI_PARSER_CB(&$1, &$4, ZEND_INI_PARSER_POP_ENTRY, ZEND_INI_PARSER_ARG);
ZEND_INI_PARSER_CB(&$1, &$5, &$2, ZEND_INI_PARSER_POP_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
free(Z_STRVAL($1));
free(Z_STRVAL($4));
free(Z_STRVAL($2));
free(Z_STRVAL($5));
}
| TC_STRING { ZEND_INI_PARSER_CB(&$1, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG); free(Z_STRVAL($1)); }
| SECTION { ZEND_INI_PARSER_CB(&$1, NULL, ZEND_INI_PARSER_SECTION, ZEND_INI_PARSER_ARG); free(Z_STRVAL($1)); }
| '\n'
| TC_STRING { ZEND_INI_PARSER_CB(&$1, NULL, NULL, ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC); free(Z_STRVAL($1)); }
| END_OF_LINE
;
section_string_or_value:
TC_RAW { $$ = $1; }
| section_var_list { $$ = $1; }
| '"' encapsed_list '"' { $$ = $2; }
| /* empty */ { zend_ini_init_string(&$$); }
;
string_or_value:
expr { $$ = $1; }
| CFG_TRUE { $$ = $1; }
| CFG_FALSE { $$ = $1; }
| '\n' { zend_ini_init_string(&$$); }
| /* empty */ { zend_ini_init_string(&$$); }
expr { $$ = $1; }
| TC_RAW { $$ = $1; }
| TC_NUMBER { $$ = $1; }
| BOOL_TRUE { $$ = $1; }
| BOOL_FALSE { $$ = $1; }
| '"' encapsed_list '"' { $$ = $2; }
| END_OF_LINE { zend_ini_init_string(&$$); }
;
option_offset:
TC_NUMBER { $$ = $1; }
| TC_RAW { $$ = $1; }
| var_string_list { $$ = $1; }
| '"' encapsed_list '"' { $$ = $2; }
| /* empty */ { zend_ini_init_string(&$$); }
;
encapsed_list:
encapsed_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
| encapsed_list TC_QUOTED_STRING { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
| /* empty */ { zend_ini_init_string(&$$); }
;
section_var_list:
cfg_var_ref { $$ = $1; }
| TC_STRING { $$ = $1; }
| section_var_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
| section_var_list TC_STRING { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
;
var_string_list:
cfg_var_ref { $$ = $1; }
| TC_ENCAPSULATED_STRING { $$ = $1; }
| constant_string { $$ = $1; }
| var_string_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free($2.value.str.val); }
| var_string_list TC_ENCAPSULATED_STRING { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
| var_string_list constant_string { zend_ini_add_string(&$$, &$1, &$2); free($2.value.str.val); }
;
cfg_var_ref:
TC_DOLLAR_CURLY TC_STRING '}' { zend_ini_get_var(&$$, &$2); free($2.value.str.val); }
cfg_var_ref { $$ = $1; }
| constant_string { $$ = $1; }
| var_string_list cfg_var_ref { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
| var_string_list constant_string { zend_ini_add_string(&$$, &$1, &$2); free(Z_STRVAL($2)); }
;
expr:
var_string_list { $$ = $1; }
| expr '|' expr { zend_ini_do_op('|', &$$, &$1, &$3); }
| expr '&' expr { zend_ini_do_op('&', &$$, &$1, &$3); }
| '~' expr { zend_ini_do_op('~', &$$, &$2, NULL); }
| '!' expr { zend_ini_do_op('!', &$$, &$2, NULL); }
| '(' expr ')' { $$ = $2; }
var_string_list { $$ = $1; }
| expr '|' expr { zend_ini_do_op('|', &$$, &$1, &$3); }
| expr '&' expr { zend_ini_do_op('&', &$$, &$1, &$3); }
| '~' expr { zend_ini_do_op('~', &$$, &$2, NULL); }
| '!' expr { zend_ini_do_op('!', &$$, &$2, NULL); }
| '(' expr ')' { $$ = $2; }
;
cfg_var_ref:
TC_DOLLAR_CURLY TC_VARNAME '}' { zend_ini_get_var(&$$, &$2 TSRMLS_CC); free(Z_STRVAL($2)); }
;
constant_string:
TC_STRING { zend_ini_get_constant(&$$, &$1); }
TC_STRING { zend_ini_get_constant(&$$, &$1 TSRMLS_CC); }
;
/*

View file

@ -22,13 +22,18 @@
#ifndef _ZEND_INI_SCANNER_H
#define _ZEND_INI_SCANNER_H
/* Scanner modes */
#define ZEND_INI_SCANNER_NORMAL 0 /* Normal mode. [DEFAULT] */
#define ZEND_INI_SCANNER_RAW 1 /* Raw mode. Option values are not parsed */
BEGIN_EXTERN_C()
int zend_ini_scanner_get_lineno(TSRMLS_D);
char *zend_ini_scanner_get_filename(TSRMLS_D);
int zend_ini_open_file_for_scanning(zend_file_handle *fh TSRMLS_DC);
int zend_ini_prepare_string_for_scanning(char *str TSRMLS_DC);
int zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mode TSRMLS_DC);
int zend_ini_prepare_string_for_scanning(char *str, int scanner_mode TSRMLS_DC);
void zend_ini_close_file(zend_file_handle *fh TSRMLS_DC);
int ini_lex(zval *ini_lval TSRMLS_DC);
void shutdown_ini_scanner(TSRMLS_D);
END_EXTERN_C()
#endif /* _ZEND_INI_SCANNER_H */

View file

@ -13,21 +13,71 @@
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Zeev Suraski <zeev@zend.com> |
| Authors: Zeev Suraski <zeev@zend.com> |
| Jani Taskinen <jani@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#define DEBUG_CFG_SCANNER 0
#define yyleng SCNG(yy_leng)
#define yytext SCNG(yy_text)
#define yytext_ptr SCNG(yy_text)
#define yyin SCNG(yy_in)
#define yyout SCNG(yy_out)
/* How it works (for the core ini directives):
* ===========================================
*
* 1. Scanner scans file for tokens and passes them to parser.
* 2. Parser parses the tokens and passes the name/value pairs to the callback
* function which stores them in the configuration hash table.
* 3. Later REGISTER_INI_ENTRIES() is called which triggers the actual
* registering of ini entries and uses zend_get_configuration_directive()
* to fetch the previously stored name/value pair from configuration hash table
* and registers the static ini entries which match the name to the value
* into EG(ini_directives) hash table.
* 4. PATH section entries are used per-request from down to top, each overriding
* previous if one exists. zend_alter_ini_entry() is called for each entry.
* Settings in PATH section are ZEND_INI_SYSTEM accessible and thus mimics the
* php_admin_* directives used within Apache httpd.conf when PHP is compiled as
* module for Apache.
* 5. User defined ini files (like .htaccess for apache) are parsed for each request and
* stored in separate hash defined by SAPI.
*/
/* TODO: (ordered by importance :-)
* ===============================================================================
*
* - Separate constant lookup totally from plain strings (using CONSTANT pattern)
* - Add #if .. #else .. #endif and ==, !=, <, > , <=, >= operators
* - Add #include "some.ini"
* - Allow variables to refer to options also when using parse_ini_file()
*
*/
/* These are not needed when yymore() is not used */
/*
#define yy_last_accepting_state SCNG(_yy_last_accepting_state)
#define yy_last_accepting_cpos SCNG(_yy_last_accepting_cpos)
#define yy_more_flag SCNG(_yy_more_flag)
#define yy_more_len SCNG(_yy_more_len)
*/
%}
%x ST_DOUBLE_QUOTES
%x ST_OFFSET
%x ST_RAW
%x ST_SECTION_RAW
%x ST_SECTION_VALUE
%x ST_VALUE
%x ST_VARNAME
%option stack
%{
#include <errno.h>
#include "zend.h"
@ -35,9 +85,6 @@
#include <zend_ini_parser.h>
#include "zend_ini_scanner.h"
#undef YYSTYPE
#define YYSTYPE zval
#define YY_DECL int ini_lex(zval *ini_lval TSRMLS_DC)
/* Globals Macros */
@ -48,204 +95,417 @@ ZEND_API ts_rsrc_id ini_scanner_globals_id;
ZEND_API zend_scanner_globals ini_scanner_globals;
#endif
# define YY_INPUT(buf, result, max_size) \
if ( ((result = zend_stream_read(yyin, buf, max_size TSRMLS_CC)) == 0) \
&& zend_stream_ferror( yyin TSRMLS_CC) ) \
YY_FATAL_ERROR( "input in flex scanner failed" );
/* Eat trailing whitespace + extra char */
#define EAT_TRAILING_WHITESPACE_EX(ch) \
while (yyleng > 0 && ( \
(ch != 'X' && yytext[yyleng - 1] == ch) || \
yytext[yyleng - 1] == '\n' || \
yytext[yyleng - 1] == '\r' || \
yytext[yyleng - 1] == '\t' || \
yytext[yyleng - 1] == ' ') \
) { \
yyleng--; \
yytext[yyleng]=0; \
}
/* Eat trailing whitespace */
#define EAT_TRAILING_WHITESPACE() EAT_TRAILING_WHITESPACE_EX('X')
#define zend_ini_copy_value(retval, str, len) { \
Z_STRVAL_P(retval) = zend_strndup(str, len); \
Z_STRLEN_P(retval) = len; \
Z_TYPE_P(retval) = IS_STRING; \
}
#define RETURN_TOKEN(type, str, len) { \
zend_ini_copy_value(ini_lval, str, len); \
return type; \
}
static char *ini_filename;
void init_ini_scanner(TSRMLS_D)
/* {{{ init_ini_scanner()
*/
static void init_ini_scanner(TSRMLS_D)
{
SCNG(lineno)=1;
SCNG(lineno) = 1;
SCNG(scanner_mode) = ZEND_INI_SCANNER_NORMAL;
SCNG(yy_start_stack_ptr) = 0;
SCNG(yy_start_stack_depth) = 0;
SCNG(current_buffer) = NULL;
}
/* }}} */
/* {{{ shutdown_ini_scanner()
*/
void shutdown_ini_scanner(TSRMLS_D)
{
if (SCNG(yy_start_stack)) {
yy_flex_free(SCNG(yy_start_stack));
SCNG(yy_start_stack) = NULL;
}
yy_delete_buffer(SCNG(current_buffer) TSRMLS_CC);
if (ini_filename) {
free(ini_filename);
}
}
/* }}} */
/* {{{ zend_ini_scanner_get_lineno()
*/
int zend_ini_scanner_get_lineno(TSRMLS_D)
{
return SCNG(lineno);
}
/* }}} */
/* {{{ zend_ini_scanner_get_filename()
*/
char *zend_ini_scanner_get_filename(TSRMLS_D)
{
return ini_filename;
}
/* }}} */
int zend_ini_open_file_for_scanning(zend_file_handle *fh TSRMLS_DC)
/* {{{ zend_ini_open_file_for_scanning()
*/
int zend_ini_open_file_for_scanning(zend_file_handle *fh, int scanner_mode TSRMLS_DC)
{
if (FAILURE == zend_stream_fixup(fh TSRMLS_CC)) {
return FAILURE;
}
init_ini_scanner(TSRMLS_C);
SCNG(scanner_mode) = scanner_mode;
yyin = fh;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE TSRMLS_CC) TSRMLS_CC);
ini_filename = fh->filename;
ini_filename = zend_strndup(fh->filename, strlen(fh->filename));
return SUCCESS;
}
/* }}} */
int zend_ini_prepare_string_for_scanning(char *str TSRMLS_DC)
/* {{{ zend_ini_prepare_string_for_scanning()
*/
int zend_ini_prepare_string_for_scanning(char *str, int scanner_mode TSRMLS_DC)
{
int len = strlen(str);
init_ini_scanner(TSRMLS_C);
SCNG(scanner_mode) = scanner_mode;
yyin = NULL;
yy_scan_buffer(str, len + 2 TSRMLS_CC);
ini_filename = NULL;
return SUCCESS;
}
/* }}} */
/* {{{ zend_ini_close_file()
*/
void zend_ini_close_file(zend_file_handle *fh TSRMLS_DC)
{
zend_stream_close(fh);
}
/* }}} */
/* {{{ zend_ini_escape_string()
*/
static void zend_ini_escape_string(zval *lval, char *str, int len, char quote_type TSRMLS_DC)
{
register char *s, *t;
char *end;
zend_ini_copy_value(lval, str, len);
/* convert escape sequences */
s = t = Z_STRVAL_P(lval);
end = s + Z_STRLEN_P(lval);
while (s < end) {
if (*s == '\\') {
s++;
if (s >= end) {
continue;
}
switch (*s) {
case 'n':
*t++ = '\n';
Z_STRLEN_P(lval)--;
break;
case 'r':
*t++ = '\r';
Z_STRLEN_P(lval)--;
break;
case 't':
*t++ = '\t';
Z_STRLEN_P(lval)--;
break;
case '"':
if (*s != quote_type) {
*t++ = '\\';
*t++ = *s;
break;
}
case '\\':
case '$':
*t++ = *s;
Z_STRLEN_P(lval)--;
break;
default:
*t++ = '\\';
*t++ = *s;
break;
}
} else {
*t++ = *s;
}
if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
SCNG(lineno)++;
}
s++;
}
*t = 0;
}
/* }}} */
%}
NEWLINE ("\r"|"\n"|"\r\n")
LNUM [0-9]+
DNUM ([0-9]*[\.][0-9]+)|([0-9]+[\.][0-9]*)
NUMBER {LNUM}|{DNUM}
ANY_CHAR (.|[\n])
NEWLINE ("\r"|"\n"|"\r\n")
TABS_AND_SPACES [ \t]
CONSTANT [a-zA-Z][a-zA-Z0-9_]*
LABEL [a-zA-Z0-9][a-zA-Z0-9._]*
TOKENS [:,.\[\]"'()|^&+-/*=%$!~<>?@]
OPERATORS [&|~()!]
LITERAL_DOLLAR ("$"+([^a-zA-Z0-9$"'\\{]|("\\"{ANY_CHAR})))
VALUE_CHARS ("{"*([^=\n\r;&|~()!$"'\\{]|("\\"{ANY_CHAR}))|{LITERAL_DOLLAR})
RAW_VALUE_CHARS [^=\n\r;]
SINGLE_QUOTED_CHARS [^']
SECTION_VALUE_CHARS ("{"*([^\n\r;$"'\\{\]]|("\\"{ANY_CHAR}))|{LITERAL_DOLLAR})
SECTION_RAW_CHARS [^\]\n\r]
/* Allow using ${foobar} inside quoted strings */
DOUBLE_QUOTES_CHARS ("{"*([^$"\\{]|("\\"{ANY_CHAR}))|{LITERAL_DOLLAR})
/* " */
%option nounput
%option noyywrap
%option noyylineno
%option noyy_top_state
%option never-interactive
%%
<INITIAL>[ ]*[\[][ ]*[\]][ ]* {
return BRACK;
}
<INITIAL>[ ]*("true"|"on"|"yes")[ ]* {
Z_STRVAL_P(ini_lval) = zend_strndup("1", 1);
Z_STRLEN_P(ini_lval) = 1;
Z_TYPE_P(ini_lval) = IS_STRING;
return CFG_TRUE;
}
<INITIAL>[ ]*("false"|"off"|"no"|"none"|"null")[ ]* {
Z_STRVAL_P(ini_lval) = zend_strndup("", 0);
Z_STRLEN_P(ini_lval) = 0;
Z_TYPE_P(ini_lval) = IS_STRING;
return CFG_FALSE;
}
<INITIAL>[[][^\]\n]+[\]][ ]*{NEWLINE}? {
/* SECTION */
/* eat trailing ] and spaces */
while (yyleng>0 && (yytext[yyleng-1]=='\n' || yytext[yyleng-1]=='\r' || yytext[yyleng-1]==']' || yytext[yyleng-1]==' ')) {
yyleng--;
yytext[yyleng]=0;
<INITIAL>"[" { /* Section start */
/* Enter section data lookup state */
if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
yy_push_state(ST_SECTION_RAW TSRMLS_CC);
} else {
yy_push_state(ST_SECTION_VALUE TSRMLS_CC);
}
return TC_SECTION;
}
<ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" { /* Raw string */
/* Eat leading and trailing single quotes */
if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
yytext++;
yyleng = yyleng - 2;
yytext[yyleng] = 0;
}
RETURN_TOKEN(TC_RAW, yytext, yyleng);
}
<ST_SECTION_RAW,ST_SECTION_VALUE>"]"{TABS_AND_SPACES}*{NEWLINE}? { /* End of section */
BEGIN(INITIAL);
SCNG(lineno)++;
/* eat leading [ */
yytext++;
yyleng--;
Z_STRVAL_P(ini_lval) = zend_strndup(yytext, yyleng);
Z_STRLEN_P(ini_lval) = yyleng;
Z_TYPE_P(ini_lval) = IS_STRING;
return SECTION;
return ']';
}
<INITIAL>["][^"]*["] {
char *p = yytext;
<INITIAL>{LABEL}"["{TABS_AND_SPACES}* { /* Start of option with offset */
/* Eat trailing whitespace and [ */
EAT_TRAILING_WHITESPACE_EX('[');
/* ENCAPSULATED TC_STRING */
while ((p = strpbrk(p, "\r\n"))) {
if (*p == '\r' && *(p + 1) == '\n') {
p++;
}
SCNG(lineno)++;
p++;
}
/* eat trailing " */
yytext[yyleng-1]=0;
/* eat leading " */
yytext++;
Z_STRVAL_P(ini_lval) = zend_strndup(yytext, yyleng - 2);
Z_STRLEN_P(ini_lval) = yyleng - 2;
Z_TYPE_P(ini_lval) = IS_STRING;
return TC_ENCAPSULATED_STRING;
/* Enter offset lookup state */
yy_push_state(ST_OFFSET TSRMLS_CC);
RETURN_TOKEN(TC_OFFSET, yytext, yyleng);
}
<INITIAL>"${" {
<ST_OFFSET>{TABS_AND_SPACES}*"]" { /* End of section or an option offset */
BEGIN(INITIAL);
return ']';
}
<ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>"${" { /* Variable start */
yy_push_state(ST_VARNAME TSRMLS_CC);
return TC_DOLLAR_CURLY;
}
<INITIAL>"}" {
Z_LVAL_P(ini_lval) = (long) yytext[0];
return yytext[0];
<ST_VARNAME>{LABEL} { /* Variable name */
RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
}
<INITIAL>[&|~$(){}!] {
return yytext[0];
<ST_VARNAME>"}" { /* Variable end */
yy_pop_state(TSRMLS_C);
return '}';
}
<INITIAL>[^=\n\r\t;|&$~(){}!"\[]+ {
/* STRING */
register int i;
<INITIAL,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* { /* TRUE value (when used outside option value/offset this causes parse error!) */
RETURN_TOKEN(BOOL_TRUE, "1", 1);
}
/* eat trailing whitespace */
for (i=yyleng-1; i>=0; i--) {
if (yytext[i]==' ' || yytext[i]=='\t') {
yytext[i]=0;
yyleng--;
} else {
break;
}
}
/* eat leading whitespace */
while (yytext[0]) {
if (yytext[0]==' ' || yytext[0]=='\t') {
yytext++;
yyleng--;
} else {
break;
}
}
if (yyleng!=0) {
Z_STRVAL_P(ini_lval) = zend_strndup(yytext, yyleng);
Z_STRLEN_P(ini_lval) = yyleng;
Z_TYPE_P(ini_lval) = IS_STRING;
return TC_STRING;
<INITIAL,ST_VALUE>("false"|"off"|"no"|"none"|"null"){TABS_AND_SPACES}* { /* FALSE value (when used outside option value/offset this causes parse error!)*/
RETURN_TOKEN(BOOL_FALSE, "", 0);
}
<INITIAL,ST_OFFSET>{LABEL} { /* Get option name or option offset value */
RETURN_TOKEN(TC_STRING, yytext, yyleng);
}
<INITIAL>{TABS_AND_SPACES}*[=]{TABS_AND_SPACES}* { /* Start option value */
if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
yy_push_state(ST_RAW TSRMLS_CC);
} else {
/* whitespace */
yy_push_state(ST_VALUE TSRMLS_CC);
}
return '=';
}
<INITIAL>[=\n] {
if (yytext[0] == '\n') {
SCNG(lineno)++;
<ST_RAW>{RAW_VALUE_CHARS}+ { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
/* Eat leading and trailing double quotes */
if (yytext[0] == '"' && yytext[yyleng - 1] == '"') {
yytext++;
yyleng = yyleng - 2;
yytext[yyleng] = 0;
}
RETURN_TOKEN(TC_RAW, yytext, yyleng);
}
<ST_SECTION_RAW>{SECTION_RAW_CHARS}+ { /* Raw value, only used when SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW. */
RETURN_TOKEN(TC_RAW, yytext, yyleng);
}
<ST_VALUE,ST_RAW>{NEWLINE} { /* End of option value */
BEGIN(INITIAL);
SCNG(lineno)++;
return END_OF_LINE;
}
<ST_VALUE,ST_OFFSET>{CONSTANT} { /* Get constant option value */
RETURN_TOKEN(TC_STRING, yytext, yyleng);
}
<ST_VALUE,ST_OFFSET>{NUMBER} { /* Get number option value as string */
RETURN_TOKEN(TC_NUMBER, yytext, yyleng);
}
<INITIAL>{TOKENS} { /* Disallow these chars outside option values */
return yytext[0];
}
<ST_VALUE>{OPERATORS}{TABS_AND_SPACES}* { /* Boolean operators */
return yytext[0];
}
<ST_VALUE>[=] { /* Make = used in option value to trigger error */
yyless(yyleng - 1);
BEGIN(INITIAL);
return END_OF_LINE;
}
<ST_VALUE>{VALUE_CHARS}+ { /* Get everything else as option/offset value */
/* Eat trailing tabs and spaces */
EAT_TRAILING_WHITESPACE();
RETURN_TOKEN(TC_STRING, yytext, yyleng);
}
<ST_SECTION_VALUE,ST_OFFSET>{SECTION_VALUE_CHARS}+ { /* Get rest as section/offset value */
RETURN_TOKEN(TC_STRING, yytext, yyleng);
}
<ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>["] { /* Double quoted '"' string start */
yy_push_state(ST_DOUBLE_QUOTES TSRMLS_CC);
return '"';
}
<ST_DOUBLE_QUOTES>{DOUBLE_QUOTES_CHARS}+ { /* Escape double quoted string contents */
zend_ini_escape_string(ini_lval, yytext, yyleng, '"' TSRMLS_CC);
return TC_QUOTED_STRING;
}
<ST_DOUBLE_QUOTES>["] { /* Double quoted '"' string ends */
yy_pop_state(TSRMLS_C);
return '"';
}
<INITIAL,ST_VALUE,ST_RAW,ST_OFFSET>{TABS_AND_SPACES} {
/* eat whitespace */
}
<INITIAL>{NEWLINE} {
SCNG(lineno)++;
return '\n';
return END_OF_LINE;
}
<INITIAL>[;][^\r\n]*{NEWLINE}? {
/* comment */
<INITIAL,ST_VALUE,ST_RAW>[;][^\r\n]*{NEWLINE} { /* Comment */
BEGIN(INITIAL);
SCNG(lineno)++;
return '\n';
return END_OF_LINE;
}
<INITIAL>[ \t] {
/* eat whitespace */
}
<INITIAL>. {
#if DEBUG
php_error(E_NOTICE,"Unexpected character on line %d: '%s' (ASCII %d)\n", yylineno, yytext, yytext[0]);
#endif
<ST_VALUE,ST_RAW><<EOF>> { /* End of option value (if EOF is reached before EOL */
BEGIN(INITIAL);
return END_OF_LINE;
}
<<EOF>> {
yy_delete_buffer(YY_CURRENT_BUFFER TSRMLS_CC);
#if DEBUG_CFG_SCANNER
while (YYSTATE != INITIAL) {
switch (YYSTATE) {
case INITIAL:
break;
case ST_DOUBLE_QUOTES:
fprintf(stderr, "ERROR: Unterminated ini option value double quotes\n");
break;
case ST_OFFSET:
fprintf(stderr, "ERROR: Unterminated ini option offset\n");
break;
case ST_RAW:
fprintf(stderr, "ERROR: Unterminated raw ini option value\n");
break;
case ST_SECTION_RAW:
fprintf(stderr, "ERROR: Unterminated raw ini section value\n");
break;
case ST_SECTION_VALUE:
fprintf(stderr, "ERROR: Unterminated ini section value\n");
break;
case ST_VALUE:
fprintf(stderr, "ERROR: Unterminated ini option value\n");
break;
case ST_VARNAME:
fprintf(stderr, "ERROR: Unterminated ini variable\n");
break;
default:
fprintf(stderr, "BUG: Unknown state (%d)\n", YYSTATE);
break;
}
yy_pop_state(TSRMLS_C);
}
#endif
yyterminate();
}

View file

@ -41,6 +41,7 @@
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#include "zend.h"
#include "zend_ini_scanner.h"
#include "zend_language_scanner.h"
#include <zend_language_parser.h>
@ -947,8 +948,15 @@ static
ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_ini_file, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, process_sections)
ZEND_ARG_INFO(0, scanner_mode)
ZEND_END_ARG_INFO()
#if ZEND_DEBUG
static
ZEND_BEGIN_ARG_INFO(arginfo_dump_config_hash, 0)
ZEND_END_ARG_INFO()
#endif
static
ZEND_BEGIN_ARG_INFO_EX(arginfo_import_request_variables, 0, 0, 1)
ZEND_ARG_INFO(0, types)
@ -1405,6 +1413,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_fnmatch, 0, 0, 2)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
#endif
static
ZEND_BEGIN_ARG_INFO(arginfo_sys_get_temp_dir, 0)
ZEND_END_ARG_INFO()
@ -3384,7 +3393,7 @@ const zend_function_entry basic_functions[] = {
PHP_FE(set_magic_quotes_runtime, NULL)
PHP_FE(get_magic_quotes_gpc, NULL)
PHP_FE(get_magic_quotes_runtime, NULL)
PHP_FE(import_request_variables, arginfo_import_request_variables)
PHP_FE(error_log, arginfo_error_log)
PHP_FE(error_get_last, arginfo_error_get_last)
@ -3430,6 +3439,9 @@ const zend_function_entry basic_functions[] = {
PHP_FE(connection_status, arginfo_connection_status)
PHP_FE(ignore_user_abort, arginfo_ignore_user_abort)
PHP_FE(parse_ini_file, arginfo_parse_ini_file)
#if ZEND_DEBUG
PHP_FE(dump_config_hash, arginfo_dump_config_hash)
#endif
PHP_FE(is_uploaded_file, arginfo_is_uploaded_file)
PHP_FE(move_uploaded_file, arginfo_move_uploaded_file)
@ -3988,6 +4000,9 @@ PHP_MINIT_FUNCTION(basic)
REGISTER_LONG_CONSTANT("INI_SYSTEM", ZEND_INI_SYSTEM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("INI_ALL", ZEND_INI_ALL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("INI_SCANNER_NORMAL", ZEND_INI_SCANNER_NORMAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("INI_SCANNER_RAW", ZEND_INI_SCANNER_RAW, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHP_URL_SCHEME", PHP_URL_SCHEME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHP_URL_HOST", PHP_URL_HOST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHP_URL_PORT", PHP_URL_PORT, CONST_CS | CONST_PERSISTENT);
@ -4847,12 +4862,34 @@ PHP_FUNCTION(get_current_user)
}
/* }}} */
/* {{{ proto string get_cfg_var(string option_name)
/* {{{ add_config_entry_cb
*/
static int add_config_entry_cb(zval *entry, int num_args, va_list args, zend_hash_key *hash_key TSRMLS_DC)
{
zval *retval = (zval *) va_arg(args, int);
zval *tmp;
if (Z_TYPE_P(entry) == IS_STRING) {
if (hash_key->nKeyLength > 0) {
add_assoc_stringl_ex(retval, hash_key->arKey, hash_key->nKeyLength, Z_STRVAL_P(entry), Z_STRLEN_P(entry), 1);
} else {
add_index_stringl(retval, hash_key->h, Z_STRVAL_P(entry), Z_STRLEN_P(entry), 1);
}
} else if (Z_TYPE_P(entry) == IS_ARRAY) {
MAKE_STD_ZVAL(tmp);
array_init(tmp);
zend_hash_apply_with_arguments(Z_ARRVAL_P(entry), (apply_func_args_t) add_config_entry_cb, 1, tmp TSRMLS_CC);
add_assoc_zval_ex(retval, hash_key->arKey, hash_key->nKeyLength, tmp);
}
return 0;
}
/* }}} */
/* {{{ proto mixed get_cfg_var(string option_name)
Get the value of a PHP configuration option */
PHP_FUNCTION(get_cfg_var)
{
zval **varname;
char *value;
zval **varname, *retval;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &varname) == FAILURE) {
WRONG_PARAM_COUNT;
@ -4860,10 +4897,19 @@ PHP_FUNCTION(get_cfg_var)
convert_to_string_ex(varname);
if (cfg_get_string(Z_STRVAL_PP(varname), &value) == FAILURE) {
retval = cfg_get_entry(Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) + 1);
if (retval) {
if (Z_TYPE_P(retval) == IS_ARRAY) {
array_init(return_value);
zend_hash_apply_with_arguments(Z_ARRVAL_P(retval), (apply_func_args_t) add_config_entry_cb, 1, return_value TSRMLS_CC);
return;
} else {
RETURN_STRING(Z_STRVAL_P(retval), 1);
}
} else {
RETURN_FALSE;
}
RETURN_STRING(value, 1);
}
/* }}} */
@ -5576,7 +5622,7 @@ PHP_FUNCTION(ini_get)
convert_to_string_ex(varname);
str = zend_ini_string(Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, 0);
str = zend_ini_string(Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) + 1, 0);
if (!str) {
RETURN_FALSE;
@ -5713,8 +5759,7 @@ PHP_FUNCTION(ini_set)
}
}
if (zend_alter_ini_entry(Z_STRVAL_PP(varname), Z_STRLEN_PP(varname)+1, Z_STRVAL_PP(new_value), Z_STRLEN_PP(new_value),
PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
if (zend_alter_ini_entry_ex(Z_STRVAL_PP(varname), Z_STRLEN_PP(varname) + 1, Z_STRVAL_PP(new_value), Z_STRLEN_PP(new_value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
@ -5739,7 +5784,6 @@ PHP_FUNCTION(ini_restore)
/* {{{ proto string set_include_path(string new_include_path)
Sets the include_path configuration option */
PHP_FUNCTION(set_include_path)
{
zval **new_value;
@ -5756,19 +5800,15 @@ PHP_FUNCTION(set_include_path)
} else {
RETVAL_FALSE;
}
if (zend_alter_ini_entry("include_path", sizeof("include_path"),
Z_STRVAL_PP(new_value), Z_STRLEN_PP(new_value),
PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
if (zend_alter_ini_entry_ex("include_path", sizeof("include_path"), Z_STRVAL_PP(new_value), Z_STRLEN_PP(new_value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string get_include_path()
Get the current include_path configuration option */
PHP_FUNCTION(get_include_path)
{
char *str;
@ -5781,22 +5821,18 @@ PHP_FUNCTION(get_include_path)
}
RETURN_STRING(str, 1);
}
/* }}} */
/* {{{ proto void restore_include_path()
Restore the value of the include_path configuration option */
PHP_FUNCTION(restore_include_path)
{
if (ZEND_NUM_ARGS() != 0) {
WRONG_PARAM_COUNT;
}
zend_restore_ini_entry("include_path", sizeof("include_path"),
PHP_INI_STAGE_RUNTIME);
zend_restore_ini_entry("include_path", sizeof("include_path"), PHP_INI_STAGE_RUNTIME);
}
/* }}} */
/* {{{ proto mixed print_r(mixed var [, bool return])
@ -5861,7 +5897,7 @@ PHP_FUNCTION(ignore_user_abort)
RETURN_FALSE;
}
convert_to_string_ex(arg);
zend_alter_ini_entry("ignore_user_abort", sizeof("ignore_user_abort"), Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
zend_alter_ini_entry_ex("ignore_user_abort", sizeof("ignore_user_abort"), Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
break;
default:
@ -6116,7 +6152,7 @@ PHP_FUNCTION(move_uploaded_file)
/* {{{ php_simple_ini_parser_cb
*/
static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, int callback_type, zval *arr)
static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr TSRMLS_DC)
{
zval *element;
@ -6146,11 +6182,11 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, int callback_type,
if (!(Z_STRLEN_P(arg1) > 1 && Z_STRVAL_P(arg1)[0] == '0') && is_numeric_string(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), NULL, NULL, 0) == IS_LONG) {
ulong key = (ulong) zend_atoi(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1));
if (zend_hash_index_find(Z_ARRVAL_P(arr), key, (void **) &find_hash) == FAILURE) {
ALLOC_ZVAL(hash);
INIT_PZVAL(hash);
array_init(hash);
ALLOC_ZVAL(hash);
INIT_PZVAL(hash);
array_init(hash);
zend_hash_index_update(Z_ARRVAL_P(arr), key, &hash, sizeof(zval *), NULL);
zend_hash_index_update(Z_ARRVAL_P(arr), key, &hash, sizeof(zval *), NULL);
} else {
hash = *find_hash;
}
@ -6176,7 +6212,12 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, int callback_type,
*element = *arg2;
zval_copy_ctor(element);
INIT_PZVAL(element);
add_next_index_zval(hash, element);
if (arg3 && Z_STRLEN_P(arg3) > 0) {
add_assoc_zval_ex(hash, Z_STRVAL_P(arg3), Z_STRLEN_P(arg3) + 1, element);
} else {
add_next_index_zval(hash, element);
}
}
break;
@ -6188,10 +6229,8 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, int callback_type,
/* {{{ php_ini_parser_cb_with_sections
*/
static void php_ini_parser_cb_with_sections(zval *arg1, zval *arg2, int callback_type, zval *arr)
static void php_ini_parser_cb_with_sections(zval *arg1, zval *arg2, zval *arg3, int callback_type, zval *arr TSRMLS_DC)
{
TSRMLS_FETCH();
if (callback_type == ZEND_INI_PARSER_SECTION) {
MAKE_STD_ZVAL(BG(active_ini_file_section));
array_init(BG(active_ini_file_section));
@ -6205,59 +6244,62 @@ static void php_ini_parser_cb_with_sections(zval *arg1, zval *arg2, int callback
active_arr = arr;
}
php_simple_ini_parser_cb(arg1, arg2, callback_type, active_arr);
php_simple_ini_parser_cb(arg1, arg2, arg3, callback_type, active_arr TSRMLS_CC);
}
}
/* }}} */
/* {{{ proto array parse_ini_file(string filename [, bool process_sections])
/* {{{ proto array parse_ini_file(string filename [, bool process_sections [, int scanner_mode]])
Parse configuration file */
PHP_FUNCTION(parse_ini_file)
{
zval **filename, **process_sections;
char *filename = NULL;
int filename_len = 0;
zend_bool process_sections = 0;
long scanner_mode = ZEND_INI_SCANNER_NORMAL;
zend_file_handle fh;
zend_ini_parser_cb_t ini_parser_cb;
switch (ZEND_NUM_ARGS()) {
case 1:
if (zend_get_parameters_ex(1, &filename) == FAILURE) {
RETURN_FALSE;
}
ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
break;
case 2:
if (zend_get_parameters_ex(2, &filename, &process_sections) == FAILURE) {
RETURN_FALSE;
}
convert_to_boolean_ex(process_sections);
if (Z_BVAL_PP(process_sections)) {
BG(active_ini_file_section) = NULL;
ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
} else {
ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
}
break;
default:
ZEND_WRONG_PARAM_COUNT();
break;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &filename, &filename_len, &process_sections, &scanner_mode) == FAILURE) {
RETURN_FALSE;
}
convert_to_string_ex(filename);
if (filename_len == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filename can not be empty!");
RETURN_FALSE;
}
/* Set callback function */
if (process_sections) {
BG(active_ini_file_section) = NULL;
ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
} else {
ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
}
/* Setup filehandle */
memset(&fh, 0, sizeof(fh));
fh.filename = Z_STRVAL_PP(filename);
Z_TYPE(fh) = ZEND_HANDLE_FILENAME;
fh.filename = filename;
fh.type = ZEND_HANDLE_FILENAME;
array_init(return_value);
zend_parse_ini_file(&fh, 0, ini_parser_cb, return_value);
zend_parse_ini_file(&fh, 0, scanner_mode, ini_parser_cb, return_value TSRMLS_CC);
}
/* }}} */
#if ZEND_DEBUG
/* {{{ proto void dump_config_hash(void)
*/
PHP_FUNCTION(dump_config_hash)
{
HashTable hash = get_configuration_hash();
array_init(return_value);
zend_hash_apply_with_arguments(&hash, (apply_func_args_t) add_config_entry_cb, 1, return_value TSRMLS_CC);
}
/* }}} */
#endif
static int copy_request_variable(void *pDest, int num_args, va_list args, zend_hash_key *hash_key)
{
char *prefix, *new_key;

View file

@ -125,6 +125,9 @@ PHP_FUNCTION(move_uploaded_file);
/* From the INI parser */
PHP_FUNCTION(parse_ini_file);
#if ZEND_DEBUG
PHP_FUNCTION(dump_config_hash);
#endif
PHP_FUNCTION(str_rot13);
PHP_FUNCTION(stream_get_filters);

View file

@ -23,11 +23,12 @@
#include "php_browscap.h"
#include "php_ini.h"
#include "php_string.h"
#include "zend_ini_scanner.h"
#include "zend_globals.h"
static HashTable browser_hash;
static zval *current_section;
static char *current_section_name;
#define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
@ -88,7 +89,7 @@ static void convert_browscap_pattern(zval *pattern)
/* {{{ php_browscap_parser_cb
*/
static void php_browscap_parser_cb(zval *arg1, zval *arg2, int callback_type, void *arg)
static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC)
{
if (!arg1) {
return;
@ -100,12 +101,37 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, int callback_type, vo
zval *new_property;
char *new_key;
/* parent entry can not be same as current section -> causes infinite loop! */
if (!strcasecmp(Z_STRVAL_P(arg1), "parent") &&
!strcasecmp(current_section_name, Z_STRVAL_P(arg2))
) {
zend_error(E_CORE_ERROR, "Invalid browscap ini file: 'Parent' value can not be same as the section name: %s (in file %s)", current_section_name, INI_STR("browscap"));
return;
}
new_property = (zval *) pemalloc(sizeof(zval), 1);
INIT_PZVAL(new_property);
Z_STRVAL_P(new_property) = zend_strndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
Z_STRLEN_P(new_property) = Z_STRLEN_P(arg2);
Z_TYPE_P(new_property) = IS_STRING;
/* Set proper value for true/false settings */
if ((Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "on", sizeof("on") - 1)) ||
(Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "yes", sizeof("yes") - 1)) ||
(Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "true", sizeof("true") - 1))
) {
Z_STRVAL_P(new_property) = zend_strndup("1", 1);
Z_STRLEN_P(new_property) = 1;
} else if (
(Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "no", sizeof("no") - 1)) ||
(Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "off", sizeof("off") - 1)) ||
(Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "none", sizeof("none") - 1)) ||
(Z_STRLEN_P(arg2) == 5 && !strncasecmp(Z_STRVAL_P(arg2), "false", sizeof("false") - 1))
) {
Z_STRVAL_P(new_property) = zend_strndup("", 0);
Z_STRLEN_P(new_property) = 0;
} else { /* Other than true/false setting */
Z_STRVAL_P(new_property) = zend_strndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
Z_STRLEN_P(new_property) = Z_STRLEN_P(arg2);
}
new_key = zend_strndup(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1));
zend_str_tolower(new_key, Z_STRLEN_P(arg1));
zend_hash_update(Z_ARRVAL_P(current_section), new_key, Z_STRLEN_P(arg1)+1, &new_property, sizeof(zval *), NULL);
@ -127,8 +153,10 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, int callback_type, vo
section_properties = (HashTable *) pemalloc(sizeof(HashTable), 1);
zend_hash_init(section_properties, 0, NULL, (dtor_func_t) browscap_entry_dtor, 1);
current_section->value.ht = section_properties;
current_section->type = IS_ARRAY;
Z_ARRVAL_P(current_section) = section_properties;
Z_TYPE_P(current_section) = IS_ARRAY;
current_section_name = zend_strndup(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1));
zend_hash_update(&browser_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)+1, (void *) &current_section, sizeof(zval *), NULL);
Z_STRVAL_P(processed) = Z_STRVAL_P(arg1);
@ -171,7 +199,7 @@ PHP_MINIT_FUNCTION(browscap)
}
fh.filename = browscap;
Z_TYPE(fh) = ZEND_HANDLE_FP;
zend_parse_ini_file(&fh, 1, (zend_ini_parser_cb_t) php_browscap_parser_cb, &browser_hash);
zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_RAW, (zend_ini_parser_cb_t) php_browscap_parser_cb, &browser_hash TSRMLS_CC);
}
return SUCCESS;

View file

@ -50,98 +50,98 @@ Hex_Value2 = 0x103
[Non-alphanumerics_as_values]
;Non-alpha numeric chars without quotes
Non-alpha1 = ;
Non-alpha2 = +
Non-alpha3 = *
Non-alpha4 = %
Non-alpha5 = <>
Non-alpha6 = @
Non-alpha7 = #
Non-alpha8 = ^
non-alpha9 = -
Non-alpha10 = :
Non-alpha11 = ?
Non-alpha12 = /
Non-alpha13 = \
Non_alpha1 = ;
Non_alpha2 = +
Non_alpha3 = *
Non_alpha4 = %
Non_alpha5 = <>
Non_alpha6 = @
Non_alpha7 = #
Non_alpha8 = ^
Non_alpha9 = -
Non_alpha10 = :
Non_alpha11 = ?
Non_alpha12 = /
Non_alpha13 = \
;These chars have a special meaning when used in the value,
; hence parser throws an error
;Non-alpha14 = &
;Non-alpha15 = {}
;Non-alpha16 = |
;Non-alpha17 = ~
;Non-alpha18 = !
;Non-alpha19 = $
;Non-alpha20 = ()
;Non_alpha14 = &
;Non_alpha15 = {}
;Non_alpha16 = |
;Non_alpha17 = ~
;Non_alpha18 = !
;Non_alpha19 = $
;Non_alpha20 = ()
Non-alpha1_quotes = ";"
Non-alpha2_quotes = "+"
Non-alpha3_quotes = "*"
Non-alpha4_quotes = "%"
Non-alpha5_quotes = "<>"
Non-alpha6_quotes = "@"
Non-alpha7_quotes = "#"
Non-alpha8_quotes = "^"
Non-alpha9_quotes = "-"
Non-alpha10_quotes = "="
Non-alpha11_quotes = ":"
Non-alpha12_quotes = "?"
Non-alpha13_quotes = "/"
Non-alpha14_quotes = "\"
Non-alpha15_quotes = "&"
Non-alpha16_quotes = "{}"
Non-alpha17_quotes = "|"
Non-alpha18_quotes = "~"
Non-alpha19_quotes = "!"
non-alpha20_quotes = "$"
non-alpha21_quotes = "()"
Non_alpha1_quotes = ";"
Non_alpha2_quotes = "+"
Non_alpha3_quotes = "*"
Non_alpha4_quotes = "%"
Non_alpha5_quotes = "<>"
Non_alpha6_quotes = "@"
Non_alpha7_quotes = "#"
Non_alpha8_quotes = "^"
Non_alpha9_quotes = "-"
Non_alpha10_quotes = "="
Non_alpha11_quotes = ":"
Non_alpha12_quotes = "?"
Non_alpha13_quotes = "/"
;Non_alpha14_quotes = "\"
Non_alpha15_quotes = "&"
Non_alpha16_quotes = "{}"
Non_alpha17_quotes = "|"
Non_alpha18_quotes = "~"
Non_alpha19_quotes = "!"
;Non_alpha20_quotes = "$"
Non_alpha21_quotes = "()"
[Non-alpha numerics in strings]
;expected error, as the non-alphanumeric chars not enclosed in double quotes("")
Non-alpha_string1 = Hello@world
;Non-alpha_string2 = Hello!world
;Non-alpha_string3 = Hello#world
;Non-alpha_string4 = Hello%world
;Non-alpha_string5 = Hello&world
;Non-alpha_string6 = Hello*world
;Non-alpha_string7 = Hello+world
;Non-alpha_string8 = Hello-world
;Non-alpha_string9 = Hello'world
;Non-alpha_string10 = Hello:world
;Non-alpha_string11 = Hello;world
;Non-alpha_string12 = Hello<world
;Non-alpha_string13 = Hello>world
;Non-alpha_string14 = Hello>world
;Non-alpha_string15 = Hello?world
;Non-alpha_string16 = Hello\world
;Non-alpha_string17 = Hello^world
;Non-alpha_string18 = Hello_world
;Non-alpha_string19 = Hello|world
;Non-alpha_string20 = Hello~world
;Non-alpha_string21 = Hello`world
;Non-alpha_string22 = Hello(world)
Non_alpha_string1 = Hello@world
;Non_alpha_string2 = Hello!world
;Non_alpha_string3 = Hello#world
;Non_alpha_string4 = Hello%world
;Non_alpha_string5 = Hello&world
;Non_alpha_string6 = Hello*world
;Non_alpha_string7 = Hello+world
;Non_alpha_string8 = Hello-world
;Non_alpha_string9 = Hello'world
;Non_alpha_string10 = Hello:world
;Non_alpha_string11 = Hello;world
;Non_alpha_string12 = Hello<world
;Non_alpha_string13 = Hello>world
;Non_alpha_string14 = Hello>world
;Non_alpha_string15 = Hello?world
;Non_alpha_string16 = Hello\world
;Non_alpha_string17 = Hello^world
;Non_alpha_string18 = Hello_world
;Non_alpha_string19 = Hello|world
;Non_alpha_string20 = Hello~world
;Non_alpha_string21 = Hello`world
;Non_alpha_string22 = Hello(world)
[Non-alpha numerics in strings -with quotes]
Non-alpha_string1_quotes = "Hello@world"
Non-alpha_string2_quotes = "Hello!world"
Non-alpha_string3_quotes = "Hello#world"
Non-alpha_string4_quotes = "Hello&world"
Non-alpha_string5_quotes = "Hello*world"
Non-alpha_string6_quotes = "Hello+world"
Non-alpha_string7_quotes = "Hello-world"
Non-alpha_string8_quotes = "Hello'world"
Non-alpha_string9_quotes = "Hello:world"
Non-alpha_string10_quotes = "Hello;world"
Non-alpha_string11_quotes = "Hello<world"
Non-alpha_string12_quotes = "Hello>world"
Non-alpha_string13_quotes = "Hello>world"
Non-alpha_string14_quotes = "Hello?world"
Non-alpha_string15_quotes = "Hello\world"
Non-alpha_string16_quotes = "Hello^world"
Non-alpha_string17_quotes = "Hello_world"
Non-alpha_string18_quotes = "Hello|world"
Non-alpha_string19_quotes = "Hello~world"
Non-alpha_string20_quotes = "Hello`world"
Non-alpha_string21_quotes = "Hello(world)"
Non_alpha_string1_quotes = "Hello@world"
Non_alpha_string2_quotes = "Hello!world"
Non_alpha_string3_quotes = "Hello#world"
Non_alpha_string4_quotes = "Hello&world"
Non_alpha_string5_quotes = "Hello*world"
Non_alpha_string6_quotes = "Hello+world"
Non_alpha_string7_quotes = "Hello-world"
Non_alpha_string8_quotes = "Hello'world"
Non_alpha_string9_quotes = "Hello:world"
Non_alpha_string10_quotes = "Hello;world"
Non_alpha_string11_quotes = "Hello<world"
Non_alpha_string12_quotes = "Hello>world"
Non_alpha_string13_quotes = "Hello>world"
Non_alpha_string14_quotes = "Hello?world"
Non_alpha_string15_quotes = "Hello\world"
Non_alpha_string16_quotes = "Hello^world"
Non_alpha_string17_quotes = "Hello_world"
Non_alpha_string18_quotes = "Hello|world"
Non_alpha_string19_quotes = "Hello~world"
Non_alpha_string20_quotes = "Hello`world"
Non_alpha_string21_quotes = "Hello(world)"
[Newlines_in_Values]
String1 = "Hello, world\nGood Morning"
@ -150,7 +150,7 @@ String2 = "\nHello, world
String3 = 'Hello, world\tGood Morning'
String4 = "\n"
String5 = "\n\n"
String3 = Hello, world\tGood Morning
String6 = Hello, world\tGood Morning
[ReservedKeys_as_Values]
Key1 = YES
@ -242,74 +242,73 @@ Array
[Octal_value] => 0100
[Hex_value1] => 0x101
[Hex_Value2] => 0x103
[Non-alpha1] =>
[Non-alpha2] => +
[Non-alpha3] => *
[Non-alpha4] => %
[Non-alpha5] => <>
[Non-alpha6] => @
[Non-alpha7] => #
[Non-alpha8] => ^
[non-alpha9] => -
[Non-alpha10] => :
[Non-alpha11] => ?
[Non-alpha12] => /
[Non-alpha13] => \
[Non-alpha1_quotes] => ;
[Non-alpha2_quotes] => +
[Non-alpha3_quotes] => *
[Non-alpha4_quotes] => %
[Non-alpha5_quotes] => <>
[Non-alpha6_quotes] => @
[Non-alpha7_quotes] => #
[Non-alpha8_quotes] => ^
[Non-alpha9_quotes] => -
[Non-alpha10_quotes] => =
[Non-alpha11_quotes] => :
[Non-alpha12_quotes] => ?
[Non-alpha13_quotes] => /
[Non-alpha14_quotes] => \
[Non-alpha15_quotes] => &
[Non-alpha16_quotes] => {}
[Non-alpha17_quotes] => |
[Non-alpha18_quotes] => ~
[Non-alpha19_quotes] => !
[non-alpha20_quotes] => $
[non-alpha21_quotes] => ()
[Non-alpha_string1] => Hello@world
[Non-alpha_string1_quotes] => Hello@world
[Non-alpha_string2_quotes] => Hello!world
[Non-alpha_string3_quotes] => Hello#world
[Non-alpha_string4_quotes] => Hello&world
[Non-alpha_string5_quotes] => Hello*world
[Non-alpha_string6_quotes] => Hello+world
[Non-alpha_string7_quotes] => Hello-world
[Non-alpha_string8_quotes] => Hello'world
[Non-alpha_string9_quotes] => Hello:world
[Non-alpha_string10_quotes] => Hello;world
[Non-alpha_string11_quotes] => Hello<world
[Non-alpha_string12_quotes] => Hello>world
[Non-alpha_string13_quotes] => Hello>world
[Non-alpha_string14_quotes] => Hello?world
[Non-alpha_string15_quotes] => Hello\world
[Non-alpha_string16_quotes] => Hello^world
[Non-alpha_string17_quotes] => Hello_world
[Non-alpha_string18_quotes] => Hello|world
[Non-alpha_string19_quotes] => Hello~world
[Non-alpha_string20_quotes] => Hello`world
[Non-alpha_string21_quotes] => Hello(world)
[Non_alpha1] =>
[Non_alpha2] => +
[Non_alpha3] => *
[Non_alpha4] => %
[Non_alpha5] => <>
[Non_alpha6] => @
[Non_alpha7] => #
[Non_alpha8] => ^
[Non_alpha9] => -
[Non_alpha10] => :
[Non_alpha11] => ?
[Non_alpha12] => /
[Non_alpha13] => \
[Non_alpha1_quotes] => ;
[Non_alpha2_quotes] => +
[Non_alpha3_quotes] => *
[Non_alpha4_quotes] => %
[Non_alpha5_quotes] => <>
[Non_alpha6_quotes] => @
[Non_alpha7_quotes] => #
[Non_alpha8_quotes] => ^
[Non_alpha9_quotes] => -
[Non_alpha10_quotes] => =
[Non_alpha11_quotes] => :
[Non_alpha12_quotes] => ?
[Non_alpha13_quotes] => /
[Non_alpha15_quotes] => &
[Non_alpha16_quotes] => {}
[Non_alpha17_quotes] => |
[Non_alpha18_quotes] => ~
[Non_alpha19_quotes] => !
[Non_alpha21_quotes] => ()
[Non_alpha_string1] => Hello@world
[Non_alpha_string1_quotes] => Hello@world
[Non_alpha_string2_quotes] => Hello!world
[Non_alpha_string3_quotes] => Hello#world
[Non_alpha_string4_quotes] => Hello&world
[Non_alpha_string5_quotes] => Hello*world
[Non_alpha_string6_quotes] => Hello+world
[Non_alpha_string7_quotes] => Hello-world
[Non_alpha_string8_quotes] => Hello'world
[Non_alpha_string9_quotes] => Hello:world
[Non_alpha_string10_quotes] => Hello;world
[Non_alpha_string11_quotes] => Hello<world
[Non_alpha_string12_quotes] => Hello>world
[Non_alpha_string13_quotes] => Hello>world
[Non_alpha_string14_quotes] => Hello?world
[Non_alpha_string15_quotes] => Hello\world
[Non_alpha_string16_quotes] => Hello^world
[Non_alpha_string17_quotes] => Hello_world
[Non_alpha_string18_quotes] => Hello|world
[Non_alpha_string19_quotes] => Hello~world
[Non_alpha_string20_quotes] => Hello`world
[Non_alpha_string21_quotes] => Hello(world)
[String1] => Hello, world
Good Morning
[String2] =>
Hello, world
Good Morning
[String3] => Hello, worldGood Morning
[String3] => Hello, world Good Morning
[String4] =>
[String5] =>
[String6] => Hello, world Good Morning
[Key1] => 1
[Key2] => 1
[Key3] => 1
@ -379,70 +378,68 @@ Array
[Non-alphanumerics_as_values] => Array
(
[Non-alpha1] =>
[Non-alpha2] => +
[Non-alpha3] => *
[Non-alpha4] => %
[Non-alpha5] => <>
[Non-alpha6] => @
[Non-alpha7] => #
[Non-alpha8] => ^
[non-alpha9] => -
[Non-alpha10] => :
[Non-alpha11] => ?
[Non-alpha12] => /
[Non-alpha13] => \
[Non-alpha1_quotes] => ;
[Non-alpha2_quotes] => +
[Non-alpha3_quotes] => *
[Non-alpha4_quotes] => %
[Non-alpha5_quotes] => <>
[Non-alpha6_quotes] => @
[Non-alpha7_quotes] => #
[Non-alpha8_quotes] => ^
[Non-alpha9_quotes] => -
[Non-alpha10_quotes] => =
[Non-alpha11_quotes] => :
[Non-alpha12_quotes] => ?
[Non-alpha13_quotes] => /
[Non-alpha14_quotes] => \
[Non-alpha15_quotes] => &
[Non-alpha16_quotes] => {}
[Non-alpha17_quotes] => |
[Non-alpha18_quotes] => ~
[Non-alpha19_quotes] => !
[non-alpha20_quotes] => $
[non-alpha21_quotes] => ()
[Non_alpha1] =>
[Non_alpha2] => +
[Non_alpha3] => *
[Non_alpha4] => %
[Non_alpha5] => <>
[Non_alpha6] => @
[Non_alpha7] => #
[Non_alpha8] => ^
[Non_alpha9] => -
[Non_alpha10] => :
[Non_alpha11] => ?
[Non_alpha12] => /
[Non_alpha13] => \
[Non_alpha1_quotes] => ;
[Non_alpha2_quotes] => +
[Non_alpha3_quotes] => *
[Non_alpha4_quotes] => %
[Non_alpha5_quotes] => <>
[Non_alpha6_quotes] => @
[Non_alpha7_quotes] => #
[Non_alpha8_quotes] => ^
[Non_alpha9_quotes] => -
[Non_alpha10_quotes] => =
[Non_alpha11_quotes] => :
[Non_alpha12_quotes] => ?
[Non_alpha13_quotes] => /
[Non_alpha15_quotes] => &
[Non_alpha16_quotes] => {}
[Non_alpha17_quotes] => |
[Non_alpha18_quotes] => ~
[Non_alpha19_quotes] => !
[Non_alpha21_quotes] => ()
)
[Non-alpha numerics in strings] => Array
(
[Non-alpha_string1] => Hello@world
[Non_alpha_string1] => Hello@world
)
[Non-alpha numerics in strings -with quotes] => Array
(
[Non-alpha_string1_quotes] => Hello@world
[Non-alpha_string2_quotes] => Hello!world
[Non-alpha_string3_quotes] => Hello#world
[Non-alpha_string4_quotes] => Hello&world
[Non-alpha_string5_quotes] => Hello*world
[Non-alpha_string6_quotes] => Hello+world
[Non-alpha_string7_quotes] => Hello-world
[Non-alpha_string8_quotes] => Hello'world
[Non-alpha_string9_quotes] => Hello:world
[Non-alpha_string10_quotes] => Hello;world
[Non-alpha_string11_quotes] => Hello<world
[Non-alpha_string12_quotes] => Hello>world
[Non-alpha_string13_quotes] => Hello>world
[Non-alpha_string14_quotes] => Hello?world
[Non-alpha_string15_quotes] => Hello\world
[Non-alpha_string16_quotes] => Hello^world
[Non-alpha_string17_quotes] => Hello_world
[Non-alpha_string18_quotes] => Hello|world
[Non-alpha_string19_quotes] => Hello~world
[Non-alpha_string20_quotes] => Hello`world
[Non-alpha_string21_quotes] => Hello(world)
[Non_alpha_string1_quotes] => Hello@world
[Non_alpha_string2_quotes] => Hello!world
[Non_alpha_string3_quotes] => Hello#world
[Non_alpha_string4_quotes] => Hello&world
[Non_alpha_string5_quotes] => Hello*world
[Non_alpha_string6_quotes] => Hello+world
[Non_alpha_string7_quotes] => Hello-world
[Non_alpha_string8_quotes] => Hello'world
[Non_alpha_string9_quotes] => Hello:world
[Non_alpha_string10_quotes] => Hello;world
[Non_alpha_string11_quotes] => Hello<world
[Non_alpha_string12_quotes] => Hello>world
[Non_alpha_string13_quotes] => Hello>world
[Non_alpha_string14_quotes] => Hello?world
[Non_alpha_string15_quotes] => Hello\world
[Non_alpha_string16_quotes] => Hello^world
[Non_alpha_string17_quotes] => Hello_world
[Non_alpha_string18_quotes] => Hello|world
[Non_alpha_string19_quotes] => Hello~world
[Non_alpha_string20_quotes] => Hello`world
[Non_alpha_string21_quotes] => Hello(world)
)
[Newlines_in_Values] => Array
@ -453,12 +450,13 @@ Good Morning
Hello, world
Good Morning
[String3] => Hello, worldGood Morning
[String3] => Hello, world Good Morning
[String4] =>
[String5] =>
[String6] => Hello, world Good Morning
)
[ReservedKeys_as_Values] => Array
@ -488,4 +486,4 @@ Hello, world
)
)
*** Done **
*** Done **

View file

@ -0,0 +1,106 @@
[basic]
basicval = bar
longval = 12345
with.dot = fooobar
boolon = on
booltrue = true
boolyes = yes
booloff = off
boolfalse = false
boolnone = none
boolno = no
string = asdadfsdjkslkj ¡@£$$ { }[ ]/%#¤
sqstring = 'adsasdadasdasd'
dqstring = "asdadfsdjkslkj ¡@£$$ { } !^~|¥¥{[()/)&/% ¤ # #"
php_constant = E_ALL
[basic with whitespace]
basicval = bar
longval = 12345
with.dot = fooobar
boolon = on
booltrue = true
boolyes = yes
booloff = off
boolfalse = false
boolnone = none
boolno = no
sqstring = 'adsasdadasdasd'
dqstring = "asdadfsdjkslkj ¡@£$$€¥¥{[()/)&/%#¤"
php_constant = E_ALL
[comments]
; some comment
; some comment with whitespace
somecomment = comment follows;aaa@bbb ; comment here
;
[variables]
var1 = ${basicval}
var2 = ${basicval}/foo
var3 = foo/${basicval}
var4 = foo/${basicval}/foo
quoted_var1 = "${basicqval}"
quoted_var2 = "${basicqval}/foo"
quoted_var3 = "foo/${basicqval}"
quoted_var4 = "foo/${basicqval}/foo"
[offset values]
foo1[] = "basic offset 1"
foo1[ ] = "basic offset 2"
foo2[123] = "long offset"
foo3[abc] = "string offset"
foo4[""] = "quoted offset 1"
foo4[" "] = "quoted offset 2"
foo4["sqfoobar"] = "quoted string offset"
foo4['dqfoobar'] = "single quoted offset"
foo6[${basicval}] = "variable"
foo6[${basicval}/foo] = "variable with string 1"
foo6[foo/${basicval}] = "variable with string 2"
foo6[foo/${basicval}/foo] = "variable with string 3"
foo7["${basicqval}"] = "quoted variable 1"
foo7["${basicqval}/foo"] = "quoted variable 2"
foo7["foo/${basicqval}"] = "quoted variable 3"
foo7[ "foo/${basicqval}/foo" ] = "quoted variable 4"
[non value]
novalue_option1 =
novalue_option2=
novalue_option3 =
novalue_option4=
novalue_option4[] =
novalue_option4[]=
novalue_option4[]=
["Quoted strings and variables in sections"]
[${basicval}]
[${basicval}/foo]
[foo/${basicval}]
[foo/${basicval}/foo]
["${basicqval}"]
["${basicqval}/foo"]
["foo/${basicqval}"]
["foo/${basicqval}/foo"]
[PATH=${basicval}/no/quotes]
; Invalid!
;[PATH="${basicval}/path/quoted"]
["PATH=${basicval}/all/quoted"]
; The rest is from bug #29306
[01]
e=e
f=f
[02]
g=g
h=h
[1]
a=a
b=b
[2]
c=c
d=d
[0815]
bla=bla

View file

@ -0,0 +1,239 @@
--TEST--
parse_ini_file() tests
--ENV--
basicval=FUBAR_VARIABLE
basicqval=FUBAR_QUOTES_VARIABLE
--FILE--
<?php
$ini_file = dirname(__FILE__)."/parse_ini_basic.data";
var_dump(parse_ini_file($ini_file, 1));
echo "Done.\n";
?>
--EXPECTF--
array(22) {
["basic"]=>
array(14) {
["basicval"]=>
string(3) "bar"
["longval"]=>
string(5) "12345"
["with.dot"]=>
string(7) "fooobar"
["boolon"]=>
string(1) "1"
["booltrue"]=>
string(1) "1"
["boolyes"]=>
string(1) "1"
["booloff"]=>
string(0) ""
["boolfalse"]=>
string(0) ""
["boolnone"]=>
string(0) ""
["boolno"]=>
string(0) ""
["string"]=>
string(34) "asdadfsdjkslkj ¡@£$$ { }[ ]/%#¤"
["sqstring"]=>
string(14) "adsasdadasdasd"
["dqstring"]=>
string(51) "asdadfsdjkslkj ¡@£$$ { } !^~|¥¥{[()/)&/% ¤ # #"
["php_constant"]=>
string(4) "6143"
}
["basic with whitespace"]=>
array(13) {
["basicval"]=>
string(3) "bar"
["longval"]=>
string(5) "12345"
["with.dot"]=>
string(7) "fooobar"
["boolon"]=>
string(1) "1"
["booltrue"]=>
string(1) "1"
["boolyes"]=>
string(1) "1"
["booloff"]=>
string(0) ""
["boolfalse"]=>
string(0) ""
["boolnone"]=>
string(0) ""
["boolno"]=>
string(0) ""
["sqstring"]=>
string(14) "adsasdadasdasd"
["dqstring"]=>
string(41) "asdadfsdjkslkj ¡@£$$€¥¥{[()/)&/%#¤"
["php_constant"]=>
string(4) "6143"
}
["comments"]=>
array(1) {
["somecomment"]=>
string(15) "comment follows"
}
["variables"]=>
array(8) {
["var1"]=>
string(14) "FUBAR_VARIABLE"
["var2"]=>
string(18) "FUBAR_VARIABLE/foo"
["var3"]=>
string(18) "foo/FUBAR_VARIABLE"
["var4"]=>
string(22) "foo/FUBAR_VARIABLE/foo"
["quoted_var1"]=>
string(21) "FUBAR_QUOTES_VARIABLE"
["quoted_var2"]=>
string(25) "FUBAR_QUOTES_VARIABLE/foo"
["quoted_var3"]=>
string(25) "foo/FUBAR_QUOTES_VARIABLE"
["quoted_var4"]=>
string(29) "foo/FUBAR_QUOTES_VARIABLE/foo"
}
["offset values"]=>
array(6) {
["foo1"]=>
array(2) {
[0]=>
string(14) "basic offset 1"
[1]=>
string(14) "basic offset 2"
}
["foo2"]=>
array(1) {
[123]=>
string(11) "long offset"
}
["foo3"]=>
array(1) {
["abc"]=>
string(13) "string offset"
}
["foo4"]=>
array(4) {
[0]=>
string(15) "quoted offset 1"
[" "]=>
string(15) "quoted offset 2"
["sqfoobar"]=>
string(20) "quoted string offset"
["dqfoobar"]=>
string(20) "single quoted offset"
}
["foo6"]=>
array(4) {
["FUBAR_VARIABLE"]=>
string(8) "variable"
["FUBAR_VARIABLE/foo"]=>
string(22) "variable with string 1"
["foo/FUBAR_VARIABLE"]=>
string(22) "variable with string 2"
["foo/FUBAR_VARIABLE/foo"]=>
string(22) "variable with string 3"
}
["foo7"]=>
array(4) {
["FUBAR_QUOTES_VARIABLE"]=>
string(17) "quoted variable 1"
["FUBAR_QUOTES_VARIABLE/foo"]=>
string(17) "quoted variable 2"
["foo/FUBAR_QUOTES_VARIABLE"]=>
string(17) "quoted variable 3"
["foo/FUBAR_QUOTES_VARIABLE/foo"]=>
string(17) "quoted variable 4"
}
}
["non value"]=>
array(4) {
["novalue_option1"]=>
string(0) ""
["novalue_option2"]=>
string(0) ""
["novalue_option3"]=>
string(0) ""
["novalue_option4"]=>
array(3) {
[0]=>
string(0) ""
[1]=>
string(0) ""
[2]=>
string(0) ""
}
}
["Quoted strings and variables in sections"]=>
array(0) {
}
["FUBAR_VARIABLE"]=>
array(0) {
}
["FUBAR_VARIABLE/foo"]=>
array(0) {
}
["foo/FUBAR_VARIABLE"]=>
array(0) {
}
["foo/FUBAR_VARIABLE/foo"]=>
array(0) {
}
["FUBAR_QUOTES_VARIABLE"]=>
array(0) {
}
["FUBAR_QUOTES_VARIABLE/foo"]=>
array(0) {
}
["foo/FUBAR_QUOTES_VARIABLE"]=>
array(0) {
}
["foo/FUBAR_QUOTES_VARIABLE/foo"]=>
array(0) {
}
["PATH=FUBAR_VARIABLE/no/quotes"]=>
array(0) {
}
["PATH=FUBAR_VARIABLE/all/quoted"]=>
array(0) {
}
["01"]=>
array(2) {
["e"]=>
string(1) "e"
["f"]=>
string(1) "f"
}
["02"]=>
array(2) {
["g"]=>
string(1) "g"
["h"]=>
string(1) "h"
}
[1]=>
array(2) {
["a"]=>
string(1) "a"
["b"]=>
string(1) "b"
}
[2]=>
array(2) {
["c"]=>
string(1) "c"
["d"]=>
string(1) "d"
}
["0815"]=>
array(1) {
["bla"]=>
string(3) "bla"
}
}
Done.

View file

@ -0,0 +1,27 @@
[error_reporting values]
foo = E_ALL E_NOTICE
error_reporting = E_ALL
error_reporting1 = E_COMPILE_ERROR|E_RECOVERABLE_ERROR |E_ERROR|E_CORE_ERROR
error_reporting2 = E_ALL&~E_NOTICE
error_reporting3 = E_ALL & ~E_NOTICE
error_reporting4 = E_ALL & ~E_NOTICE | E_STRICT
[true or false]
bool_true = true
bool_yes = yes
bool_on = on
bool_false=false
bool_off =Off
bool_no=No
bool_none= NoNe
bool_null = NULl
[strings]
string_true = "true"
string_yes = " yes"
string_on = " on "
string_false="false"
string_off ="Off "
string_no="No "
string_none=" NoNe"
string_null = "NULl"

View file

@ -0,0 +1,69 @@
--TEST--
parse_ini_file() boolean operators
--FILE--
<?php
$ini_file = dirname(__FILE__)."/parse_ini_booleans.data";
var_dump(parse_ini_file($ini_file, 1));
echo "Done.\n";
?>
--EXPECTF--
array(3) {
["error_reporting values"]=>
array(6) {
["foo"]=>
string(14) "E_ALL E_NOTICE"
["error_reporting"]=>
string(4) "6143"
["error_reporting1"]=>
string(4) "4177"
["error_reporting2"]=>
string(4) "6135"
["error_reporting3"]=>
string(4) "6135"
["error_reporting4"]=>
string(4) "8183"
}
["true or false"]=>
array(8) {
["bool_true"]=>
string(1) "1"
["bool_yes"]=>
string(1) "1"
["bool_on"]=>
string(1) "1"
["bool_false"]=>
string(0) ""
["bool_off"]=>
string(0) ""
["bool_no"]=>
string(0) ""
["bool_none"]=>
string(0) ""
["bool_null"]=>
string(0) ""
}
["strings"]=>
array(8) {
["string_true"]=>
string(4) "true"
["string_yes"]=>
string(4) " yes"
["string_on"]=>
string(5) " on "
["string_false"]=>
string(5) "false"
["string_off"]=>
string(4) "Off "
["string_no"]=>
string(4) "No "
["string_none"]=>
string(5) " NoNe"
["string_null"]=>
string(4) "NULl"
}
}
Done.

View file

@ -1,12 +1,13 @@
--TEST--
parse_ini_file() tests
parse_ini_file() multiple calls
--FILE--
<?php
$filename = dirname(__FILE__)."/parse_ini_file.dat";
@unlink($filename); /* Make sure the file really does not exist! */
var_dump(parse_ini_file());
var_dump(parse_ini_file(1,1,1));
var_dump(parse_ini_file(1,1,1,1));
var_dump(parse_ini_file($filename));
var_dump(parse_ini_file($filename, true));
@ -15,7 +16,6 @@ test =
";
file_put_contents($filename, $ini);
var_dump(parse_ini_file($filename));
$ini = "
test==
";
@ -81,7 +81,6 @@ $ini = "
";
file_put_contents($filename, $ini);
var_dump(parse_ini_file($filename, true));
$ini = "
test=test2
test=test3
@ -90,22 +89,21 @@ test=test4
file_put_contents($filename, $ini);
var_dump(parse_ini_file($filename, true));
@unlink($filename);
echo "Done\n";
?>
--EXPECTF--
Warning: Wrong parameter count for parse_ini_file() in %s on line %d
NULL
Warning: parse_ini_file() expects at least 1 parameter, 0 given in %sparse_ini_file.php on line 6
bool(false)
Warning: Wrong parameter count for parse_ini_file() in %s on line %d
NULL
Warning: parse_ini_file() expects at most 3 parameters, 4 given in %sparse_ini_file.php on line 7
bool(false)
Warning: parse_ini_file(%sparse_ini_file.dat): failed to open stream: No such file or directory in %s on line %d
Warning: parse_ini_file(%sparse_ini_file.dat): failed to open stream: No such file or directory in %sparse_ini_file.php on line 8
array(0) {
}
Warning: parse_ini_file(%sparse_ini_file.dat): failed to open stream: No such file or directory in %s on line %d
Warning: parse_ini_file(%sparse_ini_file.dat): failed to open stream: No such file or directory in %sparse_ini_file.php on line 9
array(0) {
}
array(1) {
@ -113,15 +111,15 @@ array(1) {
string(0) ""
}
Warning: Error parsing %sparse_ini_file.dat on line 2
in %s on line %d
Warning: syntax error, unexpected '=' in %sparse_ini_file.dat on line 2
in %sparse_ini_file.php on line 20
array(1) {
["test"]=>
string(0) ""
}
Warning: Error parsing %sparse_ini_file.dat on line 2
in %s on line %d
Warning: syntax error, unexpected '=' in %sparse_ini_file.dat on line 2
in %sparse_ini_file.php on line 26
array(1) {
["test"]=>
string(4) "test"

View file

@ -447,12 +447,15 @@ PHP_INI_BEGIN()
PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("always_populate_raw_post_data", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, always_populate_raw_post_data, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("realpath_cache_size", "16K", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_size_limit, virtual_cwd_globals, cwd_globals)
STD_PHP_INI_ENTRY("realpath_cache_ttl", "120", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_ttl, virtual_cwd_globals, cwd_globals)
STD_PHP_INI_ENTRY("user_ini.filename", ".user.ini", PHP_INI_SYSTEM, OnUpdateString, user_ini_filename, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("user_ini.cache_ttl", "300", PHP_INI_SYSTEM, OnUpdateLong, user_ini_cache_ttl, php_core_globals, core_globals)
PHP_INI_END()
/* }}} */
@ -1025,7 +1028,7 @@ PHP_FUNCTION(set_time_limit)
}
convert_to_string_ex(new_timeout);
if (zend_alter_ini_entry("max_execution_time", sizeof("max_execution_time"), Z_STRVAL_PP(new_timeout), Z_STRLEN_PP(new_timeout), PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == SUCCESS) {
if (zend_alter_ini_entry_ex("max_execution_time", sizeof("max_execution_time"), Z_STRVAL_PP(new_timeout), Z_STRLEN_PP(new_timeout), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == SUCCESS) {
RETURN_TRUE;
} else {
RETURN_FALSE;

View file

@ -161,6 +161,9 @@ struct _php_core_globals {
#endif
long max_input_nesting_level;
zend_bool in_user_include;
char *user_ini_filename;
long user_ini_cache_ttl;
};

View file

@ -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)); */
zend_hash_update(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, &hash, sizeof(zval *), NULL);
} else {
hash = *find_hash;
/* 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);
}
ALLOC_ZVAL(element);
*element = *arg2;
zval_copy_ctor(element);
INIT_PZVAL(element);
add_next_index_zval(hash, element);
/* 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 {
zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2, sizeof(zval), (void **) &entry);
}
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

View file

@ -24,6 +24,7 @@
#include "zend_ini.h"
BEGIN_EXTERN_C()
void config_zval_dtor(zval *zvalue);
int php_init_config(TSRMLS_D);
int php_shutdown_config(void);
void php_ini_register_extensions(TSRMLS_D);
@ -31,6 +32,12 @@ PHPAPI zval *cfg_get_entry(char *name, uint name_length);
PHPAPI int cfg_get_long(char *varname, long *result);
PHPAPI int cfg_get_double(char *varname, double *result);
PHPAPI int cfg_get_string(char *varname, char **result);
PHPAPI int php_parse_user_ini_file(char *dirname, char *ini_filename, HashTable *target_hash TSRMLS_DC);
PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage TSRMLS_DC);
PHPAPI void php_ini_activate_per_dir_config(char *path, uint path_len TSRMLS_DC);
#if ZEND_DEBUG
PHPAPI HashTable get_configuration_hash(void);
#endif
END_EXTERN_C()
#define PHP_INI_USER ZEND_INI_USER

View file

@ -63,6 +63,17 @@
; defaults (that is, if no php.ini is used, or if you delete these lines,
; the builtin defaults will be identical).
;;;;;;;;;;;;;;;;;;;;
; php.ini Options ;
;;;;;;;;;;;;;;;;;;;;
; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
;user_ini.filename = ".user.ini"
; To disable this feature set this option to empty value
;user_ini.filename =
; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)
;user_ini.cache_ttl = 300
;;;;;;;;;;;;;;;;;;;;
; Language Options ;

View file

@ -112,6 +112,18 @@
; Using short tags is discouraged when developing code meant for redistribution
; since short tags may not be supported on the target server.
;;;;;;;;;;;;;;;;;;;;
; php.ini Options ;
;;;;;;;;;;;;;;;;;;;;
; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
;user_ini.filename = ".user.ini"
; To disable this feature set this option to empty value
;user_ini.filename =
; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)
;user_ini.cache_ttl = 300
;;;;;;;;;;;;;;;;;;;;
; Language Options ;
;;;;;;;;;;;;;;;;;;;;

View file

@ -152,8 +152,30 @@ typedef struct _php_cgi_globals_struct {
#ifdef PHP_WIN32
zend_bool impersonate;
#endif
HashTable user_config_cache;
} php_cgi_globals_struct;
/* {{{ user_config_cache
*
* Key for each cache entry is dirname(PATH_TRANSLATED).
*
* NOTE: Each cache entry config_hash contains the combination from all user ini files found in
* the path starting from doc_root throught to dirname(PATH_TRANSLATED). There is no point
* storing per-file entries as it would not be possible to detect added / deleted entries
* between separate files.
*/
typedef struct _user_config_cache_entry {
time_t expires;
HashTable *user_config;
} user_config_cache_entry;
static void user_config_cache_entry_dtor(user_config_cache_entry *entry) /* {{{ */
{
zend_hash_destroy(entry->user_config);
free(entry->user_config);
}
/* }}} */
#ifdef ZTS
static int php_cgi_globals_id;
#define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
@ -566,12 +588,96 @@ static void sapi_cgi_log_message(char *message)
}
}
/* {{{ php_cgi_ini_activate_user_config
*/
static void php_cgi_ini_activate_user_config(char *path, int path_len, int start TSRMLS_DC)
{
char *ptr;
user_config_cache_entry *new_entry, *entry;
time_t request_time = sapi_get_request_time(TSRMLS_C);
/* Find cached config entry: If not found, create one */
if (zend_hash_find(&CGIG(user_config_cache), path, path_len + 1, (void **) &entry) == FAILURE) {
new_entry = pemalloc(sizeof(user_config_cache_entry), 1);
new_entry->expires = 0;
new_entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1);
zend_hash_init(new_entry->user_config, 0, NULL, (dtor_func_t) config_zval_dtor, 1);
zend_hash_update(&CGIG(user_config_cache), path, path_len + 1, new_entry, sizeof(user_config_cache_entry), (void **) &entry);
free(new_entry);
}
/* Check whether cache entry has expired and rescan if it is */
if (request_time > entry->expires) {
/* Clear the expired config */
zend_hash_clean(entry->user_config);
/* Walk through each directory and apply entries to user_config hash */
ptr = path + start; /* start is the point where doc_root ends! */
while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) {
*ptr = 0;
php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
*ptr = '/';
ptr++;
}
entry->expires = request_time + PG(user_ini_cache_ttl);
}
/* Activate ini entries with values from the user config hash */
php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS TSRMLS_CC);
}
/* }}} */
static int sapi_cgi_activate(TSRMLS_D)
{
char *path, *doc_root;
uint path_len, doc_root_len;
/* PATH_TRANSLATED should be defined at this stage but better safe than sorry :) */
if (!SG(request_info).path_translated) {
return FAILURE;
}
doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
if (!doc_root) {
return FAILURE;
}
doc_root_len = strlen(doc_root);
if (doc_root[doc_root_len - 1] == '/') {
--doc_root_len;
}
/* Prepare search path */
path_len = strlen(SG(request_info).path_translated);
path = zend_strndup(SG(request_info).path_translated, path_len);
php_dirname(path, path_len);
path_len = strlen(path);
/* Make sure we have trailing slash! */
if (!IS_SLASH(path[path_len])) {
path[path_len++] = DEFAULT_SLASH;
}
path[path_len] = 0;
/* Activate per-dir-system-configuration defined in php.ini and stored into configuration_hash during startup */
php_ini_activate_per_dir_config(path, path_len TSRMLS_CC); /* Note: for global settings sake we check from root to path */
/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
if (strlen(PG(user_ini_filename))) {
php_cgi_ini_activate_user_config(path, path_len, doc_root_len - 1 TSRMLS_CC);
}
free(path);
return SUCCESS;
}
static int sapi_cgi_deactivate(TSRMLS_D)
{
/* flush only when SAPI was started. The reasons are:
1. SAPI Deactivate is called from two places: module init and request shutdown
2. When the first call occurs and the request is not set up, flush fails on
FastCGI.
2. When the first call occurs and the request is not set up, flush fails on FastCGI.
*/
if (SG(sapi_started)) {
sapi_cgibin_flush(SG(server_context));
@ -587,7 +693,6 @@ static int php_cgi_startup(sapi_module_struct *sapi_module)
return SUCCESS;
}
/* {{{ sapi_module_struct cgi_sapi_module
*/
static sapi_module_struct cgi_sapi_module = {
@ -597,7 +702,7 @@ static sapi_module_struct cgi_sapi_module = {
php_cgi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
NULL, /* activate */
sapi_cgi_activate, /* activate */
sapi_cgi_deactivate, /* deactivate */
sapi_cgibin_ub_write, /* unbuffered write */
@ -1072,6 +1177,7 @@ static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_
#ifdef PHP_WIN32
php_cgi_globals->impersonate = 0;
#endif
zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1);
}
/* }}} */
@ -1093,6 +1199,8 @@ static PHP_MINIT_FUNCTION(cgi)
*/
static PHP_MSHUTDOWN_FUNCTION(cgi)
{
zend_hash_destroy(&CGIG(user_config_cache));
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}