在PHP 中,我們可以通過hash_update_stream來計算大文件的哈希值,以確保文件的完整性。結合數據庫記錄文件哈希,可以在後續驗證文件的完整性時,迅速對比文件的哈希值,確保文件沒有被篡改。本文將詳細講解如何實現這一過程。
hash_update_stream函數用於從一個文件流中計算哈希值。相比一次性加載文件到內存的方式,使用流式處理能夠有效節省內存,特別適合處理大文件。
bool hash_update_stream ( resource $context , resource $handle [, int $length ] )
$context :通過hash_init()初始化的哈希上下文。
$handle :一個有效的文件句柄。
$length (可選):一次讀取的字節數,默認為8192字節。
該函數通常與hash_init()和hash_final()一起使用,後者用於返回最終計算的哈希值。
通過使用hash_update_stream ,我們可以將文件的哈希值計算結果流式存儲到數據庫中。驗證時,我們只需要重新計算文件的哈希值,並與數據庫中存儲的值進行比對,從而實現文件完整性驗證。
以下是整個流程的簡要步驟:
上傳文件時,計算文件的哈希值並存入數據庫。
驗證文件時,從數據庫中讀取哈希值並與新計算的哈希值進行比對。
若兩者匹配,表示文件未被篡改;否則,文件的完整性受到質疑。
首先,設計一個簡單的數據庫表,用於記錄文件信息及其哈希值。我們假設數據庫中已有一個files表,結構如下:
CREATE TABLE `files` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`filename` VARCHAR(255) NOT NULL,
`hash` CHAR(64) NOT NULL,
`uploaded_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
filename存儲文件名, hash存儲文件的哈希值, uploaded_at記錄上傳時間。
當用戶上傳文件時,我們將文件流傳遞給hash_update_stream來計算文件的哈希值,並將文件名及其哈希值存入數據庫。
<?php
// 假設文件上傳處理
if (isset($_FILES['file'])) {
// 獲取上傳文件的信息
$fileTmpPath = $_FILES['file']['tmp_name'];
$fileName = $_FILES['file']['name'];
// 初始化哈希計算
$hashContext = hash_init('sha256');
// 打開文件流
$fileHandle = fopen($fileTmpPath, 'rb');
// 計算哈希值
while (!feof($fileHandle)) {
// 更新哈希
hash_update_stream($hashContext, $fileHandle);
}
// 獲取最終哈希值
$fileHash = hash_final($hashContext);
// 將哈希值存入數據庫
$db = new mysqli('localhost', 'root', '', 'file_db');
$stmt = $db->prepare("INSERT INTO files (filename, hash) VALUES (?, ?)");
$stmt->bind_param("ss", $fileName, $fileHash);
$stmt->execute();
// 關閉文件句柄
fclose($fileHandle);
}
?>
在這個例子中,我們使用hash_init()初始化一個SHA-256 的哈希上下文,然後通過hash_update_stream()來計算上傳文件的哈希值,最終使用hash_final()獲取哈希值並存入數據庫。
在後續的驗證過程中,我們可以根據文件名從數據庫中獲取對應的哈希值,並與當前文件的哈希值進行比對。
<?php
// 假設文件驗證處理
$fileNameToVerify = 'example_file.txt'; // 假設需要驗證的文件名
$filePath = '/path/to/files/' . $fileNameToVerify;
// 獲取數據庫中的哈希值
$db = new mysqli('localhost', 'root', '', 'file_db');
$stmt = $db->prepare("SELECT hash FROM files WHERE filename = ?");
$stmt->bind_param("s", $fileNameToVerify);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$storedHash = $row['hash'];
// 計算當前文件的哈希值
$hashContext = hash_init('sha256');
$fileHandle = fopen($filePath, 'rb');
while (!feof($fileHandle)) {
hash_update_stream($hashContext, $fileHandle);
}
$currentHash = hash_final($hashContext);
fclose($fileHandle);
// 比較數據庫中的哈希值與當前計算的哈希值
if ($currentHash === $storedHash) {
echo "文件完整性驗證通過!";
} else {
echo "文件完整性驗證失敗!";
}
?>
在驗證時,我們首先從數據庫中獲取文件的哈希值,然後重新計算文件的哈希值,最後進行比對。如果兩個哈希值一致,說明文件未被修改;如果不一致,文件可能已被篡改。
通過結合hash_update_stream和數據庫記錄文件哈希值的方式,我們能夠高效地進行文件完整性驗證。無論是上傳文件時還是後續驗證,流式哈希計算能夠有效減少內存佔用,同時數據庫中的哈希記錄為後續驗證提供了可靠的數據支持。