当前位置: 首页> 最新文章列表> 与数据库结合:记录文件哈希以供后续验证

与数据库结合:记录文件哈希以供后续验证

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 和数据库记录文件哈希值的方式,我们能够高效地进行文件完整性验证。无论是上传文件时还是后续验证,流式哈希计算能够有效减少内存占用,同时数据库中的哈希记录为后续验证提供了可靠的数据支持。