Strings7 min readExamples run on PHP 8.5.10

sha1()

Learn how PHP sha1() computes a SHA-1 digest, how the binary flag changes the result, and why it is unsuitable for password storage.

Signature

sha1(string $string, bool $binary = false): string
Available since PHP 4.3.07.48.08.18.28.38.48.5All versions →

Purpose

sha1() calculates the SHA-1 digest of a string. A digest is a fixed-size fingerprint: the same input always gives the same output, and a tiny change in the input produces a completely different digest. Typical uses are building cache keys, comparing content against a known checksum, or interoperating with an older system that still publishes SHA-1 values.

The PHP manual warns that sha1() should not be used to secure passwords, because the algorithm is fast, which makes guessing attacks cheap. For passwords, use password_hash() and password_verify() instead.

Signature

Parameters and defaults

  • $string is the input. PHP strings are byte sequences, so the digest is computed over the raw bytes. A UTF-8 string and the same text in another encoding produce different digests.
  • $binary defaults to false. With false you get a 40-character lowercase hexadecimal string. With true you get the raw digest, which is exactly 20 bytes long and usually not printable.

Return value and failure cases

The function always returns a string. There is no false return and no error value for ordinary string input, including the empty string. The only failures come from PHP's type rules: passing an array or an object without a string conversion throws a TypeError, and under declare(strict_types=1) passing an integer also throws instead of being converted to a string.

Example 1: hexadecimal digests

The default output is easy to print, log or store. Even an empty string has a well-defined digest.

Example
<?php
echo sha1('abc'), "\n";
echo sha1(''), "\n";
Output
a9993e364706816aba3e25717850c26c9cd0d89d
da39a3ee5e6b4b0d3255bfef95601890afd80709

Example 2: comparing against a stored checksum

When you compare a computed digest with a known value, use hash_equals(). It compares in constant time, which avoids leaking information about where two strings first differ. This matters most when the known value is secret-adjacent, such as a token.

Example
<?php
$stored = 'd0be2dc421be4fcd0172e5afceea3970e2f3d940';
$input = 'apple';
echo json_encode(['match' => hash_equals($stored, sha1($input)), 'length' => strlen(sha1($input))]);
Output
{"match":true,"length":40}

Example 3: raw binary output

The raw form is half the size of the hex form because each byte is shown as two hex characters. Use bin2hex() to convert it back to readable text.

Example
<?php
$raw = sha1('abc', true);
echo json_encode(['rawLength' => strlen($raw), 'hex' => bin2hex($raw), 'same' => bin2hex($raw) === sha1('abc')]);
Output
{"rawLength":20,"hex":"a9993e364706816aba3e25717850c26c9cd0d89d","same":true}

Edge cases

  • Empty string: it is valid input and returns the fixed digest da39a3ee5e6b4b0d3255bfef95601890afd80709.
  • Binary data: strings with null bytes or invalid UTF-8 are fine, because the function reads bytes, not characters.
  • Numbers: an integer is converted to its decimal string when strict typing is off, so sha1(123) hashes the text 123. Be explicit with a cast or a string literal if you want to avoid surprises.
  • Whitespace and case: 'apple', 'Apple' and 'apple ' all have different digests. Normalize input before hashing if your application treats them as equal.
  • Output case: the hex result is lowercase. If you receive an uppercase checksum from elsewhere, lowercase it before comparing.

Common mistakes

  1. Hashing passwords with it. A plain fast hash without a per-user salt and a deliberately slow algorithm is a poor fit for credentials. Use password_hash().
  2. Treating a hash as encryption. A digest cannot be reversed by design, so you cannot recover the original text from it. It is also not a way to hide small, guessable inputs, since an attacker can hash candidates and compare.
  3. Comparing with == or === for secrets. Ordinary comparison is not constant time. Use hash_equals() with the known value as the first argument.
  4. Assuming the binary flag gives readable text. The raw result may contain control characters. Do not echo it into HTML or JSON without encoding it, for example with bin2hex() or base64_encode().
  5. Storing the raw digest in a text column. The 20 bytes may not survive a text encoding. Store the 40-character hex form, or use a binary column.
  6. Choosing it for new security designs. If you are free to choose an algorithm, hash() lets you pick a different one, such as sha256, with the same basic call style.
  • hash() generates digests with many algorithms, selected by name.
  • password_hash() and password_verify() are the right tools for password storage.
  • hash_equals() performs timing-safe string comparison.
  • bin2hex() converts raw bytes to hexadecimal text.
  • md5() and crc32() are other quick checksum functions with their own trade-offs.

Recap

sha1() turns a string into a 40-character hex digest, or a 20-byte raw digest when $binary is true. It is deterministic and accepts any bytes, including an empty string. Compare results with hash_equals(), and never rely on it to protect passwords.

Tested examples

Hexadecimal digests of a short string and an empty string
<?php
echo sha1('abc'), "\n";
echo sha1(''), "\n";
Output
a9993e364706816aba3e25717850c26c9cd0d89d
da39a3ee5e6b4b0d3255bfef95601890afd80709
Comparing a computed digest with a stored checksum using hash_equals()
<?php
$stored = 'd0be2dc421be4fcd0172e5afceea3970e2f3d940';
$input = 'apple';
echo json_encode(['match' => hash_equals($stored, sha1($input)), 'length' => strlen(sha1($input))]);
Output
{"match":true,"length":40}
Raw binary digest length and its hexadecimal form
<?php
$raw = sha1('abc', true);
echo json_encode(['rawLength' => strlen($raw), 'hex' => bin2hex($raw), 'same' => bin2hex($raw) === sha1('abc')]);
Output
{"rawLength":20,"hex":"a9993e364706816aba3e25717850c26c9cd0d89d","same":true}