Hi,
  I'm submitting a patch to perform "on the fly" MD5/SHA1 digest
calculation of a file uploaded via the HTTP POST method.  Being
not uncommon for applications to require some digest of a freshly
uploaded file, doing the math directly in the buffer where the file is
being read can save some time.

A similar patch was submitted in August 2004 and raised some interest,
but never got merged.

Digest calculation is triggered by setting the special input fields
COMPUTE_MD5 and/or COMPUTE_SHA1 to a non-zero value:

  <input type="hidden" name="COMPUTE_SHA1" value="1">

(note that these assignments must precede the
<input type="file" name=...> field, as in the MAX_FILE_SIZE case.)

The result is found in the special variables
$_FILES[userfile]["md5"] and $_FILES[userfile]["sha1"].
These variables are only defined upon request of the corresponding
digest.

The patch was produced against the php6 CVS version of rfc1867.c
(1.190).

Cheers,
 David
-- 
 David Santinoli
 Tieffe Sistemi S.r.l.                      viale Piceno 21, Milano
 www.tieffesistemi.com                         tel. +39 02 45490882
--- main/rfc1867.c      2007-05-05 11:36:25.000000000 +0200
+++ main/rfc1867.c.new  2007-05-05 01:04:28.000000000 +0200
@@ -32,6 +32,8 @@
 #include "php_globals.h"
 #include "php_variables.h"
 #include "rfc1867.h"
+#include "ext/standard/md5.h"
+#include "ext/standard/sha1.h"
 
 #define DEBUG_FILE_UPLOAD ZEND_DEBUG
 
@@ -1011,8 +1013,18 @@
        U_STRING_DECL(name_key, "name", 4);
        U_STRING_DECL(filename_key, "filename", 8);
        U_STRING_DECL(maxfilesize_key, "MAX_FILE_SIZE", 13);
+       U_STRING_DECL(computemd5_key, "COMPUTE_MD5", 11);
+       U_STRING_DECL(computesha1_key, "COMPUTE_SHA1", 12);
        static zend_bool did_string_init = FALSE;
        int llen = 0;
+       int compute_md5=0, compute_sha1=0;
+       PHP_MD5_CTX md5_context;
+       unsigned char md5_digest[16];
+       char md5_ascii_string[33];
+       PHP_SHA1_CTX sha1_context;
+       unsigned char sha1_digest[20];
+       char sha1_ascii_string[41];
+       UChar *md5_string=NULL, *sha1_string=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));
@@ -1069,6 +1081,8 @@
                U_STRING_INIT(name_key, "name", 4);
                U_STRING_INIT(filename_key, "filename", 8);
                U_STRING_INIT(maxfilesize_key, "MAX_FILE_SIZE", 13);
+               U_STRING_INIT(computemd5_key, "COMPUTE_MD5", 11);
+               U_STRING_INIT(computesha1_key, "COMPUTE_SHA1", 12);
                did_string_init = TRUE;
        }
 
@@ -1165,6 +1179,12 @@
                                if (!u_strcasecmp(param, maxfilesize_key, 0)) {
                                        max_file_size = zend_u_strtol(u_val, 
NULL, 10);
                                }
+                               else if (!u_strcasecmp(param, computemd5_key, 
0)) {
+                                       compute_md5 = zend_u_strtol(u_val, 
NULL, 10);
+                               }
+                               else if (!u_strcasecmp(param, computesha1_key, 
0)) {
+                                       compute_sha1 = zend_u_strtol(u_val, 
NULL, 10);
+                               }
 
 var_done:
                                efree(param);
@@ -1247,6 +1267,14 @@
                                cancel_upload = UPLOAD_ERROR_D;
                        }
 
