diff -x '*.o' -x '*.lo' -c -r php-4.3.11.original/main/rfc1867.c php-4.3.11/main/rfc1867.c
*** php-4.3.11.original/main/rfc1867.c	2005-02-14 22:28:39.000000000 -0200
--- php-4.3.11/main/rfc1867.c	2006-12-18 14:15:29.000000000 -0200
***************
*** 34,39 ****
--- 34,41 ----
  
  #undef DEBUG_FILE_UPLOAD
  
+ PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
+ 
  #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
  #include "ext/mbstring/mbstring.h"
  
***************
*** 127,132 ****
--- 129,136 ----
  #define UPLOAD_ERROR_C    3  /* Partially uploaded */
  #define UPLOAD_ERROR_D    4  /* No file uploaded */
  #define UPLOAD_ERROR_E    6  /* Missing /tmp or similar directory */
+ #define UPLOAD_ERROR_F    7  /* Failed to write file to disk */
+ #define UPLOAD_ERROR_X    8  /* File upload stopped by extension */
  
  void php_rfc1867_register_constants(TSRMLS_D)
  {
***************
*** 136,141 ****
--- 140,147 ----
  	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
  	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
  	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
+ 	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F,  CONST_CS | CONST_PERSISTENT);
+ 	REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION",  UPLOAD_ERROR_X,  CONST_CS | CONST_PERSISTENT);
  }
  
  static void normalize_protected_variable(char *varname TSRMLS_DC)
***************
*** 700,706 ****
  
  
  /* read until a boundary condition */
! static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes TSRMLS_DC)
  {
  	int len, max;
  	char *bound;
--- 706,712 ----
  
  
  /* read until a boundary condition */
! static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
  {
  	int len, max;
  	char *bound;
***************
*** 713,718 ****
--- 719,727 ----
  	/* look for a potential boundary match, only read data up to that point */
  	if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
  		max = bound - self->buf_begin;
+ 		if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
+ 			*end = 1;
+ 		}
  	} else {
  		max = self->bytes_in_buffer;
  	}
***************
*** 744,761 ****
    XXX: this is horrible memory-usage-wise, but we only expect
    to do this on small pieces of form data.
  */
! static char *multipart_buffer_read_body(multipart_buffer *self TSRMLS_DC)
  {
  	char buf[FILLUNIT], *out=NULL;
  	int total_bytes=0, read_bytes=0;
  
! 	while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf) TSRMLS_CC))) {
  		out = erealloc(out, total_bytes + read_bytes + 1);
  		memcpy(out + total_bytes, buf, read_bytes);
  		total_bytes += read_bytes;
  	}
  
  	if (out) out[total_bytes] = '\0';
  
  	return out;
  }
--- 753,771 ----
    XXX: this is horrible memory-usage-wise, but we only expect
    to do this on small pieces of form data.
  */
! static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
  {
  	char buf[FILLUNIT], *out=NULL;
  	int total_bytes=0, read_bytes=0;
  
! 	while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
  		out = erealloc(out, total_bytes + read_bytes + 1);
  		memcpy(out + total_bytes, buf, read_bytes);
  		total_bytes += read_bytes;
  	}
  
  	if (out) out[total_bytes] = '\0';
+ 	*len = total_bytes;
  
  	return out;
  }
***************
*** 779,786 ****
  	zend_bool magic_quotes_gpc;
  	multipart_buffer *mbuff;
  	zval *array_ptr = (zval *) arg;
! 	FILE *fp;
  	zend_llist header;
  
  	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));
--- 789,797 ----
  	zend_bool magic_quotes_gpc;
  	multipart_buffer *mbuff;
  	zval *array_ptr = (zval *) arg;
! 	int fd=-1;
  	zend_llist header;
+ 	void *event_extra_data = NULL;
  
  	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));
