Я хотел бы попросить вашей помощи о том, как рассчитать sha256 больших файлов в PHP. В настоящее время я использовал Amazon Glacier для хранения старых файлов и использования их API для загрузки архива. Изначально я использовал только небольшие файлы, которые не могут охватить изображения размером в МБ. Когда я попытался загрузить более 1 МБ, ответ 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 МБ вычислите хэш SHA-256. Последний кусок данных может быть менее 1 МБ. Например, если вы загружаете архив размером 3,2 МБ, вы вычисляете значения хеш-функции SHA-256 для каждого из первых трех блоков данных размером 1 МБ, а затем вычисляете хэш-код SHA-256 из оставшихся данных размером 0,2 МБ. Эти хеш-значения образуют листовые узлы дерева.
Я думаю, что есть что-то с правильным способом предоставления контрольной суммы, но я не знаю, как я должен делать это с большими файлами, используя PHP. Мне действительно нужна твоя помощь по этому поводу.
У ледника есть свой способ подсчета SHA256-TREE-HASH.
Здесь у вас есть рабочий код на PHP.
Эта функция возвращает хеш SHA256, созданный из частей размером 1 МБ, как они хотят. Он отлично работает даже для больших или маленьких файлов.
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]);
}
}
}
Других решений пока нет …