md5_file

Calculates the MD5 digest of a file's contents without loading the whole file into memory.

Signature
md5_file(string $filename, bool $binary = false): string|false
  • Added in PHP 4.2.0

Parameters

ParameterTypeDescription
$filenamestringPath of the file to hash. Supports fopen() stream wrappers.
$binaryoptionalbool= falseWhen 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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · php
<?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.

Example · php
<?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

  • Be the first to comment on this lesson.