diff options
| -rw-r--r-- | Zend/zend.c | 25 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 16 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 2 | ||||
| -rw-r--r-- | Zend/zend_globals.h | 3 | ||||
| -rw-r--r-- | ext/filter/filter.c | 16 | ||||
| -rw-r--r-- | ext/mbstring/mb_gpc.c | 2 | ||||
| -rw-r--r-- | ext/pcre/php_pcre.c | 2 | ||||
| -rw-r--r-- | ext/standard/basic_functions.c | 59 | ||||
| -rw-r--r-- | ext/standard/basic_functions.h | 4 | ||||
| -rw-r--r-- | ext/standard/php_string.h | 4 | ||||
| -rw-r--r-- | ext/standard/string.c | 8 | ||||
| -rw-r--r-- | main/SAPI.c | 19 | ||||
| -rw-r--r-- | main/SAPI.h | 4 | ||||
| -rw-r--r-- | main/php_globals.h | 2 | ||||
| -rw-r--r-- | main/php_variables.c | 403 | ||||
| -rw-r--r-- | main/php_variables.h | 4 | ||||
| -rw-r--r-- | main/rfc1867.c | 1190 | ||||
| -rw-r--r-- | sapi/apache/mod_php.c | 6 | ||||
| -rw-r--r-- | sapi/apache2filter/sapi_apache2.c | 12 | ||||
| -rw-r--r-- | sapi/apache2handler/sapi_apache2.c | 16 | ||||
| -rw-r--r-- | sapi/cgi/cgi_main.c | 17 | ||||
| -rw-r--r-- | unicode-todo.txt | 3 |
22 files changed, 492 insertions, 1325 deletions
diff --git a/Zend/zend.c b/Zend/zend.c index f1576b5abf..3445420222 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -195,13 +195,17 @@ ZEND_INI_BEGIN() STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals) STD_ZEND_INI_ENTRY("unicode.runtime_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, runtime_encoding_conv, zend_unicode_globals, unicode_globals) STD_ZEND_INI_ENTRY("unicode.script_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, script_encoding_conv, zend_unicode_globals, unicode_globals) - STD_ZEND_INI_ENTRY("unicode.http_input_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, http_input_encoding_conv, zend_unicode_globals, unicode_globals) STD_ZEND_INI_ENTRY("unicode.filesystem_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, filesystem_encoding_conv, zend_unicode_globals, unicode_globals) /* * This is used as a default for the stream contexts. It's not an actual * UConverter because each stream needs its own. */ STD_ZEND_INI_ENTRY("unicode.stream_encoding", "UTF-8", ZEND_INI_ALL, OnUpdateStringUnempty, stream_encoding, zend_unicode_globals, unicode_globals) + /* + * This is used as a default for the request encoding. It's not an actual + * UConverter because the request encoding converter is reset on each request. + */ + STD_ZEND_INI_ENTRY("unicode.request_encoding_default", "UTF-8", ZEND_INI_ALL, OnUpdateStringUnempty, request_encoding_def, zend_unicode_globals, unicode_globals) ZEND_INI_END() @@ -1008,8 +1012,8 @@ static void unicode_globals_ctor(zend_unicode_globals *unicode_globals TSRMLS_DC unicode_globals->runtime_encoding_conv = NULL; unicode_globals->output_encoding_conv = NULL; unicode_globals->script_encoding_conv = NULL; - unicode_globals->http_input_encoding_conv = NULL; unicode_globals->filesystem_encoding_conv = NULL; + unicode_globals->request_encoding_conv = NULL; zend_set_converter_encoding(&unicode_globals->utf8_conv, "UTF-8"); zend_set_converter_error_mode(unicode_globals->utf8_conv, ZEND_TO_UNICODE, ZEND_CONV_ERROR_STOP); zend_set_converter_encoding(&unicode_globals->ascii_conv, "US-ASCII"); @@ -1061,11 +1065,6 @@ static void unicode_globals_dtor(zend_unicode_globals *unicode_globals TSRMLS_DC unicode_globals->script_encoding_conv != unicode_globals->ascii_conv) { ucnv_close(unicode_globals->script_encoding_conv); } - if (unicode_globals->http_input_encoding_conv && - unicode_globals->http_input_encoding_conv != unicode_globals->utf8_conv && - unicode_globals->http_input_encoding_conv != unicode_globals->ascii_conv) { - ucnv_close(unicode_globals->http_input_encoding_conv); - } if (unicode_globals->utf8_conv) { ucnv_close(unicode_globals->utf8_conv); } @@ -1385,12 +1384,24 @@ static void init_unicode_request_globals(TSRMLS_D) /* {{{ */ UG(default_locale) = safe_estrdup(uloc_getDefault()); UG(default_collator) = NULL; + if (strcmp(UG(request_encoding_def), "binary") != 0) { + if (zend_set_converter_encoding(&UG(request_encoding_conv), UG(request_encoding_def)) == FAILURE) { + zend_error(E_CORE_ERROR, "Unrecognized encoding '%s' used for request_encoding", UG(request_encoding_def)); + return; + } + zend_set_converter_error_mode(UG(request_encoding_conv), ZEND_TO_UNICODE, ZEND_CONV_ERROR_STOP); + } + zend_reset_locale_deps(TSRMLS_C); } /* }}} */ static void shutdown_unicode_request_globals(TSRMLS_D) /* {{{ */ { + if (UG(request_encoding_conv)) { + ucnv_close(UG(request_encoding_conv)); + UG(request_encoding_conv) = NULL; + } zend_collator_destroy(UG(default_collator)); efree(UG(default_locale)); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e55c8b5ebe..86afab0875 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -104,11 +104,25 @@ static void build_runtime_defined_function_key(zval *result, zend_uchar type, co } /* }}} */ -int zend_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */ +ZEND_API int zend_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */ { auto_global->armed = (auto_global->auto_global_callback ? 1 : 0); return 0; } + +ZEND_API int zend_auto_global_arm_by_name(const char *name, zend_uint name_len TSRMLS_DC) /* {{{ */ +{ + zend_auto_global *auto_global; + + if (zend_hash_find(CG(auto_globals), name, name_len+1, (void **) &auto_global)==FAILURE) { + return FAILURE; + } + + auto_global->armed = 1; + CG(auto_globals_cache)[auto_global->index] = NULL; + + return SUCCESS; +} /* }}} */ int zend_auto_global_disable_jit(const char *varname, zend_uint varname_length TSRMLS_DC) /* {{{ */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 52f0f8852c..fb91a42fe9 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -625,6 +625,8 @@ ZEND_API int zend_register_auto_global_ex(const char *name, uint name_len, zend_ ZEND_API zend_bool zend_is_auto_global(const char *name, uint name_len TSRMLS_DC); ZEND_API zend_bool zend_u_is_auto_global(zend_uchar type, zstr name, uint name_len TSRMLS_DC); ZEND_API zend_bool zend_u_is_auto_global_ex(zend_uchar type, zstr name, uint name_len, zend_bool runtime, zend_auto_global **ret TSRMLS_DC); +ZEND_API int zend_auto_global_arm(zend_auto_global *auto_global TSRMLS_DC); +ZEND_API int zend_auto_global_arm_by_name(const char *name, zend_uint name_len TSRMLS_DC); ZEND_API int zend_auto_global_disable_jit(const char *varname, zend_uint varname_length TSRMLS_DC); ZEND_API size_t zend_dirname(char *path, size_t len); ZEND_API size_t zend_u_dirname(UChar *path, size_t len); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index b74c8a2dc1..2139e24839 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -292,8 +292,8 @@ struct _zend_unicode_globals { UConverter *fallback_encoding_conv; /* converter for default encoding for IS_STRING type */ UConverter *runtime_encoding_conv; /* runtime encoding converter */ UConverter *output_encoding_conv; /* output layer converter */ + UConverter *request_encoding_conv; /* http request encoding converter */ UConverter *script_encoding_conv; /* default script encoding converter */ - UConverter *http_input_encoding_conv;/* http input encoding converter */ UConverter *filesystem_encoding_conv;/* default filesystem converter (entries, not contents) */ UConverter *utf8_conv; /* all-purpose UTF-8 converter */ UConverter *ascii_conv; /* all-purpose ASCII converter */ @@ -301,6 +301,7 @@ struct _zend_unicode_globals { char *stream_encoding; /* default stream encoding (contents, not FS entries) Uses name of encoding rather than a real converter because each stream needs its own instance */ + char *request_encoding_def; /* the default http request encoding */ uint16_t from_error_mode; UChar from_subst_char[3]; diff --git a/ext/filter/filter.c b/ext/filter/filter.c index 853d033e3d..8370a321bc 100644 --- a/ext/filter/filter.c +++ b/ext/filter/filter.c @@ -139,7 +139,7 @@ zend_module_entry filter_module_entry = { filter_functions, PHP_MINIT(filter), PHP_MSHUTDOWN(filter), - NULL, + PHP_RINIT(filter), PHP_RSHUTDOWN(filter), PHP_MINFO(filter), "0.11.0", @@ -287,6 +287,20 @@ PHP_MSHUTDOWN_FUNCTION(filter) } /* }}} */ +/* {{{ PHP_RINIT_FUNCTION + */ +PHP_RINIT_FUNCTION(filter) +{ + IF_G(get_array) = NULL; + IF_G(post_array) = NULL; + IF_G(cookie_array) = NULL; + IF_G(server_array) = NULL; + IF_G(env_array) = NULL; + IF_G(session_array) = NULL; + return SUCCESS; +} +/* }}} */ + /* {{{ PHP_RSHUTDOWN_FUNCTION */ #define VAR_ARRAY_COPY_DTOR(a) \ diff --git a/ext/mbstring/mb_gpc.c b/ext/mbstring/mb_gpc.c index 1a7476d4bd..01a4b71557 100644 --- a/ext/mbstring/mb_gpc.c +++ b/ext/mbstring/mb_gpc.c @@ -326,7 +326,7 @@ enum mbfl_no_encoding _php_mb_encoding_handler_ex(const php_mb_encoding_handler_ val = estrndup(val, val_len); if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { /* add variable to symbol table */ - php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); + php_register_variable_safe(IS_STRING, ZSTR(var), ZSTR(val), new_val_len, array_ptr TSRMLS_CC); } efree(val); diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index cc06bd86df..1d4eb94c71 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -996,7 +996,7 @@ static int preg_do_eval(char *eval_str, int eval_str_len, char *subject, match = subject + offsets[backref<<1]; match_len = offsets[(backref<<1)+1] - offsets[backref<<1]; if (match_len) { - esc_match = php_addslashes_ex(match, match_len, &esc_match_len, 0, 1 TSRMLS_CC); + esc_match = php_addslashes_ex(match, match_len, &esc_match_len, 0 TSRMLS_CC); } else { esc_match = match; esc_match_len = 0; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 59d9aefb8a..fa4d2a3fc5 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -861,6 +861,13 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_sys_getloadavg, 0) ZEND_END_ARG_INFO() #endif + +ZEND_BEGIN_ARG_INFO(arginfo_request_set_encoding, 0) + ZEND_ARG_INFO(0, encoding) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_request_had_errors, 0) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ assert.c */ ZEND_BEGIN_ARG_INFO(arginfo_assert, 0) @@ -3364,6 +3371,9 @@ const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(sys_get_temp_dir, arginfo_sys_get_temp_dir) + PHP_FE(request_set_encoding, arginfo_request_set_encoding) + PHP_FE(request_had_errors, arginfo_request_had_errors) + {NULL, NULL, NULL} }; /* }}} */ @@ -6213,6 +6223,55 @@ PHP_FUNCTION(sys_getloadavg) /* }}} */ #endif +PHP_FUNCTION(request_set_encoding) +{ + char *req_enc; + int req_enc_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &req_enc, &req_enc_len) == FAILURE) { + return; + } + + if (req_enc_len == 0 || strcmp(req_enc, "binary") == 0) { + /* converter is already unset, no need to re-arm, just return */ + if (UG(request_encoding_conv) == NULL) + return; + ucnv_close(UG(request_encoding_conv)); + UG(request_encoding_conv) = NULL; + } else { + /* if the converter is the same as the requested one, no need to re-arm, just + * return */ + if (UG(request_encoding_conv)) { + UErrorCode status = U_ZERO_ERROR; + const char *current = ucnv_getName(UG(request_encoding_conv), &status); + if (!ucnv_compareNames(current, req_enc)) { + return; + } + } + if (zend_set_converter_encoding(&UG(request_encoding_conv), req_enc) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized encoding '%s'", req_enc); + RETURN_FALSE; + } + zend_set_converter_error_mode(UG(request_encoding_conv), ZEND_TO_UNICODE, ZEND_CONV_ERROR_STOP); + } + + zend_auto_global_arm_by_name(ZEND_STRL("_GET") TSRMLS_CC); + zend_auto_global_arm_by_name(ZEND_STRL("_POST") TSRMLS_CC); + zend_auto_global_arm_by_name(ZEND_STRL("_FILES") TSRMLS_CC); + zend_auto_global_arm_by_name(ZEND_STRL("_REQUEST") TSRMLS_CC); + + RETURN_TRUE; +} + +PHP_FUNCTION(request_had_errors) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(PG(request_decoding_error)); +} + /* * Local variables: * tab-width: 4 diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index b494214f45..0e4dfcf47c 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -141,6 +141,10 @@ PHP_FUNCTION(stream_bucket_new); PHP_MINIT_FUNCTION(user_filters); PHP_RSHUTDOWN_FUNCTION(user_filters); +/* Unicode-related */ +PHP_FUNCTION(request_set_encoding); +PHP_FUNCTION(request_had_errors); + PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers TSRMLS_DC); PHPAPI char *php_get_current_user(void); PHPAPI int php_prefix_varname(zval *result, zval *prefix, zstr var_name, int var_name_len, int var_name_type, zend_bool add_underscore TSRMLS_DC); diff --git a/ext/standard/php_string.h b/ext/standard/php_string.h index 4a9c8fba9d..c387140355 100644 --- a/ext/standard/php_string.h +++ b/ext/standard/php_string.h @@ -129,9 +129,9 @@ PHPAPI UChar *php_u_strtoupper(UChar *s, int *len, const char *locale); PHPAPI UChar *php_u_strtolower(UChar *s, int *len, const char *locale); PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen); PHPAPI UChar *php_u_addslashes(UChar *str, int length, int *new_length, int freeit TSRMLS_DC); -PHPAPI UChar *php_u_addslashes_ex(UChar *str, int length, int *new_length, int freeit, int ignore_sybase TSRMLS_DC); +PHPAPI UChar *php_u_addslashes_ex(UChar *str, int length, int *new_length, int freeit TSRMLS_DC); PHPAPI char *php_addslashes(char *str, int length, int *new_length, int freeit TSRMLS_DC); -PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int freeit, int ignore_sybase TSRMLS_DC); +PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int freeit TSRMLS_DC); PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int freeit, char *what, int wlength TSRMLS_DC); PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC); PHPAPI void php_u_stripslashes(UChar *str, int *len TSRMLS_DC); diff --git a/ext/standard/string.c b/ext/standard/string.c index 47b0e7f84e..447a22c21d 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -4874,13 +4874,13 @@ PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_ */ PHPAPI UChar *php_u_addslashes(UChar *str, int length, int *new_length, int should_free TSRMLS_DC) { - return php_u_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC); + return php_u_addslashes_ex(str, length, new_length, should_free TSRMLS_CC); } /* }}} */ /* {{{ php_u_addslashes_ex */ -PHPAPI UChar *php_u_addslashes_ex(UChar *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC) +PHPAPI UChar *php_u_addslashes_ex(UChar *str, int length, int *new_length, int should_free TSRMLS_DC) { UChar *buf; int32_t buf_len = 0, i = 0; @@ -4929,13 +4929,13 @@ PHPAPI UChar *php_u_addslashes_ex(UChar *str, int length, int *new_length, int s */ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC) { - return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC); + return php_addslashes_ex(str, length, new_length, should_free TSRMLS_CC); } /* }}} */ /* {{{ php_addslashes_ex */ -PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC) +PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free TSRMLS_DC) { /* maximum string length, worst case situation */ char *new_str; diff --git a/main/SAPI.c b/main/SAPI.c index 55a3defd41..327856c129 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -118,13 +118,22 @@ SAPI_API void sapi_free_header(sapi_header_struct *sapi_header) SAPI_API void sapi_handle_post(void *arg TSRMLS_DC) { if (SG(request_info).post_entry && SG(request_info).content_type_dup) { + /* + * We need to re-populate post_data from the stored raw POST data in case we had + * any before, so that the handler can get to it. + */ + if (SG(request_info).post_data == NULL && SG(request_info).raw_post_data != NULL) { + SG(request_info).post_data = estrndup(SG(request_info).raw_post_data, SG(request_info).raw_post_data_length); + } SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC); if (SG(request_info).post_data) { efree(SG(request_info).post_data); SG(request_info).post_data = NULL; } +#if 0 /* UTODO see if this works */ efree(SG(request_info).content_type_dup); SG(request_info).content_type_dup = NULL; +#endif } } @@ -384,6 +393,8 @@ SAPI_API void sapi_activate(TSRMLS_D) SG(request_info).headers_only = 0; } SG(rfc1867_uploaded_files) = NULL; + SG(rfc1867_vars) = NULL; + SG(rfc1867_vars) = NULL; /* handle request mehtod */ if (SG(server_context)) { @@ -468,6 +479,14 @@ SAPI_API void sapi_deactivate(TSRMLS_D) if (SG(rfc1867_uploaded_files)) { destroy_uploaded_files_hash(TSRMLS_C); } + if (SG(rfc1867_vars)) { + zend_hash_destroy(SG(rfc1867_vars)); + FREE_HASHTABLE(SG(rfc1867_vars)); + } + if (SG(rfc1867_files_vars)) { + zend_hash_destroy(SG(rfc1867_files_vars)); + FREE_HASHTABLE(SG(rfc1867_files_vars)); + } if (SG(sapi_headers).mimetype) { efree(SG(sapi_headers).mimetype); SG(sapi_headers).mimetype = NULL; diff --git a/main/SAPI.h b/main/SAPI.h index 064c275b9b..d85a81ed24 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -131,6 +131,10 @@ typedef struct _sapi_globals_struct { zend_bool sapi_started; time_t global_request_time; HashTable known_post_content_types; + + /* raw POST and FILES variables from RFC1867 handler */ + HashTable *rfc1867_vars; + HashTable *rfc1867_files_vars; } sapi_globals_struct; diff --git a/main/php_globals.h b/main/php_globals.h index 7b61cca20d..49e6bdfafc 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -154,6 +154,8 @@ struct _php_core_globals { zend_bool mail_x_header; char *mail_log; + + zend_bool request_decoding_error; }; diff --git a/main/php_variables.c b/main/php_variables.c index 027b215173..4f9f98c1ec 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -29,41 +29,82 @@ #include "SAPI.h" #include "php_logos.h" #include "zend_globals.h" +#include "rfc1867.h" /* for systems that need to override reading of environment variables */ void _php_import_environment_variables(zval *array_ptr TSRMLS_DC); PHPAPI void (*php_import_environment_variables)(zval *array_ptr TSRMLS_DC) = _php_import_environment_variables; +static int php_decode_raw_var_array(HashTable *raw_array, zval *track_array TSRMLS_DC); PHPAPI void php_register_variable(char *var, char *strval, zval *track_vars_array TSRMLS_DC) { - php_register_variable_safe(var, strval, strlen(strval), track_vars_array TSRMLS_CC); + php_register_variable_safe(IS_STRING, ZSTR(var), ZSTR(strval), strlen(strval), track_vars_array TSRMLS_CC); } -/* binary-safe version */ -PHPAPI void php_register_variable_safe(char *var, char *strval, int str_len, zval *track_vars_array TSRMLS_DC) +PHPAPI int php_register_variable_with_conv(UConverter *conv, char *var, int var_len, char *val, int val_len, zval *array_ptr, int filter_arg TSRMLS_DC) { - zval new_entry; - assert(strval != NULL); - - /* Prepare value */ - Z_STRLEN(new_entry) = str_len; - Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry)); - Z_TYPE(new_entry) = IS_STRING; + zstr c_var, c_val; + int c_var_len, c_val_len; + zend_uchar type = IS_UNICODE; + + if (conv == NULL) { + type = IS_STRING; + } + + if (type == IS_UNICODE) { + c_var.u = c_val.u = NULL; + if (zend_string_to_unicode(conv, &c_var.u, &c_var_len, var, var_len TSRMLS_CC) == FAILURE || + zend_string_to_unicode(conv, &c_val.u, &c_val_len, val, val_len TSRMLS_CC) == FAILURE) { + + if (c_var.u) { + efree(c_var.u); + } + if (c_val.u) { + efree(c_val.u); + } + return FAILURE; + + } + } else { + c_var.s = var; + c_var_len = var_len; + c_val.s = val; + c_val_len = val_len; + } + + /* UTODO + * do input filtering + */ + php_register_variable_safe(type, c_var, c_val, c_val_len, array_ptr TSRMLS_CC); - php_register_variable_ex(var, &new_entry, track_vars_array TSRMLS_CC); + if (type == IS_UNICODE) { + efree(c_var.u); + efree(c_val.u); + } + + return SUCCESS; } -PHPAPI void php_u_register_variable_safe(UChar *var, UChar *strval, int str_len, zval *track_vars_array TSRMLS_DC) +PHPAPI void php_register_variable_safe(zend_uchar type, zstr var, zstr strval, int str_len, zval *track_vars_array TSRMLS_DC) { zval new_entry; - assert(strval != NULL); - - /* Prepare value */ - Z_USTRLEN(new_entry) = str_len; - Z_USTRVAL(new_entry) = eustrndup(strval, Z_USTRLEN(new_entry)); - Z_TYPE(new_entry) = IS_UNICODE; + assert(strval.v != NULL); - php_u_register_variable_ex(var, &new_entry, track_vars_array TSRMLS_CC); + if (type == IS_UNICODE) { + /* Prepare value */ + Z_USTRLEN(new_entry) = str_len; + Z_USTRVAL(new_entry) = eustrndup(strval.u, Z_USTRLEN(new_entry)); + Z_TYPE(new_entry) = IS_UNICODE; + + php_u_register_variable_ex(var.u, &new_entry, track_vars_array TSRMLS_CC); + } else { + /* Prepare value */ + Z_STRLEN(new_entry) = str_len; + Z_STRVAL(new_entry) = estrndup(strval.s, Z_STRLEN(new_entry)); + Z_TYPE(new_entry) = IS_STRING; + + php_register_variable_ex(var.s, &new_entry, track_vars_array TSRMLS_CC); + } } PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC) @@ -78,7 +119,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars HashTable *symtable1 = NULL; assert(var_name != NULL); - + if (track_vars_array) { symtable1 = Z_ARRVAL_P(track_vars_array); } @@ -119,6 +160,9 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars return; } +#if 0 + // Do we realy need this, now that register_globals is gone? Is it the job of this + // function to guard against calls with active_symbol_table as the array? /* GLOBALS hijack attempt, reject parameter */ if (symtable1 == EG(active_symbol_table) && var_len == sizeof("GLOBALS")-1 && @@ -127,6 +171,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars efree(var_orig); return; } +#endif index = var; index_len = var_len; @@ -176,7 +221,7 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars return; } *ip = 0; - new_idx_len = strlen(index_s); + new_idx_len = strlen(index_s); } if (!index) { @@ -184,11 +229,11 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars array_init(gpc_element); zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } else { - if (zend_rt_symtable_find(symtable1, index, index_len + 1, (void **) &gpc_element_p) == FAILURE + if (zend_symtable_find(symtable1, index, index_len + 1, (void **) &gpc_element_p) == FAILURE || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) { MAKE_STD_ZVAL(gpc_element); array_init(gpc_element); - zend_rt_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } } symtable1 = Z_ARRVAL_PP(gpc_element_p); @@ -212,18 +257,18 @@ plain_var: if (!index) { zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } else { - /* + /* * According to rfc2965, more specific paths are listed above the less specific ones. * If we encounter a duplicate cookie name, we should skip it, since it is not possible * to have the same (plain text) cookie name for the same path and we should not overwrite * more specific cookies with the less specific ones. */ if (PG(http_globals)[TRACK_VARS_COOKIE] && - symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) && - zend_rt_symtable_exists(symtable1, index, index_len+1)) { + symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) && + zend_symtable_exists(symtable1, index, index_len+1)) { zval_ptr_dtor(&gpc_element); } else { - zend_rt_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } } } @@ -234,7 +279,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a { UChar *p = NULL; UChar *ip; /* index pointer */ - UChar *index; + UChar *index, *var_orig; int var_len, index_len; zval *gpc_element, **gpc_element_p; zend_bool is_array; @@ -255,6 +300,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a /* * Prepare variable name */ + var_orig = eustrdup(var); ip = u_strchr(var, 0x5b /*'['*/); if (ip) { is_array = 1; @@ -269,6 +315,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a var_len = u_strlen(var); if (var_len==0) { /* empty variable name, or variable name with a space in it */ zval_dtor(val); + efree(var_orig); return; } /* ensure that we don't have spaces or dots in the variable name (not binary safe) */ @@ -276,7 +323,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a switch(*p) { case 0x20: /*' '*/ case 0x2e: /*'.'*/ - *p=0x5f; /*'_'*/ + *p=0x5f; /*'_'*/ break; } } @@ -287,19 +334,16 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a if (is_array) { int nest_level = 0; while (1) { - zstr escaped_index = NULL_ZSTR; UChar *index_s; int new_idx_len = 0; if(++nest_level > PG(max_input_nesting_level)) { HashTable *ht; - zstr tmp_var; /* too many levels of nesting */ ht = Z_ARRVAL_P(track_vars_array); - tmp_var.u = var; - zend_u_hash_del(ht, IS_UNICODE, tmp_var, var_len + 1); + zend_u_hash_del(ht, IS_UNICODE, ZSTR(var), var_len + 1); zval_dtor(val); /* do not output the error message to the screen, @@ -307,6 +351,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a if (!PG(display_errors)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variable nesting level exceeded %ld. To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level)); } + efree(var_orig); return; } @@ -331,7 +376,7 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a return; } *ip = 0; - new_idx_len = u_strlen(index_s); + new_idx_len = u_strlen(index_s); } if (!index) { @@ -339,16 +384,11 @@ PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_a array_init(gpc_element); zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } else { - escaped_index.u = index; - - if (zend_u_symtable_find(symtable1, IS_UNICODE, escaped_index, index_len+1, (void **) &gpc_element_p)==FAILURE + if (zend_u_symtable_find(symtable1, IS_UNICODE, ZSTR(index), index_len+1, (void **) &gpc_element_p)==FAILURE || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) { MAKE_STD_ZVAL(gpc_element); array_init(gpc_element); - zend_u_symtable_update(symtable1, IS_UNICODE, escaped_index, index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); - } - if (index!=escaped_index.u) { - efree(escaped_index.u); + zend_u_symtable_update(symtable1, IS_UNICODE, ZSTR(index), index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } } symtable1 = Z_ARRVAL_PP(gpc_element_p); @@ -372,30 +412,34 @@ plain_var: if (!index) { zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); } else { - /* UTODO fix for php_addslashes case */ - /* char *escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC); */ - zstr escaped_index; - - escaped_index.u = index; - zend_u_symtable_update(symtable1, IS_UNICODE, escaped_index, index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); - /* efree(escaped_index); */ + /* + * According to rfc2965, more specific paths are listed above the less specific ones. + * If we encounter a duplicate cookie name, we should skip it, since it is not possible + * to have the same (plain text) cookie name for the same path and we should not overwrite + * more specific cookies with the less specific ones. + */ + if (PG(http_globals)[TRACK_VARS_COOKIE] && + symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) && + zend_u_symtable_exists(symtable1, IS_UNICODE, ZSTR(index), index_len+1)) { + zval_ptr_dtor(&gpc_element); + } else { + zend_u_symtable_update(symtable1, IS_UNICODE, ZSTR(index), index_len+1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + } } } + efree(var_orig); } SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler) { char *var, *val, *e, *s, *p; zval *array_ptr = (zval *) arg; - UConverter *input_conv = UG(http_input_encoding_conv); + UConverter *conv = UG(request_encoding_conv); if (SG(request_info).post_data == NULL) { return; - } - - if (!input_conv) { - input_conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); } + PG(request_decoding_error) = 0; s = SG(request_info).post_data; e = s + SG(request_info).post_data_length; @@ -403,11 +447,8 @@ SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler) while (s < e && (p = memchr(s, '&', (e - s)))) { last_value: if ((val = memchr(s, '=', (p - s)))) { /* have a value */ - UChar *u_var, *u_val; - int u_var_len, u_val_len; int var_len; int val_len; - UErrorCode status1 = U_ZERO_ERROR, status2 = U_ZERO_ERROR; var = s; var_len = val - s; @@ -415,16 +456,12 @@ last_value: php_url_decode(var, var_len); val++; val_len = php_url_decode(val, (p - val)); - zend_string_to_unicode_ex(input_conv, &u_var, &u_var_len, var, var_len, &status1); - zend_string_to_unicode_ex(input_conv, &u_val, &u_val_len, val, val_len, &status2); - if (U_SUCCESS(status1) && U_SUCCESS(status2)) { - /* UTODO add input filtering */ - php_u_register_variable_safe(u_var, u_val, u_val_len, array_ptr TSRMLS_CC); - } else { - /* UTODO set a user-accessible flag to indicate that conversion failed? */ + if (php_register_variable_with_conv(conv, var, var_len, val, val_len, array_ptr, PARSE_POST) == FAILURE) { + zend_error(E_WARNING, "Failed to decode _POST array"); + PG(request_decoding_error) = 1; + zend_hash_clean(Z_ARRVAL_P(array_ptr)); + return; } - efree(u_var); - efree(u_val); } s = p + 1; } @@ -448,8 +485,11 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) zval *array_ptr; int free_buffer = 0; char *strtok_buf = NULL; - UConverter *input_conv = UG(http_input_encoding_conv); - + char *arg_names[] = { "_POST", "_GET", "_COOKIE", "string" }; + UConverter *conv; + + PG(request_decoding_error) = 0; + switch (arg) { case PARSE_POST: case PARSE_GET: @@ -484,8 +524,24 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) } if (arg == PARSE_POST) { - sapi_handle_post(array_ptr TSRMLS_CC); - return; + if (SG(request_info).post_entry && + SG(request_info).post_entry->post_handler == rfc1867_post_handler) { + + if (SG(rfc1867_vars) == NULL) { + sapi_handle_post(NULL TSRMLS_CC); + } + if (SG(rfc1867_vars) != NULL) { + PG(request_decoding_error) = 0; + if (php_decode_raw_var_array(SG(rfc1867_vars), array_ptr TSRMLS_CC) == FAILURE) { + zend_error(E_WARNING, "Failed to decode _POST array"); + PG(request_decoding_error) = 1; + zend_hash_clean(Z_ARRVAL_P(array_ptr)); + } + } + return; + } else { + sapi_handle_post(array_ptr TSRMLS_CC); + } } if (arg == PARSE_GET) { /* GET data */ @@ -496,6 +552,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) } else { free_buffer = 0; } + conv = UG(request_encoding_conv); } else if (arg == PARSE_COOKIE) { /* Cookie data */ c_var = SG(request_info).cookie_data; if (c_var && *c_var) { @@ -507,6 +564,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) } else if (arg == PARSE_STRING) { /* String data */ res = str; free_buffer = 1; + conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); } if (!res) { @@ -523,18 +581,10 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) break; } - if (!input_conv) { - input_conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); - } - var = php_strtok_r(res, separator, &strtok_buf); while (var) { - int var_len; - /* unsigned int new_val_len; see below */ - UChar *u_var, *u_val; - int u_var_len, u_val_len; - UErrorCode status = U_ZERO_ERROR; + int var_len, val_len; val = strchr(var, '='); @@ -554,37 +604,20 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) var_len = strlen(var); php_url_decode(var, var_len); - zend_string_to_unicode_ex(input_conv, &u_var, &u_var_len, var, var_len, &status); - if (U_FAILURE(status)) { - /* UTODO set a user-accessible flag to indicate that conversion failed? */ - efree(u_var); - goto next_var; - } - if (val) { /* have a value */ - int val_len; - val_len = php_url_decode(val, strlen(val)); - zend_string_to_unicode_ex(input_conv, &u_val, &u_val_len, val, val_len, &status); - if (U_FAILURE(status)) { - /* UTODO set a user-accessible flag to indicate that conversion failed? */ - efree(u_var); - efree(u_val); - goto next_var; - } } else { - u_val_len = 0; - u_val = eustrndup(EMPTY_STR, 0); + val = ""; + val_len = 0; } - php_u_register_variable_safe(u_var, u_val, u_val_len, array_ptr TSRMLS_CC); - /* UTODO need to make input_filter Unicode aware */ - /* - if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { - php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); + + if (php_register_variable_with_conv(conv, var, var_len, val, val_len, array_ptr, arg) == FAILURE) { + zend_error(E_WARNING, "Failed to decode %s array", arg_names[arg]); + PG(request_decoding_error) = 1; + zend_hash_clean(Z_ARRVAL_P(array_ptr)); + break; } - */ - efree(u_var); - efree(u_val); + next_var: var = php_strtok_r(NULL, separator, &strtok_buf); } @@ -624,12 +657,6 @@ void _php_import_environment_variables(zval *array_ptr TSRMLS_DC) } } -zend_bool php_std_auto_global_callback(char *name, uint name_len TSRMLS_DC) -{ - zend_printf("%s\n", name); - return 0; /* don't rearm */ -} - /* {{{ php_build_argv */ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) @@ -637,11 +664,11 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) zval *arr, *argc, *tmp; int count = 0; char *ss, *space; - + if (!(SG(request_info).argc || track_vars_array)) { return; } - + ALLOC_INIT_ZVAL(arr); array_init(arr); @@ -668,6 +695,10 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) } /* auto-type */ ALLOC_ZVAL(tmp); + /* UTODO + * use UG(request_encoding) here. This also means that we need to clean out + * and re-arm $_SERVER and clean out $argv on request_set_encoding() + */ ZVAL_RT_STRING(tmp, ss, 1); INIT_PZVAL(tmp); count++; @@ -697,7 +728,7 @@ static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC) Z_ADDREF_P(argc); zend_ascii_hash_update(&EG(symbol_table), "argv", sizeof("argv"), &arr, sizeof(zval *), NULL); zend_ascii_hash_add(&EG(symbol_table), "argc", sizeof("argc"), &argc, sizeof(zval *), NULL); - } + } if (track_vars_array) { Z_ADDREF_P(arr); Z_ADDREF_P(argc); @@ -798,9 +829,72 @@ static void php_autoglobal_merge(HashTable *dest, HashTable *src TSRMLS_DC) } /* }}} */ +static int php_decode_raw_var_array(HashTable *raw_array, zval *track_array TSRMLS_DC) +{ + zstr raw_var; + uint raw_var_len; + zval **raw_value; + zstr var, value; + int var_len, value_len; + ulong num_index; + zend_uchar type = IS_UNICODE; + UConverter *conv = UG(request_encoding_conv); + + if (conv == NULL) { + type = IS_STRING; + } + + for (zend_hash_internal_pointer_reset(raw_array); + zend_hash_get_current_data(raw_array, (void **)&raw_value) == SUCCESS; + zend_hash_move_forward(raw_array)) { + + zend_hash_get_current_key_ex(raw_array, &raw_var, &raw_var_len, &num_index, 0, NULL); + + if (type == IS_UNICODE) { + var.u = value.u = NULL; + + if (zend_string_to_unicode(conv, &var.u, &var_len, raw_var.s, raw_var_len) == FAILURE) { + return FAILURE; + } + + if (Z_TYPE_PP(raw_value) == IS_STRING) { + if (zend_string_to_unicode(conv, &value.u, &value_len, Z_STRVAL_PP(raw_value), Z_STRLEN_PP(raw_value)) == FAILURE) { + efree(var.u); + return FAILURE; + } + + /* UTODO add input filtering */ + php_register_variable_safe(IS_UNICODE, var, value, value_len, track_array TSRMLS_CC); + efree(value.u); + } else { + php_u_register_variable_ex(var.u, *raw_value, track_array TSRMLS_CC); + } + + efree(var.u); + } else { + var.s = raw_var.s; + var_len = raw_var_len; + if (Z_TYPE_PP(raw_value) == IS_STRING) { + value.s = Z_STRVAL_PP(raw_value); + value_len = Z_STRLEN_PP(raw_value); + + /* UTODO add input filtering */ + php_register_variable_safe(IS_STRING, var, value, value_len, track_array TSRMLS_CC); + } else { + php_register_variable_ex(var.s, *raw_value, track_array TSRMLS_CC); + } + } + } + + return SUCCESS; +} + static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS_DC); static zend_bool php_auto_globals_create_env(char *name, uint name_len TSRMLS_DC); static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRMLS_DC); +static zend_bool php_auto_globals_decode_get(char *name, uint name_len TSRMLS_DC); +static zend_bool php_auto_globals_decode_post(char *name, uint name_len TSRMLS_DC); +static zend_bool php_auto_globals_decode_files(char *name, uint name_len TSRMLS_DC); /* {{{ php_hash_environment */ @@ -831,13 +925,6 @@ int php_hash_environment(TSRMLS_D) for (p=PG(variables_order); p && *p; p++) { switch(*p) { - case 'p': - case 'P': - if (!_gpc_flags[0] && !SG(headers_sent) && SG(request_info).request_method && !strcasecmp(SG(request_info).request_method, "POST")) { - sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC); /* POST Data */ - _gpc_flags[0] = 1; - } - break; case 'c': case 'C': if (!_gpc_flags[1]) { @@ -845,13 +932,7 @@ int php_hash_environment(TSRMLS_D) _gpc_flags[1] = 1; } break; - case 'g': - case 'G': - if (!_gpc_flags[2]) { - sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC); /* GET Data */ - _gpc_flags[2] = 1; - } - break; + case 'e': case 'E': if (!jit_initialization && !_gpc_flags[3]) { @@ -860,6 +941,7 @@ int php_hash_environment(TSRMLS_D) _gpc_flags[3] = 1; } break; + case 's': case 'S': if (!jit_initialization && !_gpc_flags[4]) { @@ -890,16 +972,57 @@ int php_hash_environment(TSRMLS_D) zend_ascii_hash_update(&EG(symbol_table), auto_global_records[i].name, auto_global_records[i].name_len, &PG(http_globals)[i], sizeof(zval *), NULL); } - /* Create _REQUEST */ - if (!jit_initialization) { - zend_auto_global_disable_jit("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC); - php_auto_globals_create_request("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC); - } - return SUCCESS; } /* }}} */ +static zend_bool php_auto_globals_decode_get(char *name, uint name_len TSRMLS_DC) +{ + sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC); /* GET Data */ + zend_ascii_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_GET], sizeof(zval *), NULL); + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_GET]); + return 0; +} + +static zend_bool php_auto_globals_decode_post(char *name, uint name_len TSRMLS_DC) +{ + if (SG(request_info).request_method && !strcasecmp(SG(request_info).request_method, "POST")) { + sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC); /* POST Data */ + zend_ascii_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_POST], sizeof(zval *), NULL); + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_POST]); + } + return 0; +} + +static zend_bool php_auto_globals_decode_files(char *name, uint name_len TSRMLS_DC) +{ + if (PG(http_globals)[TRACK_VARS_FILES]) { + zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_FILES]); + } + ALLOC_ZVAL(PG(http_globals)[TRACK_VARS_FILES]); + array_init(PG(http_globals)[TRACK_VARS_FILES]); + INIT_PZVAL(PG(http_globals)[TRACK_VARS_FILES]); + zend_ascii_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_FILES], sizeof(zval *), NULL); + Z_ADDREF_P(PG(http_globals)[TRACK_VARS_FILES]); + + if (SG(request_info).post_entry && + SG(request_info).post_entry->post_handler == rfc1867_post_handler) { + + if (SG(rfc1867_files_vars) == NULL) { + sapi_handle_post(NULL TSRMLS_DC); + } + if (SG(rfc1867_files_vars) != NULL) { + PG(request_decoding_error) = 0; + if (php_decode_raw_var_array(SG(rfc1867_files_vars), PG(http_globals)[TRACK_VARS_FILES] TSRMLS_CC) == FAILURE) { + zend_error(E_WARNING, "Failed to decode _FILES array"); + PG(request_decoding_error) = 1; + zend_hash_clean(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_FILES])); + } + } + } + return 0; +} + static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS_DC) { if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) { @@ -918,7 +1041,7 @@ static zend_bool php_auto_globals_create_server(char *name, uint name_len TSRMLS } } else { php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC); - } + } } } else { @@ -948,7 +1071,7 @@ static zend_bool php_auto_globals_create_env(char *name, uint name_len TSRMLS_DC zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_ENV]); } PG(http_globals)[TRACK_VARS_ENV] = env_vars; - + if (PG(variables_order) && (strchr(PG(variables_order),'E') || strchr(PG(variables_order),'e'))) { php_import_environment_variables(PG(http_globals)[TRACK_VARS_ENV] TSRMLS_CC); } @@ -980,6 +1103,7 @@ static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRML case 'g': case 'G': if (!_gpc_flags[0]) { + zend_u_is_auto_global_ex(IS_STRING, ZSTR("_GET"), sizeof("_GET")-1, 1, NULL TSRMLS_CC); php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC); _gpc_flags[0] = 1; } @@ -987,6 +1111,7 @@ static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRML case 'p': case 'P': if (!_gpc_flags[1]) { + zend_u_is_auto_global_ex(IS_STRING, ZSTR("_POST"), sizeof("_POST")-1, 1, NULL TSRMLS_CC); php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]) TSRMLS_CC); _gpc_flags[1] = 1; } @@ -1007,13 +1132,13 @@ static zend_bool php_auto_globals_create_request(char *name, uint name_len TSRML void php_startup_auto_globals(TSRMLS_D) { - zend_register_auto_global("_GET", sizeof("_GET")-1, NULL TSRMLS_CC); - zend_register_auto_global("_POST", sizeof("_POST")-1, NULL TSRMLS_CC); + zend_register_auto_global_ex("_GET", sizeof("_GET")-1, php_auto_globals_decode_get, 1 TSRMLS_CC); + zend_register_auto_global_ex("_POST", sizeof("_POST")-1, php_auto_globals_decode_post, 1 TSRMLS_CC); zend_register_auto_global("_COOKIE", sizeof("_COOKIE")-1, NULL TSRMLS_CC); zend_register_auto_global("_SERVER", sizeof("_SERVER")-1, php_auto_globals_create_server TSRMLS_CC); zend_register_auto_global("_ENV", sizeof("_ENV")-1, php_auto_globals_create_env TSRMLS_CC); - zend_register_auto_global("_REQUEST", sizeof("_REQUEST")-1, php_auto_globals_create_request TSRMLS_CC); - zend_register_auto_global("_FILES", sizeof("_FILES")-1, NULL TSRMLS_CC); + zend_register_auto_global_ex("_REQUEST", sizeof("_REQUEST")-1, php_auto_globals_create_request, 1 TSRMLS_CC); + zend_register_auto_global_ex("_FILES", sizeof("_FILES")-1, php_auto_globals_decode_files, 1 TSRMLS_CC); } /* diff --git a/main/php_variables.h b/main/php_variables.h index eea0cb041e..938d5b9697 100644 --- a/main/php_variables.h +++ b/main/php_variables.h @@ -39,10 +39,10 @@ void php_startup_auto_globals(TSRMLS_D); extern PHPAPI void (*php_import_environment_variables)(zval *array_ptr TSRMLS_DC); PHPAPI void php_register_variable(char *var, char *val, zval *track_vars_array TSRMLS_DC); /* binary-safe version */ -PHPAPI void php_register_variable_safe(char *var, char *val, int val_len, zval *track_vars_array TSRMLS_DC); +PHPAPI void php_register_variable_safe(zend_uchar type, zstr var, zstr strval, int str_len, zval *track_vars_array TSRMLS_DC); PHPAPI void php_register_variable_ex(char *var, zval *val, zval *track_vars_array TSRMLS_DC); -PHPAPI void php_u_register_variable_safe(UChar *var, UChar *strval, int str_len, zval *track_vars_array TSRMLS_DC); PHPAPI void php_u_register_variable_ex(UChar *var, zval *val, zval *track_vars_array TSRMLS_DC); +PHPAPI int php_register_variable_with_conv(UConverter *conv, char *var, int var_len, char *val, int val_len, zval *array_ptr, int input_type TSRMLS_DC); int php_hash_environment(TSRMLS_D); END_EXTERN_C() diff --git a/main/rfc1867.c b/main/rfc1867.c index 80a92d632a..18219cbdfd 100644 --- a/main/rfc1867.c +++ b/main/rfc1867.c @@ -41,7 +41,6 @@ PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void ** if (lbuf) efree(lbuf); \ if (abuf) efree(abuf); \ if (array_index) efree(array_index); \ - zend_hash_destroy(&PG(rfc1867_protected_variables)); \ zend_llist_destroy(&header); \ if (mbuff->boundary_next) efree(mbuff->boundary_next); \ if (mbuff->boundary) efree(mbuff->boundary); \ @@ -49,63 +48,6 @@ PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void ** if (mbuff) efree(mbuff); \ return; } -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) -#include "ext/mbstring/mbstring.h" - -static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC); - -void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr TSRMLS_DC) -{ - int i; - if (php_mb_encoding_translation(TSRMLS_C)) { - if (num_vars > 0 && - php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) { - php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC); - } - for (i=0; i<num_vars; i+=2){ - safe_php_register_variable(val_list[i], val_list[i+1], len_list[i+1], array_ptr, 0 TSRMLS_CC); - efree(val_list[i]); - efree(val_list[i+1]); - } - efree(val_list); - efree(len_list); - } -} - -void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc TSRMLS_DC) -{ - /* allow only even increments */ - if (inc & 1) { - inc++; - } - (*num_vars_max) += inc; - *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *)); - *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int)); -} - -void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int **plen_list, int *num_vars, int *num_vars_max TSRMLS_DC) -{ - char **val_list=*pval_list; - int *len_list=*plen_list; - - if (*num_vars>=*num_vars_max){ - php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max, - 16 TSRMLS_CC); - /* in case realloc relocated the buffer */ - val_list = *pval_list; - len_list = *plen_list; - } - - val_list[*num_vars] = (char *)estrdup(param); - len_list[*num_vars] = strlen(param); - (*num_vars)++; - val_list[*num_vars] = (char *)estrdup(value); - len_list[*num_vars] = strlen(value); - (*num_vars)++; -} - -#endif - /* The longest property name we use in an uploaded file array */ #define MAX_SIZE_OF_INDEX sizeof("[tmp_name]") @@ -134,214 +76,6 @@ void php_rfc1867_register_constants(TSRMLS_D) REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT); } -static void normalize_protected_variable(char *varname TSRMLS_DC) -{ - char *s=varname, *index=NULL, *indexend=NULL, *p; - - /* overjump leading space */ - while (*s == ' ') { - s++; - } - - /* and remove it */ - if (s != varname) { - memmove(varname, s, strlen(s)+1); - } - - for (p=varname; *p && *p != '['; p++) { - switch(*p) { - case ' ': - case '.': - *p='_'; - break; - } - } - - /* find index */ - index = strchr(varname, '['); - if (index) { - index++; - s=index; - } else { - return; - } - - /* done? */ - while (index) { - - while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { - index++; - } - indexend = strchr(index, ']'); - indexend = indexend ? indexend + 1 : index + strlen(index); - - if (s != index) { - memmove(s, index, strlen(index)+1); - s += indexend-index; - } else { - s = indexend; - } - - if (*s == '[') { - s++; - index = s; - } else { - index = NULL; - } - } - - *s = '\0'; -} - - -static void normalize_u_protected_variable(UChar *varname TSRMLS_DC) -{ - UChar *s=varname, *index=NULL, *indexend=NULL, *p; - - /* overjump leading space */ - while (*s == 0x20 /*' '*/) { - s++; - } - - /* and remove it */ - if (s != varname) { - u_memmove(varname, s, u_strlen(s)+1); - } - - for (p=varname; *p && *p != 0x5b /*'['*/; p++) { - switch(*p) { - case 0x20: /*' '*/ - case 0x2e: /*'.'*/ - *p=0x5f; /*'_'*/ - break; - } - } - - /* find index */ - index = u_strchr(varname, 0x5b /*'['*/); - if (index) { - index++; - s=index; - } else { - return; - } - - /* done? */ - while (index) { - - while (*index == 0x20 /*' '*/ || - *index == 0x0d /*'\r'*/ || - *index == 0x0a /*'\n'*/ || - *index == 0x09 /*'\t'*/) { - index++; - } - indexend = u_strchr(index, 0x5d /*']'*/); - indexend = indexend ? indexend + 1 : index + u_strlen(index); - - if (s != index) { - u_memmove(s, index, u_strlen(index)+1); - s += indexend-index; - } else { - s = indexend; - } - - if (*s == 0x5b /*'['*/) { - s++; - index = s; - } else { - index = NULL; - } - } - *s++ = 0; -} - -static void add_protected_variable(char *varname TSRMLS_DC) -{ - int dummy=1; - - normalize_protected_variable(varname TSRMLS_CC); - zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL); -} - - -static void add_u_protected_variable(UChar *varname TSRMLS_DC) -{ - int dummy=1; - - normalize_u_protected_variable(varname TSRMLS_CC); - zend_u_hash_add(&PG(rfc1867_protected_variables), IS_UNICODE, ZSTR(varname), u_strlen(varname)+1, &dummy, sizeof(int), NULL); -} - - -static zend_bool is_protected_variable(char *varname TSRMLS_DC) -{ - normalize_protected_variable(varname TSRMLS_CC); - return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1); -} - - -static zend_bool is_u_protected_variable(UChar *varname TSRMLS_DC) -{ - normalize_u_protected_variable(varname TSRMLS_CC); - return zend_u_hash_exists(&PG(rfc1867_protected_variables), IS_UNICODE, ZSTR(varname), u_strlen(varname)+1); -} - - -static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) -{ - if (override_protection || !is_protected_variable(var TSRMLS_CC)) { - php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC); - } -} - - -static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) -{ - if (override_protection || !is_protected_variable(var TSRMLS_CC)) { - php_register_variable_ex(var, val, track_vars_array TSRMLS_CC); - } -} - - -static void safe_u_php_register_variable(UChar *var, UChar *str_val, int str_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) -{ - if (override_protection || !is_u_protected_variable(var TSRMLS_CC)) { - php_u_register_variable_safe(var, str_val, str_len, track_vars_array TSRMLS_CC); - } -} - - -static void safe_u_php_register_variable_ex(UChar *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) -{ - if (override_protection || !is_u_protected_variable(var TSRMLS_CC)) { - php_u_register_variable_ex(var, val, track_vars_array TSRMLS_CC); - } -} - - -static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) -{ - safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC); -} - - -static void register_u_http_post_files_variable(UChar *strvar, UChar *val, int val_len, zval *http_post_files, zend_bool override_protection TSRMLS_DC) -{ - safe_u_php_register_variable(strvar, val, val_len, http_post_files, override_protection TSRMLS_CC); -} - - -static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) -{ - safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC); -} - - -static void register_u_http_post_files_variable_ex(UChar *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) -{ - safe_u_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC); -} - static int unlink_filename(char **filename TSRMLS_DC) { @@ -357,33 +91,6 @@ void destroy_uploaded_files_hash(TSRMLS_D) FREE_HASHTABLE(SG(rfc1867_uploaded_files)); } - -static inline UChar *php_ap_to_unicode(char *in, int32_t in_len, int32_t *out_len TSRMLS_DC) -{ - UErrorCode status = U_ZERO_ERROR; - UChar *buf; - int buf_len = 0; - UConverter *input_conv = UG(http_input_encoding_conv); - - if (!input_conv) { - input_conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); - } - - input_conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); - zend_string_to_unicode_ex(input_conv, &buf, &buf_len, in, in_len, &status); - if (U_SUCCESS(status)) { - if (out_len) - *out_len = buf_len; - return buf; - } else { - efree(buf); - if (out_len) - *out_len = 0; - return NULL; - } -} - - /* * Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. * @@ -662,44 +369,6 @@ static char *php_mime_get_hdr_value(zend_llist header, char *key) } -static UChar *php_u_ap_getword(UChar **line, UChar stop TSRMLS_DC) -{ - UChar *pos = *line, quote; - UChar *res; - - while (*pos && *pos != stop) { - - if ((quote = *pos) == '"' || quote == '\'') { - ++pos; - while (*pos && *pos != quote) { - if (*pos == '\\' && pos[1] && pos[1] == quote) { - pos += 2; - } else { - ++pos; - } - } - if (*pos) { - ++pos; - } - } else ++pos; - - } - if (*pos == '\0') { - res = eustrdup(*line); - *line += u_strlen(*line); - return res; - } - - res = eustrndup(*line, pos - *line); - - while (*pos == stop) { - ++pos; - } - - *line = pos; - return res; -} - static char *php_ap_getword(char **line, char stop) { @@ -740,24 +409,6 @@ static char *php_ap_getword(char **line, char stop) } -static UChar *substring_u_conf(UChar *start, int len, UChar quote TSRMLS_DC) -{ - UChar *result = eumalloc(len + 2); - UChar *resp = result; - int i; - - for (i = 0; i < len; ++i) { - if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) { - *resp++ = start[++i]; - } else { - *resp++ = start[i]; - } - } - - *resp++ = 0; - return result; -} - static char *substring_conf(char *start, int len, char quote TSRMLS_DC) { @@ -769,19 +420,7 @@ static char *substring_conf(char *start, int len, char quote TSRMLS_DC) if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) { *resp++ = start[++i]; } else { -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - if (php_mb_encoding_translation(TSRMLS_C)) { - size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC); - while (j-- > 0 && i < len) { - *resp++ = start[i++]; - } - --i; - } else { - *resp++ = start[i]; - } -#else *resp++ = start[i]; -#endif } } @@ -790,72 +429,10 @@ static char *substring_conf(char *start, int len, char quote TSRMLS_DC) } -static UChar *php_u_ap_getword_conf(UChar **line TSRMLS_DC) -{ - UChar *str = *line, *strend, *res, quote; - - while (*str && u_isspace(*str)) { - ++str; - } - - if (!*str) { - *line = str; - return USTR_MAKE(""); - } - - if ((quote = *str) == '"' || quote == '\'') { - strend = str + 1; -look_for_quote: - while (*strend && *strend != quote) { - if (*strend == '\\' && strend[1] && strend[1] == quote) { - strend += 2; - } else { - ++strend; - } - } - if (*strend && *strend == quote) { - UChar p = *(strend + 1); - if (p != '\r' && p != '\n' && p != '\0') { - strend++; - goto look_for_quote; - } - } - - res = substring_u_conf(str + 1, strend - str - 1, quote TSRMLS_CC); - - if (*strend == quote) { - ++strend; - } - - } else { - - strend = str; - while (*strend && !u_isspace(*strend)) { - ++strend; - } - res = substring_u_conf(str, strend - str, 0 TSRMLS_CC); - } - - while (*strend && u_isspace(*strend)) { - ++strend; - } - - *line = strend; - return res; -} - - static char *php_ap_getword_conf(char **line TSRMLS_DC) { char *str = *line, *strend, *res, quote; -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - if (php_mb_encoding_translation(TSRMLS_C)) { - int len=strlen(str); - php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC); - } -#endif - while (*str && isspace(*str)) { ++str; } @@ -1001,603 +578,39 @@ static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *le return out; } -static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_unicode) +static void register_raw_var_ex(char *var, zval *value, HashTable *array TSRMLS_DC) { - char *boundary, *boundary_end = NULL; - UChar *temp_filename=NULL, *array_index = NULL, *lbuf = NULL, *abuf = NULL; - UChar *start_arr = NULL, *s = NULL; - char *ascii_temp_filename = NULL; - int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0; - int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous; - zval *http_post_files=NULL; HashTable *uploaded_files=NULL; - multipart_buffer *mbuff; - zval *array_ptr = (zval *) arg; - FILE *fp; - zend_llist header; - void *event_extra_data = NULL; - UConverter *input_conv = UG(http_input_encoding_conv); - U_STRING_DECL(name_key, "name", 4); - U_STRING_DECL(filename_key, "filename", 8); - U_STRING_DECL(maxfilesize_key, "MAX_FILE_SIZE", 13); - static zend_bool did_string_init = FALSE; - int llen = 0; - - if (SG(request_info).content_length > SG(post_max_size)) { - sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size)); - return; - } - - /* Get the boundary */ - boundary = strstr(content_type_dup, "boundary"); - if (!boundary || !(boundary=strchr(boundary, '='))) { - sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data"); - return; - } - - boundary++; - boundary_len = strlen(boundary); - - if (boundary[0] == '"') { - boundary++; - boundary_end = strchr(boundary, '"'); - if (!boundary_end) { - sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data"); - return; - } - } else { - /* search for the end of the boundary */ - boundary_end = strchr(boundary, ','); - } - if (boundary_end) { - boundary_end[0] = '\0'; - boundary_len = boundary_end-boundary; - } - - /* Initialize the buffer */ - if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) { - sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer"); - return; - } - - /* Initialize $_FILES[] */ - zend_u_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0, 1); - - ALLOC_HASHTABLE(uploaded_files); - zend_u_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0, 1); - SG(rfc1867_uploaded_files) = uploaded_files; - - ALLOC_ZVAL(http_post_files); - array_init(http_post_files); - INIT_PZVAL(http_post_files); - PG(http_globals)[TRACK_VARS_FILES] = http_post_files; - - zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0); - - if (!did_string_init) { - U_STRING_INIT(name_key, "name", 4); - U_STRING_INIT(filename_key, "filename", 8); - U_STRING_INIT(maxfilesize_key, "MAX_FILE_SIZE", 13); - did_string_init = TRUE; - } - - if (!input_conv) { - input_conv = ZEND_U_CONVERTER(UG(output_encoding_conv)); - } - - if (php_rfc1867_callback != NULL) { - multipart_event_start event_start; - - event_start.content_length = SG(request_info).content_length; - if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) { - goto fileupload_done; - } - } - - while (!multipart_buffer_eof(mbuff TSRMLS_CC)) - { - char buff[FILLUNIT]; - char *cd=NULL; - size_t blen=0, wlen=0; - off_t offset; - UChar *param = NULL, *filename = NULL, *tmp = NULL; - int32_t param_len; - - zend_llist_clean(&header); - - if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) { - goto fileupload_done; - } - - if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) { - UChar *pair = NULL; - UChar *ucd = NULL, *ucd_start = NULL; - int32_t ucd_len; - int end=0; - - while (isspace(*cd)) { - ++cd; - } - - ucd_start = php_ap_to_unicode(cd, strlen(cd), &ucd_len TSRMLS_CC); - if (!ucd) { - /* UTODO error condition */ - } - ucd = ucd_start; - - while (*ucd && (pair = php_u_ap_getword(&ucd, 0x3b /*';'*/ TSRMLS_CC))) - { - UChar *key=NULL, *word = pair; - - while (u_isspace(*ucd)) { - ++ucd; - } - - if (u_strchr(pair, '=')) { - key = php_u_ap_getword(&pair, 0x3d /*'='*/ TSRMLS_CC); - - if (!u_strcasecmp(key, name_key, 0)) { - if (param) { - efree(param); - } - param = php_u_ap_getword_conf(&pair TSRMLS_CC); - } else if (!u_strcasecmp(key, filename_key, 0)) { - if (filename) { - efree(filename); - } - filename = php_u_ap_getword_conf(&pair TSRMLS_CC); - } - } - if (key) { - efree(key); - } - efree(word); - } - - efree(ucd_start); - - /* Normal form variable, safe to read all data into memory */ - if (!filename && param) { - UChar *u_val; - int32_t u_val_len; - unsigned int value_len; - UErrorCode status = U_ZERO_ERROR; - - char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC); - /* unsigned int new_val_len; Dummy variable */ - - if (value) { - /* UTODO use 'charset' parameter for conversion */ - zend_string_to_unicode_ex(input_conv, &u_val, &u_val_len, value, value_len, &status); - if (U_FAILURE(status)) { - /* UTODO set a user-accessible flag to indicate that conversion failed? */ - goto var_done; - } - } else { - u_val_len = 0; - u_val = USTR_MAKE(""); - } - - /* UTODO use input filtering */ - /* if (sapi_module.input_filter(PARSE_POST, param, &u_val, u_val_len, &new_val_len TSRMLS_CC)) { */ - if (php_rfc1867_callback != NULL) { - multipart_event_formdata event_formdata; - size_t newlength = (size_t) u_val_len; - - event_formdata.post_bytes_processed = SG(read_post_bytes); - event_formdata.name = ZSTR(param); - event_formdata.value = PZSTR(u_val); - event_formdata.length = (size_t) u_val_len; - event_formdata.newlength = &newlength; - if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) { - efree(param); - efree(value); - efree(u_val); - continue; - } - u_val_len = (int32_t) newlength; - } - - safe_u_php_register_variable(param, u_val, u_val_len, array_ptr, 0 TSRMLS_CC); - /* } else if (php_rfc1867_callback != NULL) { - multipart_event_formdata event_formdata; - - event_formdata.post_bytes_processed = SG(read_post_bytes); - event_formdata.name = ZSTR(param); - event_formdata.value = PZSTR(u_val); - event_formdata.length = u_val_len; - event_formdata.newlength = NULL; - php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC); - } */ - - if (!u_strcasecmp(param, maxfilesize_key, 0)) { - max_file_size = zend_u_strtol(u_val, NULL, 10); - } - -var_done: - efree(param); - efree(value); - efree(u_val); - continue; - } - - /* If file_uploads=off, skip the file part */ - if (!PG(file_uploads)) { - skip_upload = 1; - } - - /* Return with an error if the posted data is garbled */ - if (!param && !filename) { - sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled"); - goto fileupload_done; - } - - if (!param) { - is_anonymous = 1; - param = eumalloc(MAX_SIZE_ANONNAME); - u_snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++); - } else { - is_anonymous = 0; - } - param_len = u_strlen(param); - - /* New Rule: never repair potential malicious user input */ - if (!skip_upload) { - UChar32 c = 0; - int32_t ic, l_ic; - long l = 0; - - for (ic = 0; ic < param_len; ) { - l_ic = ic; - U16_NEXT(param, ic, param_len, c); - if (c == 0x5b /*'['*/) { - l++; - } else if (c == 0x5d /*']'*/) { - l--; - l_ic = ic; - U16_NEXT(param, ic, param_len, c); - if (ic < param_len && c != 0x5b /*'['*/) { - skip_upload = 1; - break; - } else { - /* go back so that the same character is retrieved again */ - ic = l_ic; - } - } - if (l < 0) { - skip_upload = 1; - break; - } - } - } - - total_bytes = cancel_upload = 0; - - if (!skip_upload) { - /* Handle file */ - fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &ascii_temp_filename TSRMLS_CC); - if (!fp) { - sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file"); - cancel_upload = UPLOAD_ERROR_E; - } - temp_filename = zend_ascii_to_unicode(ascii_temp_filename, strlen(ascii_temp_filename)+1 ZEND_FILE_LINE_CC); - } - - if (!skip_upload && php_rfc1867_callback != NULL) { - multipart_event_file_start event_file_start; - - event_file_start.post_bytes_processed = SG(read_post_bytes); - event_file_start.name = ZSTR(param); - event_file_start.filename = PZSTR(filename); - if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) { - if (ascii_temp_filename) { - if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ - fclose(fp); - unlink(ascii_temp_filename); - } - efree(ascii_temp_filename); - } - if (temp_filename) { - efree(temp_filename); - } - temp_filename = EMPTY_STR; - efree(param); - efree(filename); - continue; - } - } - - - if (skip_upload) { - efree(param); - efree(filename); - continue; - } - - if(u_strlen(filename) == 0) { -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "No file uploaded"); -#endif - cancel_upload = UPLOAD_ERROR_D; - } - - offset = 0; - end = 0; - while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC))) - { - if (php_rfc1867_callback != NULL) { - multipart_event_file_data event_file_data; - - event_file_data.post_bytes_processed = SG(read_post_bytes); - event_file_data.offset = offset; - event_file_data.data = buff; - event_file_data.length = blen; - event_file_data.newlength = &blen; - if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) { - cancel_upload = UPLOAD_ERROR_X; - continue; - } - } - - - if (PG(upload_max_filesize) > 0 && (total_bytes+blen) > PG(upload_max_filesize)) { -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%r=%r] not saved", PG(upload_max_filesize), param, filename); -#endif - cancel_upload = UPLOAD_ERROR_A; - } else if (max_file_size && ((total_bytes+blen) > max_file_size)) { -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%r=%r] not saved", max_file_size, param, filename); -#endif - cancel_upload = UPLOAD_ERROR_B; - } else if (blen > 0) { - wlen = fwrite(buff, 1, blen, fp); - - if (wlen == -1) { - /* write failed */ -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno)); -#endif - cancel_upload = UPLOAD_ERROR_F; - } else if (wlen < blen) { -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen); -#endif - cancel_upload = UPLOAD_ERROR_C; - } else { - total_bytes += wlen; - } - - offset += wlen; - } - } - if (fp) { /* may not be initialized if file could not be created */ - fclose(fp); - } - if (!cancel_upload && !end) { -#if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %v", u_strlen(filename) > 0 ? filename : EMPTY_STR); -#endif - cancel_upload = UPLOAD_ERROR_C; - } -#if DEBUG_FILE_UPLOAD - if(u_strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) { - sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%r=%r] not saved", param, filename); - cancel_upload = 5; - } -#endif - - if (php_rfc1867_callback != NULL) { - multipart_event_file_end event_file_end; - - event_file_end.post_bytes_processed = SG(read_post_bytes); - event_file_end.temp_filename = ZSTR(temp_filename); - event_file_end.cancel_upload = cancel_upload; - if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) { - cancel_upload = UPLOAD_ERROR_X; - } - } - - if (cancel_upload) { - if (temp_filename) { - if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ - unlink(ascii_temp_filename); - } - efree(ascii_temp_filename); - efree(temp_filename); - } - temp_filename = EMPTY_STR; - } else { - zend_u_hash_add(SG(rfc1867_uploaded_files), IS_UNICODE, ZSTR(temp_filename), u_strlen(temp_filename) + 1, &ascii_temp_filename, sizeof(char *), NULL); - } - - /* is_arr_upload is true when name of file upload field - * ends in [.*] - * start_arr is set to point to 1st [ - */ - is_arr_upload = (start_arr = u_strchr(param, 0x5b /*'['*/)) && (param[u_strlen(param)-1] == 0x5d /*']'*/); - - if (is_arr_upload) { - array_len = u_strlen(start_arr); - if (array_index) { - efree(array_index); - } - array_index = eustrndup(start_arr+1, array_len-2); - } - - /* Add $foo_name */ - if (lbuf) { - efree(lbuf); - } - llen = u_strlen(param) + MAX_SIZE_OF_INDEX + 1; - lbuf = eumalloc(llen); - - if (is_arr_upload) { - if (abuf) efree(abuf); - abuf = eustrndup(param, u_strlen(param)-array_len); - u_snprintf(lbuf, llen, "%S_name[%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S_name", param); - } - - /* The \ check should technically be needed for win32 systems only where - * it is a valid path separator. However, IE in all its wisdom always sends - * the full path of the file on the user's filesystem, which means that unless - * the user does basename() they get a bogus file name. Until IE's user base drops - * to nill or problem is fixed this code must remain enabled for all systems. - */ - s = u_strrchr(filename, '\\'); - if ((tmp = u_strrchr(filename, 0x2f /*'/'*/)) > s) { - s = tmp; - } - - if (!is_anonymous) { - if (s && s > filename) { - safe_u_php_register_variable(lbuf, s+1, u_strlen(s+1), NULL, 0 TSRMLS_CC); - } else { - safe_u_php_register_variable(lbuf, filename, u_strlen(filename), NULL, 0 TSRMLS_CC); - } - } - - /* Add $foo[name] */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S[name][%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S[name]", param); - } - if (s && s > filename) { - register_u_http_post_files_variable(lbuf, s+1, u_strlen(s+1), http_post_files, 0 TSRMLS_CC); - } else { - register_u_http_post_files_variable(lbuf, filename, u_strlen(filename), http_post_files, 0 TSRMLS_CC); - } - efree(filename); - s = NULL; - - /* Possible Content-Type: */ - if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) { - ucd = ecalloc(1, UBYTES(1)); - ucd_len = 0; - } else { - ucd = php_ap_to_unicode(cd, strlen(cd), &ucd_len TSRMLS_CC); - if (!ucd) { - /* UTODO error condition */ - } - /* fix for Opera 6.01 */ - s = u_strchr(ucd, 0x3b /*';'*/); - if (s != NULL) { - *s = 0; - ucd_len = u_strlen(ucd); - } - } - - /* Add $foo_type */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S_type[%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S_type", param); - } - if (!is_anonymous) { - safe_u_php_register_variable(lbuf, ucd, ucd_len, NULL, 0 TSRMLS_CC); - } - - /* Add $foo[type] */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S[type][%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S[type]", param); - } - register_u_http_post_files_variable(lbuf, ucd, ucd_len, http_post_files, 0 TSRMLS_CC); - - efree(ucd); - s = EMPTY_STR; - - /* Initialize variables */ - add_u_protected_variable(param TSRMLS_CC); - - /* if param is of form xxx[.*] this will cut it to xxx */ - if (!is_anonymous) { - safe_u_php_register_variable(param, temp_filename, u_strlen(temp_filename), NULL, 1 TSRMLS_CC); - } - - /* Add $foo[tmp_name] */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S[tmp_name][%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S[tmp_name]", param); - } - add_u_protected_variable(lbuf TSRMLS_CC); - register_u_http_post_files_variable(lbuf, temp_filename, u_strlen(temp_filename), http_post_files, 1 TSRMLS_CC); - if (!cancel_upload) { - efree(temp_filename); - } - - { - zval file_size, error_type; - - error_type.value.lval = cancel_upload; - error_type.type = IS_LONG; - - /* Add $foo[error] */ - if (cancel_upload) { - file_size.value.lval = 0; - file_size.type = IS_LONG; - } else { - file_size.value.lval = total_bytes; - file_size.type = IS_LONG; - } - - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S[error][%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S[error]", param); - } - register_u_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC); - - /* Add $foo_size */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S_size[%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S_size", param); - } - if (!is_anonymous) { - safe_u_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC); - } + zend_hash_update(array, var, strlen(var)+1, &value, sizeof(zval *), NULL TSRMLS_CC); +} - /* Add $foo[size] */ - if (is_arr_upload) { - u_snprintf(lbuf, llen, "%S[size][%S]", abuf, array_index); - } else { - u_snprintf(lbuf, llen, "%S[size]", param); - } - register_u_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC); - } - efree(param); - } - } +static void register_raw_var(char *var, char *str, int str_len, HashTable *array TSRMLS_DC) +{ + zval *new_entry; + assert(str != NULL); -fileupload_done: - if (php_rfc1867_callback != NULL) { - multipart_event_end event_end; - - event_end.post_bytes_processed = SG(read_post_bytes); - php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC); - } + /* Prepare value */ + MAKE_STD_ZVAL(new_entry); + Z_STRLEN_P(new_entry) = str_len; + Z_STRVAL_P(new_entry) = estrndup(str, Z_STRLEN_P(new_entry)); + Z_TYPE_P(new_entry) = IS_STRING; - SAFE_RETURN; + register_raw_var_ex(var, new_entry, array TSRMLS_DC); } -static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_legacy) +/* + * The combined READER/HANDLER + * + */ + +SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) { char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL; char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL; int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0; int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous; - zval *http_post_files=NULL; HashTable *uploaded_files=NULL; -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL; - char **val_list = NULL; -#endif + HashTable *uploaded_files=NULL; + HashTable *post_vars, *files_vars; multipart_buffer *mbuff; - zval *array_ptr = (zval *) arg; int fd=-1; zend_llist header; void *event_extra_data = NULL; @@ -1640,24 +653,18 @@ static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_legacy) return; } - /* Initialize $_FILES[] */ - zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0); - ALLOC_HASHTABLE(uploaded_files); zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0); SG(rfc1867_uploaded_files) = uploaded_files; - ALLOC_ZVAL(http_post_files); - array_init(http_post_files); - INIT_PZVAL(http_post_files); - PG(http_globals)[TRACK_VARS_FILES] = http_post_files; + ALLOC_HASHTABLE(post_vars); + zend_hash_init(post_vars, 5, NULL, ZVAL_PTR_DTOR, 0); + SG(rfc1867_vars) = post_vars; + + ALLOC_HASHTABLE(files_vars); + zend_hash_init(files_vars, 5, NULL, ZVAL_PTR_DTOR, 0); + SG(rfc1867_files_vars) = files_vars; -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - if (php_mb_encoding_translation(TSRMLS_C)) { - val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *)); - len_list = (int *)ecalloc(num_vars_max+2, sizeof(int)); - } -#endif zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0); if (php_rfc1867_callback != NULL) { @@ -1724,41 +731,15 @@ static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_legacy) if (!filename && param) { unsigned int value_len; char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC); - unsigned int new_val_len; /* Dummy variable */ if (!value) { value = estrdup(""); + value_len = 0; } - if (sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) { - if (php_rfc1867_callback != NULL) { - multipart_event_formdata event_formdata; - size_t newlength = 0; - - event_formdata.post_bytes_processed = SG(read_post_bytes); - event_formdata.name = ZSTR(param); - event_formdata.value = PZSTR(value); - event_formdata.length = new_val_len; - event_formdata.newlength = &newlength; - if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) { - efree(param); - efree(value); - continue; - } - new_val_len = newlength; - } + register_raw_var(param, value, value_len, post_vars TSRMLS_DC); -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - if (php_mb_encoding_translation(TSRMLS_C)) { - php_mb_gpc_stack_variable(param, value, &val_list, &len_list, - &num_vars, &num_vars_max TSRMLS_CC); - } else { - safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC); - } -#else - safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC); -#endif - } else if (php_rfc1867_callback != NULL) { + if (php_rfc1867_callback != NULL) { multipart_event_formdata event_formdata; event_formdata.post_bytes_processed = SG(read_post_bytes); @@ -1976,35 +957,6 @@ static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_legacy) llen = strlen(param) + MAX_SIZE_OF_INDEX + 1; lbuf = (char *) emalloc(llen); - if (is_arr_upload) { - if (abuf) efree(abuf); - abuf = estrndup(param, strlen(param)-array_len); - snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index); - } else { - snprintf(lbuf, llen, "%s_name", param); - } - -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - if (php_mb_encoding_translation(TSRMLS_C)) { - if (num_vars>=num_vars_max){ - php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max, - 1 TSRMLS_CC); - } - val_list[num_vars] = filename; - len_list[num_vars] = strlen(filename); - num_vars++; - if(php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) { - str_len = strlen(filename); - php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC); - } - s = php_mb_strrchr(filename, '\\' TSRMLS_CC); - if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) { - s = tmp; - } - num_vars--; - goto filedone; - } -#endif /* The \ check should technically be needed for win32 systems only where * it is a valid path separator. However, IE in all it's wisdom always sends * the full path of the file on the user's filesystem, which means that unless @@ -2016,18 +968,6 @@ static SAPI_POST_HANDLER_FUNC(rfc1867_post_handler_legacy) s = tmp; } -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) -filedone: -#endif - - if (!is_anonymous) { - if (s && s > filename) { - safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC); - } else { - safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC); - } - } - /* Add $foo[name] */ if (is_arr_upload) { snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index); @@ -2035,9 +975,9 @@ filedone: snprintf(lbuf, llen, "%s[name]", param); } if (s && s > filename) { - register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC); + register_raw_var(lbuf, s+1, strlen(s+1), files_vars TSRMLS_CC); } else { - register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC); + register_raw_var(lbuf, filename, strlen(filename), files_vars TSRMLS_CC); } efree(filename); s = NULL; @@ -2053,23 +993,13 @@ filedone: } } - /* Add $foo_type */ - if (is_arr_upload) { - snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index); - } else { - snprintf(lbuf, llen, "%s_type", param); - } - if (!is_anonymous) { - safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC); - } - /* Add $foo[type] */ if (is_arr_upload) { snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index); } else { snprintf(lbuf, llen, "%s[type]", param); } - register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC); + register_raw_var(lbuf, cd, strlen(cd), files_vars TSRMLS_CC); /* Restore Content-Type Header */ if (s != NULL) { @@ -2077,36 +1007,27 @@ filedone: } s = ""; - /* Initialize variables */ - add_protected_variable(param TSRMLS_CC); - - /* if param is of form xxx[.*] this will cut it to xxx */ - if (!is_anonymous) { - safe_php_register_variable(param, temp_filename, strlen(temp_filename), NULL, 1 TSRMLS_CC); - } - /* Add $foo[tmp_name] */ if (is_arr_upload) { snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index); } else { snprintf(lbuf, llen, "%s[tmp_name]", param); } - add_protected_variable(lbuf TSRMLS_CC); - register_http_post_files_variable(lbuf, temp_filename, http_post_files, 1 TSRMLS_CC); + register_raw_var(lbuf, temp_filename, strlen(temp_filename), files_vars TSRMLS_CC); { - zval file_size, error_type; + zval *file_size, *error_type; + + MAKE_STD_ZVAL(error_type); + ZVAL_LONG(error_type, cancel_upload); - error_type.value.lval = cancel_upload; - error_type.type = IS_LONG; + MAKE_STD_ZVAL(file_size); /* Add $foo[error] */ if (cancel_upload) { - file_size.value.lval = 0; - file_size.type = IS_LONG; + ZVAL_LONG(file_size, 0); } else { - file_size.value.lval = total_bytes; - file_size.type = IS_LONG; + ZVAL_LONG(file_size, total_bytes); } if (is_arr_upload) { @@ -2114,17 +1035,7 @@ filedone: } else { snprintf(lbuf, llen, "%s[error]", param); } - register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC); - - /* Add $foo_size */ - if (is_arr_upload) { - snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index); - } else { - snprintf(lbuf, llen, "%s_size", param); - } - if (!is_anonymous) { - safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC); - } + register_raw_var_ex(lbuf, error_type, files_vars TSRMLS_CC); /* Add $foo[size] */ if (is_arr_upload) { @@ -2132,16 +1043,13 @@ filedone: } else { snprintf(lbuf, llen, "%s[size]", param); } - register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC); + register_raw_var_ex(lbuf, file_size, files_vars TSRMLS_CC); } efree(param); } } fileupload_done: -#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) - php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); -#endif if (php_rfc1867_callback != NULL) { multipart_event_end event_end; @@ -2154,16 +1062,6 @@ fileupload_done: } /* - * The combined READER/HANDLER - * - */ - -SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) -{ - rfc1867_post_handler_unicode(content_type_dup, arg TSRMLS_CC); -} - -/* * Local variables: * tab-width: 4 * c-basic-offset: 4 diff --git a/sapi/apache/mod_php.c b/sapi/apache/mod_php.c index b1b8153cf9..34c053042d 100644 --- a/sapi/apache/mod_php.c +++ b/sapi/apache/mod_php.c @@ -257,6 +257,7 @@ static void sapi_apache_register_server_variables(zval *track_vars_array TSRMLS_ zval **path_translated; HashTable *symbol_table; unsigned int new_val_len; + UConveter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); for (i = 0; i < arr->nelts; i++) { char *val; @@ -268,8 +269,9 @@ static void sapi_apache_register_server_variables(zval *track_vars_array TSRMLS_ val = ""; } val_len = strlen(val); - if (sapi_module.input_filter(PARSE_SERVER, elts[i].key, &val, val_len, &new_val_len TSRMLS_CC)) { - php_register_variable_safe(elts[i].key, val, new_val_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, elts[i].key, strlen(elts[i].key), val, + val_len, track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } } diff --git a/sapi/apache2filter/sapi_apache2.c b/sapi/apache2filter/sapi_apache2.c index 609bf0c2a2..9e639fe8e5 100644 --- a/sapi/apache2filter/sapi_apache2.c +++ b/sapi/apache2filter/sapi_apache2.c @@ -234,19 +234,21 @@ php_apache_sapi_register_variables(zval *track_vars_array TSRMLS_DC) const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env); char *key, *val; int new_val_len; + UConverter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); APR_ARRAY_FOREACH_OPEN(arr, key, val) if (!val) { val = ""; } - if (sapi_module.input_filter(PARSE_SERVER, key, &val, strlen(val), &new_val_len TSRMLS_CC)) { - php_register_variable_safe(key, val, new_val_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, key, strlen(key), val, strlen(val), + track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } APR_ARRAY_FOREACH_CLOSE() - php_register_variable("PHP_SELF", ctx->r->uri, track_vars_array TSRMLS_CC); - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &ctx->r->uri, strlen(ctx->r->uri), &new_val_len TSRMLS_CC)) { - php_register_variable_safe("PHP_SELF", ctx->r->uri, new_val_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, ZEND_STRL("PHP_SELF"), ctx->r->uri, + strlen(ctx->r->uri), track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } } diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 49fa7a5d00..6896af5052 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -250,19 +250,21 @@ php_apache_sapi_register_variables(zval *track_vars_array TSRMLS_DC) php_struct *ctx = SG(server_context); const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env); char *key, *val; - int new_val_len; + UConverter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); APR_ARRAY_FOREACH_OPEN(arr, key, val) if (!val) { val = ""; } - if (sapi_module.input_filter(PARSE_SERVER, key, &val, strlen(val), &new_val_len TSRMLS_CC)) { - php_register_variable_safe(key, val, new_val_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, key, strlen(key), val, strlen(val), + track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } APR_ARRAY_FOREACH_CLOSE() - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &ctx->r->uri, strlen(ctx->r->uri), &new_val_len TSRMLS_CC)) { - php_register_variable_safe("PHP_SELF", ctx->r->uri, new_val_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, ZEND_STRL("PHP_SELF"), ctx->r->uri, + strlen(ctx->r->uri), track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } } @@ -491,7 +493,7 @@ static void php_apache_ini_dtor(request_rec *r, request_rec *p TSRMLS_DC) typedef struct { HashTable config; } php_conf_rec; - char *str; + zstr str; uint str_len; php_conf_rec *c = ap_get_module_config(r->per_dir_config, &php6_module); @@ -499,7 +501,7 @@ typedef struct { zend_hash_get_current_key_ex(&c->config, &str, &str_len, NULL, 0, NULL) == HASH_KEY_IS_STRING; zend_hash_move_forward(&c->config) ) { - zend_restore_ini_entry(str, str_len, ZEND_INI_STAGE_SHUTDOWN); + zend_restore_ini_entry(str.s, str_len, ZEND_INI_STAGE_SHUTDOWN); } } if (p) { diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 64e29a99b0..af96789542 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -606,6 +606,7 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC) char **val; ulong idx; int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER; + UConverter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); for (zend_hash_internal_pointer_reset_ex(request->env, &pos); zend_hash_get_current_key_ex(request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING && @@ -614,8 +615,9 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC) ) { unsigned int new_val_len; - if (sapi_module.input_filter(filter_arg, var.s, val, strlen(*val), &new_val_len TSRMLS_CC)) { - php_register_variable_safe(var.s, *val, new_val_len, array_ptr TSRMLS_CC); + if (php_register_variable_with_conv(conv, var.s, strlen(var.s), val, strlen(*val), + array_ptr, filter_arg TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode %s array entry", (filter_arg == PARSE_ENV?"_ENV":"_SERVER")); } } } @@ -625,6 +627,7 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC) { unsigned int php_self_len; char *php_self; + UConverter *conv = ZEND_U_CONVERTER(UG(runtime_encoding_conv)); /* In CGI mode, we consider the environment to be a part of the server * variables @@ -648,15 +651,17 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC) } /* Build the special-case PHP_SELF variable for the CGI version */ - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) { - php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, ZEND_STRL("PHP_SELF"), php_self, + php_self_len, track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } efree(php_self); } else { php_self = SG(request_info).request_uri ? SG(request_info).request_uri : ""; php_self_len = strlen(php_self); - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) { - php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC); + if (php_register_variable_with_conv(conv, ZEND_STRL("PHP_SELF"), php_self, + php_self_len, track_vars_array, PARSE_SERVER TSRMLS_CC) == FAILURE) { + php_error(E_WARNING, "Failed to decode _SERVER array entry"); } } } diff --git a/unicode-todo.txt b/unicode-todo.txt index 8a664a679d..c58df1ccef 100644 --- a/unicode-todo.txt +++ b/unicode-todo.txt @@ -40,3 +40,6 @@ * See if ext/pcre can ba adjusted to allow operations on pure binary strings. Ideal mode would be: convert all IS_UNICODE to UTF-8, assume that binary strings with /u modifier are UTF-8, otherwise it's pure binary. + +* Optimize for zend_string_to_unicode() and zend_unicode_to_string() for + 0-length strings. |
