在PHP 中處理哈希運算時, hash_init() 、 hash_update()和hash_final()這組函數是一個非常強大的組合。它們提供了一種流式(分段)計算哈希值的方式,適合處理大文件或分塊數據,比一次性用hash()函數更高效。
本文將詳細講解如何正確配合使用hash_update()和hash_final() ,並指出其中需要注意的事項。
這三個函數的基本流程如下:
初始化哈希上下文:
$context = hash_init('sha256');
多次更新數據:
hash_update($context, '部分數據1');
hash_update($context, '部分數據2');
獲取最終哈希值:
$hash = hash_final($context);
完整例子:
<?php
$context = hash_init('sha256');
hash_update($context, 'Hello ');
hash_update($context, 'World!');
$finalHash = hash_final($context);
echo "最終哈希值: " . $finalHash;
?>
1?? hash_final()調用後上下文不可再用
當你調用了:
$hash = hash_final($context);
上下文$context就被銷毀了,不能再用它繼續調用hash_update()或hash_final() ,否則會報錯。
如果你想在同一個數據流上繼續算其他哈希,你需要重新調用hash_init() 。
2??使用hash_copy()做分支
如果你需要在同一個上下文的基礎上得到多個分支結果,可以用hash_copy() :
$context = hash_init('sha256');
hash_update($context, '部分數據');
$copy = hash_copy($context);
hash_update($context, '後續A');
$hashA = hash_final($context);
hash_update($copy, '後續B');
$hashB = hash_final($copy);
這樣$hashA和$hashB就是不同分支的結果。
3??處理大文件時按塊更新
對於大文件,可以分塊讀取並調用hash_update() :
<?php
$context = hash_init('sha256');
$handle = fopen('largefile.bin', 'rb');
while (!feof($handle)) {
$chunk = fread($handle, 8192);
hash_update($context, $chunk);
}
fclose($handle);
$finalHash = hash_final($context);
echo "大文件哈希值: " . $finalHash;
?>
這樣避免了一次性讀取文件帶來的內存壓力。
4?? URL 場景下的使用
如果你是通過HTTP 請求流式處理數據,比如:
<?php
$url = 'https://gitbox.net/sample-file.bin';
$context = hash_init('sha256');
$handle = fopen($url, 'rb');
if ($handle) {
while (!feof($handle)) {
$chunk = fread($handle, 8192);
hash_update($context, $chunk);
}
fclose($handle);
$finalHash = hash_final($context);
echo "遠程文件哈希值: " . $finalHash;
} else {
echo "無法打開 URL。";
}
?>
要注意:確保allow_url_fopen在php.ini中是啟用的,否則fopen()無法直接打開URL。
5??選擇合適的算法
hash_init()的第一個參數是算法名,推薦使用sha256 、 sha512等現代算法,而不是老舊的md5或sha1 ,因為後者已不安全。