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