md5_file
Calculates the MD5 digest of a file's contents without loading the whole file into memory.
md5_file(string $filename, bool $binary = false): string|false- Added in PHP 4.2.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$filename | string | Path of the file to hash. Supports fopen() stream wrappers. |
$binaryoptional | bool= false | When true, returns the digest as 16 raw bytes instead of 32 hexits. |
Return value
string|falseThe 32-character hexadecimal digest, the raw 16-byte digest when binary is true, or false on failure.
Errors
Does not throw. Returns false and emits an E_WARNING when the file cannot be read.
md5_file() reads a file in chunks and returns the MD5 digest of its contents. It is the memory-safe equivalent of md5(file_get_contents($path)) — a multi-gigabyte file hashes in constant memory rather than blowing past memory_limit.
When to reach for it
Use it for non-adversarial file identity: spotting that an upload duplicates something already stored, checking whether a cached asset needs regenerating, matching against a checksum list published in MD5 form, or building a quick manifest of a directory's contents.
What trips people up
Failure is signalled by false, not an exception, and it comes with an E_WARNING that is easy to miss in production. A missing file, a directory, or a permissions problem all look the same. Check the return value explicitly with === false, because a legitimate digest is never falsy but a lazy if (!$hash) reads fine and hides the reason.
Two files with identical contents give identical digests regardless of name, path, timestamp or permissions — that is usually the point, but it means md5_file() cannot tell you a file was touched, only that its bytes changed.
For security-relevant verification, MD5 is not enough: use hash_file('sha256', ...), since MD5 collisions can be manufactured deliberately.
Example
When to use it
- Detect that an uploaded image is byte-identical to one already in storage.
- Compare a local file against a vendor's published MD5 checksum list.
- Build a manifest so a sync job only re-uploads files whose contents changed.
Frequently asked questions
What is the difference between md5_file and md5(file_get_contents())?
They produce the same digest, but md5_file() streams the file so memory use stays flat. Use it for anything larger than a few megabytes.
Why does md5_file return false?
The path does not exist, points at a directory, or is not readable by the PHP process. An E_WARNING accompanies the false return.
Is md5_file good enough to verify a download?
Only against accidental corruption. MD5 collisions can be constructed deliberately, so use hash_file('sha256', ...) when an attacker could have swapped the file.
More examples
Finding duplicate files by content
b.txt is flagged as a duplicate of a.txt because their contents are identical, while c.txt gets its own digest. Filenames play no part in the comparison.
<?php
file_put_contents('a.txt', 'same content');
file_put_contents('b.txt', 'same content');
file_put_contents('c.txt', 'different');
$seen = [];
foreach (['a.txt', 'b.txt', 'c.txt'] as $f) {
$h = md5_file($f);
echo $f, ' ', $h, isset($seen[$h]) ? " duplicate of {$seen[$h]}" : '', PHP_EOL;
$seen[$h] ??= $f;
}
array_map('unlink', ['a.txt', 'b.txt', 'c.txt']);Detecting a content change
Touching the file leaves the digest unchanged; editing one byte changes it. This is why content hashing is more reliable than modification-time checks for cache invalidation.
<?php
file_put_contents('config.ini', "debug=0\n");
$before = md5_file('config.ini');
touch('config.ini'); // only the mtime changed
var_dump($before === md5_file('config.ini'));
file_put_contents('config.ini', "debug=1\n");
var_dump($before === md5_file('config.ini'));
unlink('config.ini');
Discussion