md5
Calculates the MD5 message digest of a string and returns it as 32 hexadecimal characters.
md5(string $string, bool $binary = false): string- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$string | string | The data to hash. Binary safe — any byte sequence is accepted. |
$binaryoptional | bool= false | When true, returns the digest as 16 raw bytes instead of 32 hexits. |
Return value
stringThe 32-character lowercase hexadecimal digest, or the raw 16-byte binary digest when binary is true.
Errors
Nothing. md5() has no error conditions; every string produces a digest.
md5() runs the RFC 1321 MD5 algorithm over a string and hands back a fixed 128-bit digest. The same input always produces the same output, and a single changed byte changes roughly half the output bits.
When to reach for it
Use it for non-security fingerprinting: cache keys, ETag values, detecting that a file or config blob changed, deduplicating rows, or building a deterministic bucket for sharding. It is fast and its 32-character output fits neatly in a CHAR(32) column.
What trips people up
MD5 is broken for anything adversarial. Chosen-prefix collisions are cheap, so never use it to verify a download's authenticity, sign a payload, or store a password. For passwords use password_hash(); for signatures use hash_hmac(); for integrity against an attacker use hash('sha256', ...).
The second gotcha is $binary. Passing true gives you 16 raw bytes that will corrupt JSON, break UTF-8 validation and get mangled by a VARCHAR column. Only use it when you are about to base64_encode() or store in a BINARY(16) field.
Comparing digests with == is also a trap, and PHP 8 did not close it. The 8.0 change only affected comparing a number with a non-numeric string; two numeric strings are still compared as numbers, so "0e1" == "000" is still true. Two MD5 digests that both look like scientific notation — 0e followed only by digits — therefore compare equal under ==. Always use ===, or hash_equals() when one side is user-supplied.
Example
When to use it
- Build a cache key from a serialized set of query parameters.
- Detect whether an uploaded file duplicates one already stored.
- Generate a deterministic avatar URL from an email address (Gravatar-style).
Frequently asked questions
Is md5 safe for storing passwords?
No. MD5 is designed to be fast, which is exactly wrong for passwords — a modern GPU tries billions of candidates per second. Use password_hash() with the default algorithm and verify with password_verify().
What is the difference between md5 and hash('md5', ...)?
They produce the same digest; hash() is just the generic entry point that also accepts sha256, xxh3 and dozens of others. Use hash() when the algorithm name is a variable or config value.
Can md5 be reversed or decrypted?
Not by design — it is a one-way digest that throws information away. Short or common inputs can still be recovered from precomputed rainbow tables, which is another reason not to use it on secrets.
More examples
A stable cache key from mixed input
The first two lines print the identical digest because ksort() normalises key order before encoding. The third differs entirely, showing that one changed value produces a completely unrelated digest.
<?php
function cacheKey(array $params): string {
ksort($params); // order must not affect the key
return md5(json_encode($params));
}
echo cacheKey(['page' => 2, 'sort' => 'name']), PHP_EOL;
echo cacheKey(['sort' => 'name', 'page' => 2]), PHP_EOL;
echo cacheKey(['page' => 3, 'sort' => 'name']), PHP_EOL;Shortening a digest into buckets
Each username maps to a fixed shard number. Because MD5 spreads inputs evenly, the buckets stay balanced, and the same username always lands on the same shard across requests and servers.
<?php
$shards = 4;
foreach (['alice', 'bob', 'carol', 'dave'] as $user) {
$digest = md5($user);
$bucket = hexdec(substr($digest, 0, 8)) % $shards;
echo str_pad($user, 6), substr($digest, 0, 8), " -> shard $bucket", PHP_EOL;
}
Discussion