Hash init: примеры (PHP)

Инкрементальное хеширование через hash_init в PHP
Раздел: Хеширование и шифрование
hash_init(string $algo, int $flags = 0, string $key = "", array $options = []): HashContext

Функция hash_init инициализирует инкрементальный контекст хеширования. Она используется, когда данные для хеширования поступают частями, а не целиком. Это эффективно для обработки больших файлов или потоков данных без необходимости загружать их полностью в память.

Аргументы функции
  • algo (string): Имя выбранного алгоритма хеширования (например, 'md5', 'sha256', 'sha3-512'). Список доступных алгоритмов можно получить с помощью функции hash_algos().
  • flags (int): Необязательные флаги, изменяющие поведение функции.
    • HASH_HMAC: При использовании этого флага требуется дополнительный аргумент key. Позволяет вычислять HMAC (Hash-based Message Authentication Code).
  • key (string): Необязательный ключ для HMAC. Требуется, если установлен флаг HASH_HMAC. Если флаг установлен, но ключ не передан, будет выброшено исключение.
Простые примеры использования
Пример 1: Базовое использование

Хеширование строки по частям.

<?php
$context = hash_init('sha256');
hash_update($context, 'Hello, ');
hash_update($context, 'world!');
$result = hash_final($context);
echo $result;
?>
315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
Пример 2: Использование с HMAC

Вычисление HMAC для аутентификации сообщения.

<?php
$key = 'secret-key';
$context = hash_init('sha256', HASH_HMAC, $key);
hash_update($context, 'Важное сообщение');
$hmac = hash_final($context);
echo $hmac;
?>
9e0e5f9c7c2a1e5b8b5d9f8a2c3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2
Похожие функции в PHP

В PHP существуют другие функции для работы с хешами:

  • hash(): Вычисляет хеш из строки целиком. Используется, когда все данные уже находятся в памяти. Проще в использовании, но не подходит для потоковой обработки.
  • hash_file(): Вычисляет хеш-сумму файла. Удобна для работы с файлами, но также требует указания полного пути. Внутри может использовать механизм, схожий с hash_init.
  • md5(), sha1(): Устаревшие функции для конкретных алгоритмов. Не поддерживают инкрементальное хеширование и менее безопасны для современных задач. Рекомендуется использовать hash() или hash_init с современными алгоритмами (SHA-2, SHA-3).

hash_init предпочтительнее использовать при потоковой обработке данных или работе с большими объемами информации.

Аналоги в других языках
Python (модуль hashlib)
import hashlib
# Инкрементальное хеширование
hasher = hashlib.sha256()
hasher.update(b'Hello, ')
hasher.update(b'world!')
result = hasher.hexdigest()
print(result)  # 315f5bdb...
# HMAC (отдельный модуль hmac)
import hmac
hmac_digest = hmac.new(b'secret-key', b'Важное сообщение', hashlib.sha256).hexdigest()
print(hmac_digest)
JavaScript (Node.js, crypto модуль)
const crypto = require('crypto');
// Инкрементальное хеширование
const hash = crypto.createHash('sha256');
hash.update('Hello, ');
hash.update('world!');
let result = hash.digest('hex');
console.log(result); // 315f5bdb...
// HMAC
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('Важное сообщение');
let hmacResult = hmac.digest('hex');
console.log(hmacResult);

Hash init в MySQL

Функции хеширования в MySQL, такие как SHA2(), работают только с готовыми данными. Инкрементальное хеширование на уровне запросов не поддерживается.

SELECT SHA2('Hello, world!', 256);
-- Результат: 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
Распространенные ошибки
1. Передача неверного имени алгоритма
<?php
$context = hash_init('неизвестный_алгоритм');
?>
Warning: hash_init(): Unknown hashing algorithm: неизвестный_алгоритм
2. Отсутствие ключа при использовании HASH_HMAC
<?php
$context = hash_init('sha256', HASH_HMAC);
?>
Warning: hash_init(): HMAC requested without a key
3. Попытка обновления или финализации неверного ресурса/объекта
<?php
$context = null;
hash_update($context, 'data');
?>
TypeError: hash_update(): Argument #1 ($context) must be of type HashContext, null given
4. Использование результата hash_final() для обновлений
<?php
$ctx = hash_init('md5');
hash_update($ctx, 'test');
$result = hash_final($ctx);
// Контекст $ctx теперь недействителен
hash_update($ctx, 'more'); // Ошибка
?>
Fatal error: Uncaught TypeError: hash_update(): Argument #1 ($context) must be of type HashContext, bool given
Изменения в последних версиях PHP
  • В PHP 8.0 типичные предупреждения при передаче неверных аргументов (например, неизвестный алгоритм) были преобразованы в исключение ValueError.
  • Начиная с PHP 8.1.0, возвращаемый тип изменился с resource на объект HashContext. Это изменение направлено на устранение устаревших ресурсов.
<?php
// До PHP 8.1
// $context = hash_init(...) возвращал ресурс (resource)
// С PHP 8.1
$context = hash_init('sha256');
var_dump($context);
?>
object(HashContext)#1 (0) {
}
Расширенные примеры применения
Обработка большого файла по частям
Пример php
<?php
function getFileHash($filename, $algorithm = 'sha256') {
    if (!file_exists($filename)) {
        throw new Exception("Файл не найден.");
    }
    $handle = fopen($filename, 'rb');
    if (!$handle) {
        throw new Exception("Не удалось открыть файл.");
    }
    $context = hash_init($algorithm);
    while (!feof($handle)) {
        $chunk = fread($handle, 8192); // Чтение по 8 КБ
        hash_update($context, $chunk);
    }
    fclose($handle);
    return hash_final($context);
}
// Использование
echo getFileHash('large_video.mp4', 'sha3-512');
?>
Сравнение файлов без загрузки в память
Пример php
<?php
function areFilesIdentical($file1, $file2) {
    $ctx1 = hash_init('sha256');
    $ctx2 = hash_init('sha256');
    $fh1 = fopen($file1, 'rb');
    $fh2 = fopen($file2, 'rb');
    while (!feof($fh1) && !feof($fh2)) {
        hash_update($ctx1, fread($fh1, 4096));
        hash_update($ctx2, fread($fh2, 4096));
    }
    fclose($fh1);
    fclose($fh2);
    return hash_final($ctx1) === hash_final($ctx2);
}
?>
Построение дерева Меркла (упрощенный пример)
Пример php
<?php
function merkleLeafHash($data) {
    return hash('sha256', $data, true); // raw_output = true
}
function merkleParentHash($left, $right) {
    $context = hash_init('sha256');
    hash_update($context, $left);
    hash_update($context, $right);
    return hash_final($context, true);
}
// Пример с двумя блоками данных
$leaf1 = merkleLeafHash('Транзакция 1');
$leaf2 = merkleLeafHash('Транзакция 2');
$root = merkleParentHash($leaf1, $leaf2);
echo bin2hex($root);
?>

PHP hash_init function comments

En
Hash init Initialize an incremental hashing context