Hello,

here comes a first try of the patch (unified against HEAD, see attachment). It adds a single callback to main/rfc1867.c and a function to register a callback function. The callback looks like this:

void *php_rfc1867_callback(void *tracking, int event, int bytes,
        char *param, char *value)

tracking is just a pointer to connect different callback function calls. The callback function can return a pointer to some internal structure and this pointer is passed back to the callback function on the next callback.

The callback function is called on the following events:

MULTIPART_EVENT_START: This event is fired if a multipart upload has just begun. tracking is NULL, bytes is set to Content-length, param and value is NULL. A PECL extension can initialize a progress structure if this event is received and return a pointer to that structure which will then be passed with all following callbacks.

MULTIPART_EVENT_FORMDATA: This event is fired if a normal form-data variable was found. bytes is the current progress, param is set to the form field variable name and value to the field value. A PECL extension can use this event to intercept an UPLOAD_ID or a session id or whatever. After the PECL extension has the upload id it can start saving the file upload progress to a database or a temporary file or whatever.

MULTIPART_EVENT_FILE: This event is fired if a new file upload was found. bytes is the current progress, param is the name of the file upload, value is the filename on the client machine. A PECL extension can use these informations to increase a file counter and to display the filename of the currently uploaded file to the user.

MULTIPART_EVENT_UPDATE: This event is fired if a file a still being received. bytes is the current progress. Param and value is NULL. A PECL extension can use it to just update the upload progress data.

MULTIPART_EVENT_END: This event is fired if the multipart upload is finished or canceled. bytes is the current progress or 0 if the upload is complete. param and value is NULL. A PECL extension can use it to free the structure passed with the tracking pointer and to trigger the closing of a progress popup window or something like this.


The patch is very similiar to the one of pdoro.from.ro but it has the advantage that is not "progress meter" specific. It's just a universal callback which may be useful in other scenarios, too. So there is no need to process the UPLOAD_ID inside rfc1867.c. With my patch this task is now the responsibility of the PECL extension.


I don't know the internals of PHP very well. I have not used any of these TSRMLS macros because I don't understand them. So if these macros are needed here then tell me.

Even if this patch is not going to make it into PHP I would be glad about some comments on it.

--
Bye, K <http://www.ailis.de/~k/> (FidoNet: 2:240/2188.18)
[A735 47EC D87B 1F15 C1E9  53D3 AA03 6173 A723 E391]
(Finger [EMAIL PROTECTED] to get public key)
diff -Nur php-5.1-orig/main/rfc1867.c php-5.1-new/main/rfc1867.c
--- php-5.1-orig/main/rfc1867.c	2004-11-05 18:22:02.000000000 +0100
+++ php-5.1-new/main/rfc1867.c	2004-11-06 10:21:24.000000000 +0100
@@ -40,6 +40,9 @@
 
 static void safe_php_register_variable(char *var, char *strval, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
 
+static void *(*php_rfc1867_callback)(void *tracking, int event, int bytes, char *param, char *value) = NULL;
+#define PHP_RFC1867_CALLBACK(event, bytes, param, value) if (php_rfc1867_callback) tracking = php_rfc1867_callback(tracking, event, bytes, param, value)
+
 #define SAFE_RETURN { \
     php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
 	if (lbuf) efree(lbuf); \
@@ -762,6 +765,11 @@
 	return out;
 }
 
+void php_rfc1867_register_callback(void *callback)
+{
+    php_rfc1867_callback = callback;
+}
+
 
 /*
  * The combined READER/HANDLER
@@ -784,6 +792,7 @@
 	zval *array_ptr = (zval *) arg;
 	FILE *fp;
 	zend_llist header;
+	void *tracking = 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));
@@ -842,6 +851,9 @@
 #endif
 	zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
 
+    PHP_RFC1867_CALLBACK(MULTIPART_EVENT_START, 
+        SG(request_info).content_length, NULL, NULL);
+
 	while (!multipart_buffer_eof(mbuff TSRMLS_CC))
 	{
 		char buff[FILLUNIT];
@@ -851,6 +863,7 @@
 		zend_llist_clean(&header);
 
 		if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
+		    PHP_RFC1867_CALLBACK(MULTIPART_EVENT_END, 0, NULL, NULL);
 			SAFE_RETURN;
 		}
 
@@ -916,6 +929,9 @@
 					max_file_size = atol(value);
 				}
 
+				PHP_RFC1867_CALLBACK(MULTIPART_EVENT_FORMDATA,
+				    SG(read_post_bytes), param, value);
+
 				efree(param);
 				efree(value);
 				continue;
@@ -929,6 +945,8 @@
 			/* Return with an error if the posted data is garbled */
 			if (!param && !filename) {
 				sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
+                PHP_RFC1867_CALLBACK(MULTIPART_EVENT_END, 
+                    SG(read_post_bytes), NULL, NULL);
 				SAFE_RETURN;
 			}
 			
@@ -971,6 +989,10 @@
 					skip_upload = 1;
 				}
 			}
+
+            PHP_RFC1867_CALLBACK(MULTIPART_EVENT_FILE,
+                SG(read_post_bytes), param, filename);
+
 			if (skip_upload) {
 				efree(param);
 				efree(filename);
@@ -989,6 +1011,9 @@
 
 			while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC)))
 			{
+                PHP_RFC1867_CALLBACK(MULTIPART_EVENT_UPDATE,
+                    SG(read_post_bytes), NULL, NULL);
+			    
 				if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) {
 #if DEBUG_FILE_UPLOAD
 					sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
@@ -1211,6 +1236,7 @@
 		}
 	}
 
+    PHP_RFC1867_CALLBACK(MULTIPART_EVENT_END, 0, NULL, NULL);
 	SAFE_RETURN;
 }
 
diff -Nur php-5.1-orig/main/rfc1867.h php-5.1-new/main/rfc1867.h
--- php-5.1-orig/main/rfc1867.h	2004-11-06 10:05:09.000000000 +0100
+++ php-5.1-new/main/rfc1867.h	2004-11-06 10:09:43.000000000 +0100
@@ -24,10 +24,16 @@
 #include "SAPI.h"
 
 #define MULTIPART_CONTENT_TYPE "multipart/form-data"
+#define MULTIPART_EVENT_START 0
+#define MULTIPART_EVENT_FORMDATA 1
+#define MULTIPART_EVENT_FILE 2
+#define MULTIPART_EVENT_UPDATE 3
+#define MULTIPART_EVENT_END 4
 
 SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler);
 
 void destroy_uploaded_files_hash(TSRMLS_D);
 void php_rfc1867_register_constants(TSRMLS_D);
+void php_rfc1867_register_callback(void *callback);
 
 #endif /* RFC1867_H */

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to