hash_file
Calculates the message digest of a file's contents using the chosen hashing algorithm.
hash_file(string $algo, string $filename, bool $binary = false, array $options = []): string|false- Added in PHP 5.1.2
Parameters
| Parameter | Type | Description |
|---|---|---|
$algo | string | Name of the hashing algorithm, for example "sha256". See hash_algos() for the supported list. |
$filename | string | Location of the file to be hashed. Supports fopen() stream wrappers. |
$binaryoptional | bool= false | When true, outputs raw binary data instead of lowercase hexits. |
$optionsoptional | array= [] | Algorithm-specific options. Currently only the "seed" key, used by the MurmurHash variants. |
Return value
string|falseThe digest as lowercase hexits, the raw binary digest when binary is true, or false on failure.
Errors
Throws a ValueError if algo is unknown. A missing or unreadable file returns false and emits an E_WARNING.
Changelog
- PHP 8.1.0The options parameter was added.
- PHP 8.0.0An unknown algo now throws a ValueError; previously false was returned with an E_WARNING.
hash_file() streams a file through the chosen algorithm and returns its digest. Crucially it reads the file in chunks, so hashing a 4 GB archive uses a few kilobytes of memory — unlike hash($algo, file_get_contents($path)), which loads the whole thing first and will hit memory_limit.
When to reach for it
Use it to verify a download against a published checksum, to detect that a file on disk changed since you last saw it, to deduplicate uploads by content rather than filename, and to build content-addressed storage where the digest is the filename.
What trips people up
The two failure modes look different and both bite. An unknown algorithm throws a ValueError since PHP 8.0. A missing or unreadable file returns false and emits a warning — it does not throw. So a plain if (!$hash) check catches the file problem but not the algorithm typo, and a try/catch catches the typo but not the missing file. Handle both.
Because $filename goes through the stream layer, a path that arrives from user input can reach wrappers you did not intend. Resolve and validate paths before passing them in. And remember that the digest covers file contents only: renaming, moving or touching a file leaves its hash unchanged.
Example
When to use it
- Verify a downloaded release archive against the sha256 checksum the vendor published.
- Skip re-processing an uploaded file whose digest already exists in the database.
- Detect tampering by comparing stored digests of config files against the files on disk.
Frequently asked questions
What is the difference between hash_file and hash(file_get_contents())?
They return the same digest, but hash_file() streams the file in chunks while file_get_contents() loads it entirely into memory. Use hash_file() for anything that might be large.
Does hash_file work on remote URLs?
It accepts any path the fopen() wrappers support, so http:// URLs work when allow_url_fopen is on. Never pass a user-supplied path straight through, since that lets a caller choose the wrapper.
Why does hash_file return false?
The file does not exist, is a directory, or cannot be read with the current permissions. An E_WARNING is emitted alongside the false return.
More examples
Verifying a published checksum
The first check passes; appending a single byte makes the second fail. hash_equals() is used rather than === because the published value may come from an untrusted channel.
<?php
file_put_contents('release.tar', str_repeat('payload', 100));
$published = hash_file('sha256', 'release.tar'); // pretend this came from the vendor
$actual = hash_file('sha256', 'release.tar');
var_dump(hash_equals($published, $actual));
file_put_contents('release.tar', str_repeat('payload', 100) . 'x');
var_dump(hash_equals($published, hash_file('sha256', 'release.tar')));
unlink('release.tar');Handling both failure modes
The three lines show the digest, the caught ValueError from a bad algorithm name, and the false return from a missing file — proving that the two error paths are genuinely different and both need handling.
<?php
file_put_contents('a.txt', 'data');
function safeHash(string $algo, string $file): string {
try {
$h = hash_file($algo, $file);
} catch (ValueError $e) {
return 'bad algorithm';
}
return $h === false ? 'unreadable file' : $h;
}
echo safeHash('sha256', 'a.txt'), PHP_EOL;
echo safeHash('nope', 'a.txt'), PHP_EOL;
echo safeHash('sha256', 'nofile.txt'), PHP_EOL;
unlink('a.txt');
Discussion