我想请教您如何在PHP中计算大型文件的sha256。目前,我使用Amazon Glacier存储旧文件并使用其API上传档案。最初,我只使用了无法访问MB大小图像的小文件。当我尝试上传超过1MB时,API响应表示我给他们的校验和与他们计算的不同。
以下是我上传文件的代码:
//get the sha256 using the file path
$image = //image path;
$sha256 = hash_file("sha256", $image);
$archive = $glacier->uploadArchive([
'accountId' => '',
'body' => "",
'checksum' => $sha256,
'contentSHA256' => $sha256,
'sourceFile' => $image,
'vaultName' => 'my-vault'
]);
错误:
AWS HTTP error: Client error: `POST https://glacier.us-west-2.amazonaws.com/vaults/70/archives` resulted in a `400 Bad Request` response:{"code":"InvalidParameterValueException","message":"Checksum mismatch: expected 9f1d4da29b6ec24abde48cb65cc32652ff589467 (truncated...)
我尝试了下面的函数来检查最终的哈希值,但是当我打印它时它似乎不是正确的哈希:
private function getFinalHash($file)
{
$fp = fopen($file, "r");
$ctx = hash_init('sha256');
while (!feof($fp)) {
$buffer = fgets($fp, 1024);
hash_update($ctx, $buffer);
}
$hash = hash_final($ctx, true); print_r($hash);exit;
fclose($fp);
}
结果哈希是这样的:ŸM¢›nÂJ½äŒ¶\Ã&RÿX”gíÖ'„IoA\C÷×
Amazon Glacier API文档显示了如何计算校验和:
对于每1 MB有效负载数据块,计算SHA-256哈希值。最后一块数据可能小于1 MB。例如,如果要上载3.2 MB存档,则为前三个1 MB数据块中的每一个计算SHA-256哈希值,然后计算剩余0.2 MB数据的SHA-256哈希值。这些哈希值构成树的叶节点。
我认为提供校验和有正确的方法,但我不知道如何使用PHP使用大文件。我真的需要你的帮助。
答案 0 :(得分:1)
Glacier有他们自己的方式来计算SHA256-TREE-HASH。 这里有PHP的工作代码。 此函数返回从1MB部分创建的SHA256哈希。它对我来说非常适合,即使对于大型或小型文件也是如此。
private function getFinalHash($path, $MB = 1048576)
{
$fp = fopen($path, "rb");
$hashes = [];
while (($buffer = fread($fp, $MB))!=="") {
$hashes[] = hash("sha256", $buffer, true);
}
if(count($hashes)==1){
return bin2hex($hashes[0]);
}
while(true){
$hashes_new = [];
foreach($hashes as $k => $hash){
if ($k % 2 == 0) {
if(isset($hashes[$k+1])){
$hashes_new[] = hash("sha256", $hash.$hashes[$k+1], true);
}
}
}
if(count($hashes)>2 && count($hashes) % 2 != 0){
$hashes_new[] = $hashes[count($hashes)-1];
}
if(count($hashes_new)>1){
$hashes = $hashes_new;
}else{
fclose($fp);
return bin2hex($hashes_new[0]);
}
}
}
答案 1 :(得分:0)
诀窍是,sha256哈希是由您使用的适用于PHP的AWS开发工具包计算的。 因此,您无需自己计算哈希。 这是一个示例:
$client = new GlacierClient(array(
'key' => '[aws access key]',
'secret' => '[aws secret key]',
'region' => '[aws region]', // (e.g., us-west-2) )); $result =
$client->uploadArchive(array(
'vaultName' => $vaultName,
'body' => fopen($filename, 'r'), ));
$archiveId = $result->get('archiveId');