Library

Password Hashing

Store a password as a salted hash, with a pepper from app config. This is not reversible encryption.

PHP Free to use
Code
final class PasswordHasher
{
    public function __construct(
        private readonly string $pepper,
        private readonly string $algo = PASSWORD_DEFAULT,
        private readonly array $options = [],
    ) {
        if ($this->pepper === '') {
            throw new InvalidArgumentException('Pepper must not be empty.');
        }
    }

    public function hash(string $password): string
    {
        if ($password === '') {
            throw new InvalidArgumentException('Password must not be empty.');
        }

        $hash = password_hash($this->season($password), $this->algo, $this->options);
        if ($hash === false) {
            throw new RuntimeException('Could not hash the password.');
        }

        return $hash;
    }

    public function verify(string $password, string $hash): bool
    {
        if ($password === '' || $hash === '' || ! str_starts_with($hash, '$')) {
            return false;
        }

        return password_verify($this->season($password), $hash);
    }

    public function needsRehash(string $hash): bool
    {
        return password_needs_rehash($hash, $this->algo, $this->options);
    }

    private function season(string $password): string
    {
        return hash_hmac('sha256', $password, $this->pepper, true);
    }
}
Quick try
$hasher = new PasswordHasher($_ENV['APP_PEPPER'] ?? '');

$hash = $hasher->hash($password);

if (! $hasher->verify($password, $hash)) {
    throw new RuntimeException('Invalid password.');
}

if ($hasher->needsRehash($hash)) {
    $user->password = $hasher->hash($password);
}

What it does

  • password_hash creates the salt and stores it inside the hash. Do not add an unused custom salt.
  • Keep the pepper in the environment, not in the database. If it is lost, old passwords cannot be verified.
  • password_verify is constant-time. After a successful login, call needsRehash if the algorithm or its options changed.

Where it fits

A practical place for this snippet in a real project.

Useful for storing a user password and checking it at login. It is not for encrypting files or API tokens.

Similar snippets

Token Bucket
PHP

Token Bucket

Allow a short burst, then refill tokens at a steady rate. The burst cannot exceed the bucket size.

Connection Pool
PHP

Connection Pool

Reuse an idle connection inside the same process, instead of opening a new one for every query.

تحتاج مقتطفاً غير موجود؟

صف المشكلة أو الفكرة، وسأرى إن كان مناسباً إضافته للمكتبة.