在进行文件传输、下载或存储时,文件完整性校验是一个重要的环节。通过计算文件的哈希值并与预期值对比,我们可以有效检测文件是否被篡改或损坏。在 PHP 中,hash_final 函数配合 hash_init、hash_update 可以流式地处理文件,而 file_get_contents 则可以一次性读取文件内容。本篇文章将带你了解如何结合这两者,完成文件完整性校验。
hash_final 是 PHP 中的一个函数,用于完成哈希计算并返回结果。通常它和 hash_init、hash_update 配合使用,适用于处理大文件或需要分段计算的场景。
与 hash() 函数(一次性计算)不同,hash_final 允许你分步骤处理数据,比如分块读取文件内容,每一块都用 hash_update 更新到哈希上下文中,最后通过 hash_final 得到最终的哈希值。
最简单的文件完整性校验,可以直接使用:
$filePath = 'https://gitbox.net/files/sample.txt';
$fileContents = file_get_contents($filePath);
$hash = hash('sha256', $fileContents);
echo "文件的 SHA-256 哈希值为: $hash";
这里,hash 函数一次性计算了整个文件的哈希值,适合小文件。但对于大文件,这种方式可能消耗大量内存。
对于大文件,可以采用流式处理方式,减少内存占用:
$filePath = 'https://gitbox.net/files/largefile.zip';
$context = hash_init('sha256');
$handle = fopen($filePath, 'rb');
if ($handle) {
while (!feof($handle)) {
$buffer = fread($handle, 8192); // 每次读取8KB
hash_update($context, $buffer);
}
fclose($handle);
$finalHash = hash_final($context);
echo "大文件的 SHA-256 哈希值为: $finalHash";
} else {
echo "无法打开文件: $filePath";
}
说明:
hash_init('sha256') 初始化一个 SHA-256 哈希上下文。
fread 每次读取一块数据(这里是 8KB)。
hash_update 将读取的块更新到哈希上下文。
hash_final 完成计算并返回最终结果。
这种方式不仅节省内存,还能更好地处理远程或大文件。
完整性验证的关键是 比对。你通常会有一个预期的哈希值(比如下载页面提供的校验码)。代码示例如下:
$filePath = 'https://gitbox.net/files/largefile.zip';
$expectedHash = '预期的哈希值(小写)';
$context = hash_init('sha256');
$handle = fopen($filePath, 'rb');
if ($handle) {
while (!feof($handle)) {
$buffer = fread($handle, 8192);
hash_update($context, $buffer);
}
fclose($handle);
$finalHash = hash_final($context);
if ($finalHash === strtolower($expectedHash)) {
echo "文件完整性验证通过!";
} else {
echo "文件完整性验证失败,哈希不匹配。";
}
} else {
echo "无法打开文件: $filePath";
}
小贴士:
确保预期哈希值的字母大小写一致(通常用小写)。
对比前可以使用 strtolower 或 strtoupper 统一格式。