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