I need to quickly verify the integrity of local files against the copy on Dropbox, in PHP, to ensure that downloads match the remote and uploads match the local.
I'm getting that information via a request to the API v2's get_metadata
method.
This self-contained function will produce the file's hash, according to Dropbox's explanation:
To calculate the content_hash of a file:
- Split the file into blocks of 4 MB (4,194,304 or 4 * 1024 * 1024 bytes). The last block (if any) may be smaller than 4 MB.
- Compute the hash of each block using SHA-256.
- Concatenate the hash of all blocks in the binary format to form a single binary string.
- Compute the hash of the concatenated string using SHA-256. Output the resulting hash in hexadecimal format.
The returned hash is a SHA256 hash of the concatenated binary hashes of the file's constituent blocks.
function dropbox_content_hash($file, $binary = false) {
$fh = fopen($file, 'r');
if (!$fh) {
# warning already issued
return false;
}
$bs = 4 * 1024 ** 2; # 4 MiB blocks
$algo = 'sha256';
$hashes = '';
$zero_byte_file_check = true;
do {
$block = fread($fh, $bs);
if ($block === false) {
fclose($fh);
return false;
}
if ($zero_byte_file_check) {
if ($block === '') {
break;
}
$zero_byte_file_check = false;
}
$hashes .= hash($algo, $block, true);
} while (!feof($fh));
fclose($fh);
return hash($algo, $hashes, $binary);
}