***************
*** 839,858 ****
  #endif
  	zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
  
  	while (!multipart_buffer_eof(mbuff TSRMLS_CC))
  	{
  		char buff[FILLUNIT];
  		char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL;
! 		int blen=0, wlen=0;
  
  		zend_llist_clean(&header);
  
  		if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
! 			SAFE_RETURN;
  		}
  
  		if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
  			char *pair=NULL;
  			
  			while (isspace(*cd)) {
  				++cd;
--- 850,880 ----
  #endif
  	zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
  
+ 	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,*param=NULL,*filename=NULL, *tmp=NULL;
! 		size_t blen=0, wlen=0;
! 		off_t offset;
  
  		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"))) {
  			char *pair=NULL;
+ 			int end=0;
  			
  			while (isspace(*cd)) {
  				++cd;
***************
*** 889,901 ****
  
  			/* Normal form variable, safe to read all data into memory */
  			if (!filename && param) {
! 
! 				char *value = multipart_buffer_read_body(mbuff TSRMLS_CC);
  
  				if (!value) {
  					value = estrdup("");
  				}
  
  #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, 
--- 911,935 ----
  
  			/* Normal form variable, safe to read all data into memory */
  			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("");
  				}
  
+ 				if (php_rfc1867_callback != NULL) {
+ 					multipart_event_formdata event_formdata;
+ 
+ 					event_formdata.post_bytes_processed = SG(read_post_bytes);
+ 					event_formdata.name = param;
+ 					event_formdata.value = &value;
+ 					event_formdata.length = value_len;
+ 					event_formdata.newlength = NULL;
+ 					php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
+ 				}
+ 
  #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, 
***************
*** 917,938 ****
  
  			/* If file_uploads=off, skip the file part */
  			if (!PG(file_uploads)) {
! 				if (filename) {
! 					efree(filename);
! 				}
! 				if (param) {
! 					efree(param);
! 				}
! 				continue;
  			}
  
  			/* Return with an error if the posted data is garbled */
! 			if (!param) {
  				sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
! 				if (filename) {
! 					efree(filename);
! 				}
! 				SAFE_RETURN;
  			}
  			
  			/* New Rule: never repair potential malicious user input */
--- 951,963 ----
  
  			/* 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;
  			}
  			
  			/* New Rule: never repair potential malicious user input */
***************
*** 962,973 ****
  
  			if (!skip_upload) {
  				/* Handle file */
! 				fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &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;
  				}
  			}
  			if (skip_upload) {
  				efree(param);
  				efree(filename);
--- 987,1021 ----
  
  			if (!skip_upload) {
  				/* Handle file */
! 				fd = php_open_temporary_fd(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC);
! 				if (fd==-1) {
  					sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
  					cancel_upload = UPLOAD_ERROR_E;
  				}
  			}
+ 			
+ 			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 = param;
+ 				event_file_start.filename = &filename;
+ 				if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
+ 					if (temp_filename) {
+ 						if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
+ 							close(fd);
+ 							unlink(temp_filename);
+ 						}
+ 						efree(temp_filename);
+ 					}
+ 					temp_filename="";
+ 					efree(param);
+ 					efree(filename);
+ 					continue;
+ 				}
+ 			}
+ 
+ 			
  			if (skip_upload) {
  				efree(param);
  				efree(filename);
***************
*** 981,988 ****
  				cancel_upload = UPLOAD_ERROR_D;
  			}
  
! 			while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC)))
  			{
  				if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) {
  					sapi_module.sapi_error(E_WARNING, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
  					cancel_upload = UPLOAD_ERROR_A;
--- 1029,1053 ----
  				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 > PG(upload_max_filesize)) {
  					sapi_module.sapi_error(E_WARNING, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
  					cancel_upload = UPLOAD_ERROR_A;
***************
*** 990,1007 ****
  					sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
  					cancel_upload = UPLOAD_ERROR_B;
  				} else if (blen > 0) {
! 					wlen = fwrite(buff, 1, blen, fp);
  			
  					if (wlen < blen) {
  						sapi_module.sapi_error(E_WARNING, "Only %d bytes were written, expected to write %d", wlen, blen);
! 						cancel_upload = UPLOAD_ERROR_C;
  					} else {
  						total_bytes += wlen;
  					}
  				} 
  			} 
! 			if (fp) {
! 				fclose(fp);
  			}
  
  #ifdef DEBUG_FILE_UPLOAD
--- 1055,1081 ----
  					sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
  					cancel_upload = UPLOAD_ERROR_B;
  				} else if (blen > 0) {
! 					wlen = write(fd, buff, blen);
  			
  					if (wlen < blen) {
  						sapi_module.sapi_error(E_WARNING, "Only %d bytes were written, expected to write %d", wlen, blen);
! 						cancel_upload = UPLOAD_ERROR_F;
  					} else {
  						total_bytes += wlen;
  					}
+ 					
+ 					offset += wlen;
  				} 
  			} 
