Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:13755 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 27122 invoked by uid 1010); 6 Nov 2004 10:07:13 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 27095 invoked from network); 6 Nov 2004 10:07:12 -0000 Received: from unknown (HELO malcolm.ailis.de) (217.115.149.166) by pb1.pair.com with SMTP; 6 Nov 2004 10:07:12 -0000 Received: (qmail 3874 invoked by uid 64014); 6 Nov 2004 10:07:21 -0000 Received: from p50857cf4.dip.t-dialin.net (HELO ?192.168.36.101?) (k@80.133.124.244) by malcolm.ailis.de with SMTP; 6 Nov 2004 10:07:19 -0000 Message-ID: <418CA233.1050301@ailis.de> Date: Sat, 06 Nov 2004 11:06:43 +0100 User-Agent: Mozilla Thunderbird 0.8 (X11/20040926) X-Accept-Language: en-us, en MIME-Version: 1.0 To: internals@lists.php.net X-Enigmail-Version: 0.86.1.0 X-Enigmail-Supports: pgp-inline, pgp-mime Content-Type: multipart/mixed; boundary="------------000607060504050804020806" X-Virus-Scanned: by AMaViS 0.3.12 Subject: rfc1867_callback From: k@ailis.de (Klaus Reimer) --------------000607060504050804020806 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit 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 (FidoNet: 2:240/2188.18) [A735 47EC D87B 1F15 C1E9 53D3 AA03 6173 A723 E391] (Finger k@ailis.de to get public key) --------------000607060504050804020806 Content-Type: text/x-patch; name="rfc1867_callback.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="rfc1867_callback.patch" 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 */ --------------000607060504050804020806--