如何在PHP中为大文件计算sha256

时间:2017-03-27 06:36:19

标签: php amazon-web-services zend-framework2 sha256 amazon-glacier

我想请教您如何在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使用大文件。我真的需要你的帮助。

2 个答案:

答案 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');