Skip to content
AldeaCode Logo
Hash Generator / PHP Developer 100% local

Generate hashes in PHP: hash(), hash_file(), hash_hmac(), and password_hash()

PHP ships everything you need for hashing in the standard library. The hash() function takes an algorithm name and a string, returns hex. The trap is using it for passwords, which is not what it is for.

hash() is the general-purpose function

hash($algo, $data) returns the hex digest of $data under $algo. The first argument is a string name from the algorithm registry: 'sha256', 'sha1', 'md5', 'sha3-256', 'xxh3', and dozens more. hash_algos() returns the full list available on your build of PHP. The list grew significantly with PHP 8.1, which added xxh32, xxh64, and xxh3.

Pass a third argument true to get raw bytes instead of hex. This matters when you are feeding the digest into another binary protocol or when the hex doubles your storage. For HTTP headers and database columns, leave it at the default and store the hex string.

hash() is fast, allocator-free for small inputs, and the right tool for content addressing, integrity checks, ETag generation, and cache keys. It is the wrong tool for passwords.

Never use md5 or sha1 for passwords

MD5 and SHA-1 are designed to be fast. Modern GPUs compute billions of MD5 hashes per second. A leaked database of MD5 password hashes is a leaked database of plaintext passwords by the time the attacker finishes their coffee. SHA-256 is slower per hash but still fast enough that GPU brute force breaks any password under twelve characters in a few hours.

Password hashing needs a slow, memory-hard function: bcrypt, scrypt, or argon2. PHP's password_hash() wraps these and picks bcrypt by default, with argon2id available via PASSWORD_ARGON2ID. The function generates its own salt, encodes the algorithm and parameters into the result, and password_verify() reads them back. You never store the salt yourself, you never pick the cost yourself unless you have benchmarked the target hardware.

If you see code that calls hash('sha256', $password . $salt) to store a password, replace it. The fix is a one-time migration: on next login, verify against the old hash, then re-hash with password_hash() and overwrite the column.

hash_hmac() for authenticated hashes

An HMAC binds a hash to a secret key. Used for webhook signatures, API request signing, and any place you need to prove a message came from someone holding the shared secret. The signature is hash_hmac($algo, $data, $key).

The key argument is the shared secret as a raw string. Do not hex-encode it before passing in unless the spec you are implementing says to. GitHub webhooks pass the secret directly. Stripe webhooks pass the secret directly. Misencoding the key produces a valid-looking but wrong signature, and you will spend an hour wondering why verification fails.

Compare the result with hash_equals(), never with ==. The double-equals operator short-circuits on the first byte mismatch, leaks timing information, and lets a remote attacker reconstruct the signature byte by byte over a few thousand requests. hash_equals() is constant-time.

hash_file() for files without loading them

For multi-gigabyte files, calling hash('sha256', file_get_contents($path)) allocates the entire file in memory. hash_file($algo, $path) streams the file in fixed-size chunks and produces the same digest with constant memory.

Use it for upload integrity, dedup keys, and content addressing. The hex digest is identical whether you compute it in PHP, in OpenSSL, or in sha256sum on the command line, so cross-system verification works without coordination.

Working example

php
<?php
// 1. SHA-256 of a string (hex)
$digest = hash('sha256', 'hello world');
echo $digest, "\n";

// 2. SHA-256 of a file, streamed
$fileDigest = hash_file('sha256', '/path/to/upload.bin');
echo $fileDigest, "\n";

// 3. HMAC for webhook signature verification
$expected = hash_hmac('sha256', $rawBody, $sharedSecret);
if (!hash_equals($expected, $signatureFromHeader)) {
    http_response_code(401);
    exit('Bad signature');
}

// 4. Passwords: bcrypt by default, argon2id available
$hash = password_hash($plain, PASSWORD_BCRYPT, ['cost' => 12]);

if (password_verify($attempt, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12])) {
        $hash = password_hash($attempt, PASSWORD_BCRYPT, ['cost' => 12]);
        // persist new $hash
    }
}

Just need the result?

When you need a quick sha256 of a string for a config file or a webhook test, paste the input into the hash generator at aldeacode.com. The page computes md5, sha1, sha256, sha384, and sha512 in your browser at the same time, no upload, no network round-trip.

Open SHA Hash Generator →

Frequently asked questions

Which hash algorithm should I use in PHP for non-password data?

SHA-256 for almost everything. xxh3 if you only need a non-cryptographic hash for in-memory dedup or cache keys and want speed. MD5 only when a legacy spec mandates it.

Why does password_hash() produce a different output every time?

It generates a fresh random salt for each call. The salt is embedded in the output string, so password_verify() can read it back. This is the desired behavior; identical hashes for identical passwords would defeat the salting.

How do I list the algorithms available on my PHP build?

Call hash_algos() and var_dump the result. The list depends on the OpenSSL build PHP was compiled against. SHA-256, SHA-1, and MD5 are always present; SHA-3 needs PHP 7.1+; xxh3 needs PHP 8.1+.