在進行文件傳輸、下載或存儲時,文件完整性校驗是一個重要的環節。通過計算文件的哈希值並與預期值對比,我們可以有效檢測文件是否被篡改或損壞。在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統一格式。