34#ifndef DEBUG_FILE_UPLOAD
35# define DEBUG_FILE_UPLOAD 0
38static int dummy_encoding_translation(
void)
55static void safe_php_register_variable(
char *var,
char *
strval,
size_t val_len,
zval *track_vars_array,
bool override_protection);
58#define MAX_SIZE_OF_INDEX sizeof("[full_path]")
61#define MAX_SIZE_ANONNAME 33
63static void normalize_protected_variable(
char *varname)
65 char *
s = varname, *index =
NULL, *indexend =
NULL, *
p;
77 for (
p = varname; *
p && *
p !=
'[';
p++) {
87 index =
strchr(varname,
'[');
97 while (*index ==
' ' || *index ==
'\r' || *index ==
'\n' || *index==
'\t') {
100 indexend =
strchr(index,
']');
101 indexend = indexend ? indexend + 1 : index +
strlen(index);
121static void add_protected_variable(
char *varname)
123 normalize_protected_variable(varname);
128static bool is_protected_variable(
char *varname)
130 normalize_protected_variable(varname);
131 return zend_hash_str_exists(&
PG(rfc1867_protected_variables), varname,
strlen(varname));
135static void safe_php_register_variable(
char *var,
char *
strval,
size_t val_len,
zval *track_vars_array,
bool override_protection)
137 if (override_protection || !is_protected_variable(var)) {
143static void safe_php_register_variable_ex(
char *var,
zval *
val,
zval *track_vars_array,
bool override_protection)
145 if (override_protection || !is_protected_variable(var)) {
151static void register_http_post_files_variable(
char *strvar,
char *
val,
zval *http_post_files,
bool override_protection)
153 safe_php_register_variable(strvar,
val,
strlen(
val), http_post_files, override_protection);
157static void register_http_post_files_variable_ex(
char *var,
zval *
val,
zval *http_post_files,
bool override_protection)
159 safe_php_register_variable_ex(var,
val, http_post_files, override_protection);
163static void free_filename(
zval *el) {
178 SG(rfc1867_uploaded_files) =
NULL;
184#define FILLUNIT (1024 * 5)
215 int bytes_to_read, total_read = 0, actual_read = 0;
228 while (bytes_to_read > 0) {
235 if (actual_read > 0) {
237 SG(read_post_bytes) += actual_read;
238 total_read += actual_read;
239 bytes_to_read -= actual_read;
255static multipart_buffer *multipart_buffer_new(
char *boundary,
int boundary_len)
259 int minsize = boundary_len + 6;
272 if (php_rfc1867_encoding_translation()) {
332 char*
ptr = next_line(self);
336 ptr = next_line(self);
359 while( (
line = get_line(self)) )
380 if (!find_boundary(self, self->
boundary)) {
386 while ((
line = get_line(self)) &&
line[0] !=
'\0') {
390 if (php_rfc1867_encoding_translation()) {
395 if (!isspace(
line[0])) {
400 if (buf_value.
c &&
key) {
402 smart_string_0(&buf_value);
404 entry.
value = buf_value.
c;
415 }
else if (buf_value.
c) {
422 if (buf_value.
c &&
key) {
424 smart_string_0(&buf_value);
426 entry.
value = buf_value.
c;
441 entry = zend_llist_get_first(&
header);
446 entry = zend_llist_get_next(&
header);
457 while (*
pos && *
pos != stop) {
458 if ((quote = *
pos) ==
'"' || quote ==
'\'') {
460 while (*
pos && *
pos != quote) {
461 if (*
pos ==
'\\' &&
pos[1] &&
pos[1] == quote) {
480 while (*
pos == stop) {
488static char *substring_conf(
char *
start,
int len,
char quote)
494 for (i = 0; i <
len &&
start[i] != quote; ++i) {
495 if (
start[i] ==
'\\' && (
start[i + 1] ==
'\\' || (quote &&
start[i + 1] == quote))) {
496 *resp++ =
start[++i];
508 while (*str && isspace(*str)) {
516 if (*str ==
'"' || *str ==
'\'') {
520 return substring_conf(str, (
int)
strlen(str), quote);
524 while (*strend && !isspace(*strend)) {
527 return substring_conf(str, strend - str, 0);
556static void *php_ap_memstr(
char *haystack,
int haystacklen,
char *needle,
int needlen,
int partial)
558 int len = haystacklen;
559 char *
ptr = haystack;
562 while( (
ptr = memchr(
ptr, needle[0],
len)) ) {
565 len = haystacklen - (
ptr - (
char *)haystack);
568 if (memcmp(needle,
ptr, needlen <
len ? needlen :
len) == 0 && (partial ||
len >= needlen)) {
610 if (bound &&
len > 0 &&
buf[
len-1] ==
'\r') {
629 size_t total_bytes=0, read_bytes=0;
631 while((read_bytes = multipart_buffer_read(self,
buf,
sizeof(
buf),
NULL))) {
634 total_bytes += read_bytes;
638 out[total_bytes] =
'\0';
653 char *boundary, *
s =
NULL, *boundary_end =
NULL, *start_arr =
NULL, *array_index =
NULL;
656 int boundary_len = 0, cancel_upload = 0, is_arr_upload = 0;
657 size_t array_len = 0;
658 int64_t total_bytes = 0, max_file_size = 0;
659 int skip_upload = 0, anonymous_index = 0;
663 bool throw_exceptions =
SG(request_parse_body_context).throw_exceptions;
666 void *event_extra_data =
NULL;
667 unsigned int llen = 0;
679#define EMIT_WARNING_OR_ERROR(...) do { \
680 if (throw_exceptions) { \
681 zend_throw_exception_ex(zend_ce_request_parse_body_exception, 0, __VA_ARGS__); \
683 php_error_docref(NULL, E_WARNING, __VA_ARGS__); \
688 getword = php_rfc1867_getword;
689 getword_conf = php_rfc1867_getword_conf;
690 _basename = php_rfc1867_basename;
692 getword = php_ap_getword;
693 getword_conf = php_ap_getword_conf;
694 _basename = php_ap_basename;
697 if (post_max_size > 0 &&
SG(request_info).content_length > post_max_size) {
702 if (body_parts_cnt < 0) {
703 body_parts_cnt = max_input_vars + upload_cnt;
705 int body_parts_limit = body_parts_cnt;
708 boundary =
strstr(content_type_dup,
"boundary");
710 int content_type_len = (int)
strlen(content_type_dup);
711 char *content_type_lcase =
estrndup(content_type_dup, content_type_len);
714 boundary =
strstr(content_type_lcase,
"boundary");
716 boundary = content_type_dup + (boundary - content_type_lcase);
718 efree(content_type_lcase);
721 if (!boundary || !(boundary =
strchr(boundary,
'='))) {
727 boundary_len = (int)
strlen(boundary);
729 if (boundary[0] ==
'"') {
731 boundary_end =
strchr(boundary,
'"');
738 boundary_end =
strpbrk(boundary,
",;");
741 boundary_end[0] =
'\0';
742 boundary_len = boundary_end-boundary;
753 mbuff = multipart_buffer_new(boundary, boundary_len);
760 SG(rfc1867_uploaded_files) = uploaded_files;
774 goto fileupload_done;
778 while (!multipart_buffer_eof(mbuff))
782 size_t blen = 0, wlen = 0;
787 if (!multipart_buffer_headers(mbuff, &
header)) {
788 goto fileupload_done;
791 if ((cd = php_mime_get_hdr_value(
header,
"Content-Disposition"))) {
795 if (--body_parts_cnt < 0) {
796 EMIT_WARNING_OR_ERROR(
"Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit);
797 goto fileupload_done;
800 while (isspace(*cd)) {
806 char *
key =
NULL, *word = pair;
808 while (isspace(*cd)) {
821 unsigned char *new_param;
822 size_t new_param_len;
825 param = (
char *)new_param;
834 unsigned char *new_filename;
835 size_t new_filename_len;
838 filename = (
char *)new_filename;
850 if (!filename && param) {
852 char *
value = multipart_buffer_read_body(mbuff, &value_len);
861 unsigned char *new_value;
862 size_t new_value_len;
865 value = (
char *)new_value;
866 value_len = new_value_len;
873 size_t newlength = new_val_len;
876 event_formdata.
name = param;
878 event_formdata.
length = new_val_len;
885 new_val_len = newlength;
887 safe_php_register_variable(param,
value, new_val_len, array_ptr, 0);
889 if (
count == max_input_vars + 1) {
897 event_formdata.
name = param;
899 event_formdata.
length = value_len;
915 if (!
PG(file_uploads)) {
917 }
else if (upload_cnt <= 0) {
919 if (upload_cnt == 0) {
926 if (!param && !filename) {
928 goto fileupload_done;
944 }
else if (*tmp ==
']') {
946 if (tmp[1] && tmp[1] !=
'[') {
963 total_bytes = cancel_upload = 0;
964 temp_filename =
NULL;
971 event_file_start.
name = param;
972 event_file_start.
filename = &filename;
974 temp_filename =
NULL;
987 if (filename[0] ==
'\0') {
997 if (!cancel_upload) {
999 blen = multipart_buffer_read(mbuff, buff,
sizeof(buff), &
end);
1000#if DEBUG_FILE_UPLOAD
1015 while (!cancel_upload && (blen > 0))
1022 event_file_data.
data = buff;
1023 event_file_data.
length = blen;
1031 if (upload_max_filesize > 0 && (
zend_long)(total_bytes+blen) > upload_max_filesize) {
1032#if DEBUG_FILE_UPLOAD
1033 sapi_module.sapi_error(
E_NOTICE,
"upload_max_filesize of " ZEND_LONG_FMT " bytes exceeded - file [%s=%s] not saved", upload_max_filesize, param, filename);
1036 }
else if (max_file_size && ((
zend_long)(total_bytes+blen) > max_file_size)) {
1037#if DEBUG_FILE_UPLOAD
1038 sapi_module.sapi_error(
E_NOTICE,
"MAX_FILE_SIZE of %" PRId64
" bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
1041 }
else if (blen > 0) {
1043 wlen = write(
fd, buff, (
unsigned int)blen);
1045 wlen = write(
fd, buff, blen);
1048 if (wlen == (
size_t)-1) {
1050#if DEBUG_FILE_UPLOAD
1054 }
else if (wlen < blen) {
1055#if DEBUG_FILE_UPLOAD
1056 sapi_module.sapi_error(
E_NOTICE,
"Only %zd bytes were written, expected to write %zd", wlen, blen);
1060 total_bytes += wlen;
1066 blen = multipart_buffer_read(mbuff, buff,
sizeof(buff), &
end);
1073 if (!cancel_upload && !
end) {
1074#if DEBUG_FILE_UPLOAD
1075 sapi_module.sapi_error(
E_NOTICE,
"Missing mime boundary at the end of the data for file %s", filename[0] !=
'\0' ? filename :
"");
1079#if DEBUG_FILE_UPLOAD
1080 if (filename[0] !=
'\0' && total_bytes == 0 && !cancel_upload) {
1096 if (cancel_upload) {
1097 if (temp_filename) {
1103 temp_filename =
NULL;
1105 zend_hash_add_ptr(
SG(rfc1867_uploaded_files), temp_filename, temp_filename);
1111 is_arr_upload = (start_arr =
strchr(param,
'[')) && (param[
strlen(param)-1] ==
']');
1113 if (is_arr_upload) {
1114 array_len =
strlen(start_arr);
1118 array_index =
estrndup(start_arr + 1, array_len - 2);
1123 llen = (int)
strlen(param);
1128 if (is_arr_upload) {
1129 if (abuf)
efree(abuf);
1131 snprintf(lbuf, llen,
"%s_name[%s]", abuf, array_index);
1133 snprintf(lbuf, llen,
"%s_name", param);
1147 if (is_arr_upload) {
1148 snprintf(lbuf, llen,
"%s[name][%s]", abuf, array_index);
1150 snprintf(lbuf, llen,
"%s[name]", param);
1159 if (is_arr_upload) {
1160 snprintf(lbuf, llen,
"%s[full_path][%s]", abuf, array_index);
1162 snprintf(lbuf, llen,
"%s[full_path]", param);
1164 register_http_post_files_variable(lbuf, filename, &
PG(http_globals)[
TRACK_VARS_FILES], 0);
1168 if (cancel_upload || !(cd = php_mime_get_hdr_value(
header,
"Content-Type"))) {
1179 if (is_arr_upload) {
1180 snprintf(lbuf, llen,
"%s[type][%s]", abuf, array_index);
1182 snprintf(lbuf, llen,
"%s[type]", param);
1198 add_protected_variable(param);
1201 if (is_arr_upload) {
1202 snprintf(lbuf, llen,
"%s[tmp_name][%s]", abuf, array_index);
1204 snprintf(lbuf, llen,
"%s[tmp_name]", param);
1206 add_protected_variable(lbuf);
1207 if (temp_filename) {
1212 register_http_post_files_variable_ex(lbuf, &zfilename, &
PG(http_globals)[
TRACK_VARS_FILES], 1);
1216 zval file_size, error_type;
1217 int size_overflow = 0;
1218 char file_size_buf[65];
1223 if (cancel_upload) {
1228 if (_i64toa_s(total_bytes, file_size_buf, 65, 10)) {
1229 file_size_buf[0] =
'0';
1230 file_size_buf[1] =
'\0';
1234 int __len =
snprintf(file_size_buf, 65,
"%" PRId64, total_bytes);
1235 file_size_buf[__len] =
'\0';
1245 if (is_arr_upload) {
1246 snprintf(lbuf, llen,
"%s[error][%s]", abuf, array_index);
1248 snprintf(lbuf, llen,
"%s[error]", param);
1250 register_http_post_files_variable_ex(lbuf, &error_type, &
PG(http_globals)[
TRACK_VARS_FILES], 0);
1253 if (is_arr_upload) {
1254 snprintf(lbuf, llen,
"%s[size][%s]", abuf, array_index);
1256 snprintf(lbuf, llen,
"%s[size]", param);
1258 if (size_overflow) {
1261 register_http_post_files_variable_ex(lbuf, &file_size, &
PG(http_globals)[
TRACK_VARS_FILES], size_overflow);
1275 if (lbuf)
efree(lbuf);
1276 if (abuf)
efree(abuf);
1277 if (array_index)
efree(array_index);
1283 if (mbuff)
efree(mbuff);
1285#undef EMIT_WARNING_OR_ERROR
1298 php_rfc1867_get_detect_order = get_detect_order;
1299 php_rfc1867_set_input_encoding = set_input_encoding;
1300 php_rfc1867_getword = getword;
1301 php_rfc1867_getword_conf = getword_conf;
SAPI_API sapi_module_struct sapi_module
#define REQUEST_PARSE_BODY_OPTION_GET(name, fallback)
#define SAPI_POST_HANDLER_FUNC(post_handler)
unlink(string $filename, $context=null)
strrchr(string $haystack, string $needle, bool $before_needle=false)
strpbrk(string $string, string $characters)
header(string $header, bool $replace=true, int $response_code=0)
count(Countable|array $value, int $mode=COUNT_NORMAL)
strstr(string $haystack, string $needle, bool $before_needle=false)
basename(string $path, string $suffix="")
strchr(string $haystack, string $needle, bool $before_needle=false)
zend_ffi_ctype_name_buf buf
const mbfl_encoding * internal_encoding
bool encoding_translation
unsigned const char * end
unsigned const char * pos
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags)
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK
unsigned char key[REFLECTION_KEY_LEN]
xmlCharEncodingHandlerPtr encoding
PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *track_vars_array)
PHPAPI void php_register_variable_safe(const char *var, const char *strval, size_t str_len, zval *track_vars_array)
PHPAPI zend_result(* php_rfc1867_callback)(unsigned int event, void *event_data, void **extra)
#define MAX_SIZE_OF_INDEX
#define MAX_SIZE_ANONNAME
#define EMIT_WARNING_OR_ERROR(...)
PHPAPI void destroy_uploaded_files_hash(void)
SAPI_API void php_rfc1867_set_multibyte_callbacks(php_rfc1867_encoding_translation_t encoding_translation, php_rfc1867_get_detect_order_t get_detect_order, php_rfc1867_set_input_encoding_t set_input_encoding, php_rfc1867_getword_t getword, php_rfc1867_getword_conf_t getword_conf, php_rfc1867_basename_t basename)
#define PHP_UPLOAD_ERROR_D
char *(* php_rfc1867_getword_conf_t)(const zend_encoding *encoding, char *str)
struct _multipart_event_file_end multipart_event_file_end
char *(* php_rfc1867_basename_t)(const zend_encoding *encoding, char *str)
#define PHP_UPLOAD_ERROR_A
#define PHP_UPLOAD_ERROR_E
#define PHP_UPLOAD_ERROR_X
#define PHP_UPLOAD_ERROR_B
#define MULTIPART_EVENT_FILE_END
void(* php_rfc1867_set_input_encoding_t)(const zend_encoding *encoding)
int(* php_rfc1867_encoding_translation_t)(void)
struct _multipart_event_formdata multipart_event_formdata
#define PHP_UPLOAD_ERROR_C
#define MULTIPART_EVENT_FORMDATA
struct _multipart_event_start multipart_event_start
char *(* php_rfc1867_getword_t)(const zend_encoding *encoding, char **line, char stop)
#define PHP_UPLOAD_ERROR_F
#define MULTIPART_EVENT_START
struct _multipart_event_file_data multipart_event_file_data
#define MULTIPART_EVENT_END
#define MULTIPART_EVENT_FILE_START
#define MULTIPART_EVENT_FILE_DATA
struct _multipart_event_end multipart_event_end
void(* php_rfc1867_get_detect_order_t)(const zend_encoding ***list, size_t *list_size)
struct _multipart_event_file_start multipart_event_file_start
size_t post_bytes_processed
size_t post_bytes_processed
size_t post_bytes_processed
size_t post_bytes_processed
const zend_encoding * input_encoding
const zend_encoding ** detect_order
#define ZVAL_STRING(z, s)
#define ZVAL_EMPTY_STRING(z)
#define safe_erealloc(ptr, nmemb, size, offset)
#define estrndup(s, length)
#define ecalloc(nmemb, size)
#define FREE_HASHTABLE(ht)
#define erealloc(ptr, size)
#define ALLOC_HASHTABLE(ht)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strcasecmp(s1, s2)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *str, size_t len)
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
#define ZEND_HASH_MAP_FOREACH_VAL(ht, _val)
#define ZEND_HASH_FOREACH_END()
ZEND_API void zend_llist_destroy(zend_llist *l)
ZEND_API void zend_llist_add_element(zend_llist *l, const void *element)
ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent)
ZEND_API void zend_llist_clean(zend_llist *l)
void(* llist_dtor_func_t)(void *)
struct _zend_llist zend_llist
struct _zend_string zend_string
ZEND_API const zend_encoding * zend_multibyte_encoding_detector(const unsigned char *string, size_t length, const zend_encoding **list, size_t list_size)
ZEND_API const zend_encoding * zend_multibyte_get_internal_encoding(void)
ZEND_API size_t zend_multibyte_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const zend_encoding *encoding_to, const zend_encoding *encoding_from)
struct _zend_encoding zend_encoding
ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length)
#define smart_string_appends(str, src)
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
ZEND_RESULT_CODE zend_result
#define VCWD_UNLINK(path)