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