當前位置: 首頁> 最新文章列表> 與數據庫結合:記錄文件哈希以供後續驗證

與數據庫結合:記錄文件哈希以供後續驗證

M66 2025-06-05

在PHP 中,我們可以通過hash_update_stream來計算大文件的哈希值,以確保文件的完整性。結合數據庫記錄文件哈希,可以在後續驗證文件的完整性時,迅速對比文件的哈希值,確保文件沒有被篡改。本文將詳細講解如何實現這一過程。

一、 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 ,我們可以將文件的哈希值計算結果流式存儲到數據庫中。驗證時,我們只需要重新計算文件的哈希值,並與數據庫中存儲的值進行比對,從而實現文件完整性驗證。

以下是整個流程的簡要步驟:

  1. 上傳文件時,計算文件的哈希值並存入數據庫。

  2. 驗證文件時,從數據庫中讀取哈希值並與新計算的哈希值進行比對。

  3. 若兩者匹配,表示文件未被篡改;否則,文件的完整性受到質疑。

三、實現步驟

1. 數據庫結構設計

首先,設計一個簡單的數據庫表,用於記錄文件信息及其哈希值。我們假設數據庫中已有一個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記錄上傳時間。

2. 上傳文件時計算哈希值並保存

當用戶上傳文件時,我們將文件流傳遞給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()獲取哈希值並存入數據庫。

3. 驗證文件完整性

在後續的驗證過程中,我們可以根據文件名從數據庫中獲取對應的哈希值,並與當前文件的哈希值進行比對。

 <?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和數據庫記錄文件哈希值的方式,我們能夠高效地進行文件完整性驗證。無論是上傳文件時還是後續驗證,流式哈希計算能夠有效減少內存佔用,同時數據庫中的哈希記錄為後續驗證提供了可靠的數據支持。