! 			if (fd!=-1) {
! 				close(fd);
! 			}
! 
! 			if (!cancel_upload && !end) {
! #ifdef DEBUG_FILE_UPLOAD
! 				sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
! #endif
! 				cancel_upload = UPLOAD_ERROR_C;
  			}
  
  #ifdef DEBUG_FILE_UPLOAD
***************
*** 1011,1016 ****
--- 1085,1101 ----
  			}
  #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 = 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 */
***************
*** 1202,1208 ****
  			efree(param);
  		}
  	}
! 
  	SAFE_RETURN;
  }
  
--- 1287,1300 ----
  			efree(param);
  		}
  	}
! 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);
! 	}
! 	
  	SAFE_RETURN;
  }
  
diff -x '*.o' -x '*.lo' -c -r php-4.3.11.original/main/rfc1867.h php-4.3.11/main/rfc1867.h
*** php-4.3.11.original/main/rfc1867.h	2002-07-11 22:49:58.000000000 -0300
--- php-4.3.11/main/rfc1867.h	2006-12-16 20:44:47.000000000 -0200
***************
*** 1,13 ****
--- 1,76 ----
+ /*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2006 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author:                                                              |
+   +----------------------------------------------------------------------+
+ */
+ 
+ /* $Id: rfc1867.h,v 1.13.2.1.2.2 2006/07/26 13:22:06 tony2001 Exp $ */
+ 
  #ifndef RFC1867_H
  #define RFC1867_H
  
  #include "SAPI.h"
  
  #define MULTIPART_CONTENT_TYPE "multipart/form-data"
+ #define MULTIPART_EVENT_START		0
+ #define MULTIPART_EVENT_FORMDATA	1
+ #define MULTIPART_EVENT_FILE_START	2
+ #define MULTIPART_EVENT_FILE_DATA	3
+ #define MULTIPART_EVENT_FILE_END	4
+ #define MULTIPART_EVENT_END		5
+ 
+ typedef struct _multipart_event_start {
+ 	size_t	content_length;
+ } multipart_event_start;
+ 
+ typedef struct _multipart_event_formdata {
+ 	size_t	post_bytes_processed;
+ 	char	*name;
+ 	char	**value;
+ 	size_t	length;
+ 	size_t	*newlength;
+ } multipart_event_formdata;
+ 
+ typedef struct _multipart_event_file_start {
+ 	size_t	post_bytes_processed;
+ 	char	*name;
+ 	char	**filename;
+ } multipart_event_file_start;
+ 
+ typedef struct _multipart_event_file_data {
+ 	size_t	post_bytes_processed;
+ 	off_t	offset;
+ 	char	*data;
+ 	size_t	length;
+ 	size_t	*newlength;	
+ } multipart_event_file_data;
+ 
+ typedef struct _multipart_event_file_end {
+ 	size_t	post_bytes_processed;
+ 	char	*temp_filename;
+ 	int	cancel_upload;
+ } multipart_event_file_end;
+ 
+ typedef struct _multipart_event_end {
+ 	size_t	post_bytes_processed;
+ } multipart_event_end;
  
  SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler);
  
  void destroy_uploaded_files_hash(TSRMLS_D);
  void php_rfc1867_register_constants(TSRMLS_D);
+ extern PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC);
  
  #endif /* RFC1867_H */