+                       if (compute_md5) {
+                               PHP_MD5Init(&md5_context);
+                       }
+ 
+                       if (compute_sha1) {
+                               PHP_SHA1Init(&sha1_context);
+                       }
+
                        end = 0;
                        while (!cancel_upload && (blen = 
multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC)))
                        {
@@ -1263,6 +1291,13 @@
                                } else if (blen > 0) {
                                        wlen = fwrite(buff, 1, blen, fp);
 
+                                       if (compute_md5) {
+                                               PHP_MD5Update(&md5_context, 
buff, blen);
+                                       }
+                                       if (compute_sha1) {
+                                               PHP_SHA1Update(&sha1_context, 
buff, blen);
+                                       }
+
                                        if (wlen < blen) {
 #if DEBUG_FILE_UPLOAD
                                                
sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write 
%d", wlen, blen);
@@ -1302,6 +1337,17 @@
                                zend_u_hash_add(SG(rfc1867_uploaded_files), 
IS_UNICODE, ZSTR(temp_filename), u_strlen(temp_filename) + 1, &temp_filename, 
sizeof(UChar *), NULL);
                        }
 
+                       if (compute_md5) {
+                               PHP_MD5Final(md5_digest, &md5_context);
+                               make_digest(md5_ascii_string, md5_digest);
+                               md5_string = 
zend_ascii_to_unicode(md5_ascii_string, strlen(md5_ascii_string)+1 
ZEND_FILE_LINE_CC);
+                               }
+                       if (compute_sha1) {
+                               PHP_SHA1Final(sha1_digest, &sha1_context);
+                               make_sha1_digest(sha1_ascii_string, 
sha1_digest);
+                               sha1_string = 
zend_ascii_to_unicode(sha1_ascii_string, strlen(sha1_ascii_string)+1 
ZEND_FILE_LINE_CC);
+                               }
+
                        /* is_arr_upload is true when name of file upload field
                         * ends in [.*]
                         * start_arr is set to point to 1st [
@@ -1423,6 +1469,26 @@
                        add_u_protected_variable(lbuf TSRMLS_CC);
                        register_u_http_post_files_variable(lbuf, 
temp_filename, u_strlen(temp_filename), http_post_files, 1 TSRMLS_CC);
 
+                       /* Add $foo[md5] */
+                       if (!cancel_upload && compute_md5) {
+                               if (is_arr_upload) {
+                                       u_snprintf(lbuf, llen, "%S[md5][%S]", 
abuf, array_index);
+                               } else {
+                                       u_snprintf(lbuf, llen, "%S[md5]", 
param);
+                               }
+                               register_u_http_post_files_variable(lbuf, 
md5_string, u_strlen(md5_string), http_post_files, 0 TSRMLS_CC);
+                       }
+
+                       /* Add $foo[sha1] */
+                       if (!cancel_upload && compute_sha1) {
+                               if (is_arr_upload) {
+                                       u_snprintf(lbuf, llen, "%S[sha1][%S]", 
abuf, array_index);
+                               } else {
+                                       u_snprintf(lbuf, llen, "%S[sha1]", 
param);
+                               }
+                               register_u_http_post_files_variable(lbuf, 
sha1_string, u_strlen(sha1_string), http_post_files, 0 TSRMLS_CC);
+                       }
+
                        {
                                zval file_size, error_type;
 
@@ -1487,6 +1553,13 @@
        int fd=-1;
        zend_llist header;
        int llen = 0;
+       int compute_md5=0, compute_sha1=0;
+       PHP_MD5_CTX md5_context;
+       unsigned char md5_digest[16];
+       char md5_string[33];
+       PHP_SHA1_CTX sha1_context;
+       unsigned char sha1_digest[20];
+       char sha1_string[41];
 
        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));
@@ -1621,6 +1694,10 @@
                                }
                                if (!strcasecmp(param, "MAX_FILE_SIZE")) {
                                        max_file_size = atol(value);
+                               } else if (!strcasecmp(param, "COMPUTE_MD5")) {
+                                       compute_md5 = atol(value);
+                               } else if (!strcasecmp(param, "COMPUTE_SHA1")) {
+                                       compute_sha1 = atol(value);
                                }
 
                                efree(param);
@@ -1696,6 +1773,14 @@
                                cancel_upload = UPLOAD_ERROR_D;
                        }
 
+                       if (compute_md5) {
+                               PHP_MD5Init(&md5_context);
+                       }
+ 
+                       if (compute_sha1) {
+                               PHP_SHA1Init(&sha1_context);
+                       }
+
                        end = 0;
                        while (!cancel_upload && (blen = 
multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC)))
                        {
@@ -1711,6 +1796,13 @@
                                        cancel_upload = UPLOAD_ERROR_B;
                                } else if (blen > 0) {
                                        wlen = write(fd, buff, blen);
+
+                                       if (compute_md5) {
+                                               PHP_MD5Update(&md5_context, 
buff, blen);
+                                       }
+                                       if (compute_sha1) {
+                                               PHP_SHA1Update(&sha1_context, 
buff, blen);
+                                       }
                        
                                        if (wlen < blen) {
 #if DEBUG_FILE_UPLOAD
@@ -1750,6 +1842,15 @@
                                zend_hash_add(SG(rfc1867_uploaded_files), 
temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
                        }
 
+                       if (compute_md5) {
+                               PHP_MD5Final(md5_digest, &md5_context);
+                               make_digest(md5_string, md5_digest);
+                               }
+                       if (compute_sha1) {
+                               PHP_SHA1Final(sha1_digest, &sha1_context);
+                               make_sha1_digest(sha1_string, sha1_digest);
+                               }
+
                        /* is_arr_upload is true when name of file upload field
                         * ends in [.*]
                         * start_arr is set to point to 1st [
@@ -1889,6 +1990,26 @@
                        add_protected_variable(lbuf TSRMLS_CC);
                        register_http_post_files_variable(lbuf, temp_filename, 
http_post_files, 1 TSRMLS_CC);
 
+                       /* Add $foo[md5] */
+                       if (!cancel_upload && compute_md5) {
+                               if (is_arr_upload) {
+                                       snprintf(lbuf, llen, "%s[md5][%s]", 
abuf, array_index);
+                               } else {
+                                       snprintf(lbuf, llen, "%s[md5]", param);
+                               }
+                               register_http_post_files_variable(lbuf, 
md5_string, http_post_files, 0 TSRMLS_CC);
+                       }
+
+                       /* Add $foo[sha1] */
+                       if (!cancel_upload && compute_sha1) {
+                               if (is_arr_upload) {
+                                       snprintf(lbuf, llen, "%s[sha1][%s]", 
abuf, array_index);
+                               } else {
+                                       snprintf(lbuf, llen, "%s[sha1]", param);
+                               }
+                               register_http_post_files_variable(lbuf, 
sha1_string, http_post_files, 0 TSRMLS_CC);
+                       }
+
                        {
                                zval file_size, error_type;
 

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

Reply via email to