无状态增量文件哈希上下文恢复

Question in short

How can one "resume hash_context" in PHP?


Background & Current Situation

The software's goal is to receive big file chunk by chunk (synchronously), calculate both MD5 and SHA1 of that file and generate a download link (of the full file). Something like rapidshare but instead of sending the file fully, sending the file chunk by chunk.

Currently the software is working with this logic:
It's receiving file chunks (10MB chunks of a big file) synchronously per file session. After receiving all the chunks I need to calculating the MD5 and SHA1 of a file which takes very long time for files over 1GB.

Pseudo code for file finalizer (when all chunks are received):

$fileKey = $_GET['KEY'];
$ctxMd5 = hash_init('md5');
$ctxSha1 = hash_init('sha1');

$fh = fopen('file/containing/all_chunks.tmp', 'r');
while(!feof($fh)) {
$data = fread($fh, CHUNK_SIZE);
    hash_update($ctxMd5, $data);
    hash_update($ctxSha1, $data);
}
$md5 = hash_final($ctxMd5);
$sha1= hash_final($ctxSha1);

saveFileHashes($fileKey, $md5, $sha1);

Problem is that when all chunks are uploaded user has to wait until the script calculates both hashes which is very frustrating.


The Solution to the Problem

I would like to change the receive logic this way:
Instead of calculating hashes when all the chunks are received and saved, I would like to resume or create new hashing context, increment the context, save the hashing context state and save the file chunk, When each chunk is received.

Pseudo code for chunk receiver:

$chunkData = getIncommingChunkData();
$fileKey = $_GET['KEY'];

$ctxMd5 = resumeMd5HasingContext($fileKey);
$ctxSha1 = resumeSha1HasingContext($fileKey);

hash_update($ctxMd5, $chunkData);
hash_update($ctxSha1, $chunkData);

saveMd5HashingContext($fileKey, $ctxMd5)
saveSha1HashingContext($fileKey, $ctxSha1)

appendFileChunk($fileKey, $chunkData);

The Problem

The main problem is that PHP resources are not serializable, neither does the hash_init provide a way of resuming the context.

I would like to know how to achieve all stated above?

Just an idea to evercome the problem: maybe you should separate the reception process from the concatenation/hashing process.

When you initialize the transfer, your script could start a persistent script that runs in the background, waits for the chunks, calculates the hashes on each chunk that become available, appends them to the file and exits when all chunks are received, all in a single execution.

Your reception script would simply move the uploaded chunk files to a temporary directory to make them available to the persistent process.