Strings7 min readExamples run on PHP 8.5.10

crc32()

Learn how PHP 8.4 crc32() computes a 32-bit checksum of a string, how to format it as decimal or hex, and where it should not be used.

Signature

crc32(string $string): int
Available since PHP 4.0.17.48.08.18.28.38.48.5All versions →

Purpose

crc32() calculates a 32-bit cyclic redundancy check (CRC) for a string of bytes. A CRC is a compact fingerprint that is mainly used to notice accidental changes, such as a corrupted transfer or a damaged record. If the same bytes go in, the same number comes out. If even one bit changes, the checksum will almost always change.

Signature

Parameters and defaults

Parameter Meaning
$string The data to checksum. It is processed as raw bytes.

There are no optional parameters and no defaults. Because PHP strings are byte sequences, a UTF-8 character such as é contributes several bytes to the checksum, not one character.

Return value and failure cases

The function returns the checksum as an int. On a 64-bit build of PHP, the result is always a non-negative integer between 0 and 4294967295. The manual warns that on 32-bit platforms the signed integer type can make many results negative, so portable code should format the value rather than rely on the raw integer.

The function has no "false on failure" result. The empty string is valid and produces 0. If you pass a value that cannot be used as a string, such as an array, PHP throws a TypeError. With declare(strict_types=1), passing an integer where a string is expected also throws a TypeError.

Example 1: Checksums of small strings

The same input always gives the same integer. The empty string gives 0, and "123456789" is the classic test string used for CRC-32 implementations.

Example
<?php
echo json_encode([crc32(""), crc32("hello"), crc32("123456789")]), "\n";
Output
[0,907060870,3421780262]

The output is [0,907060870,3421780262] followed by a newline.

Example 2: Decimal and hexadecimal formatting

The manual recommends %u for an unsigned decimal string and %x (or dechex()) for hexadecimal. Padding to eight digits keeps leading zeros, which matters when you compare with other tools. The manual also states that hash("crc32b", $str) returns the same string as the padded hexadecimal form of crc32().

Example
<?php
$data = "123456789";
$checksum = crc32($data);
echo sprintf("%u", $checksum), "\n";
echo sprintf("%08x", $checksum), "\n";
echo hash("crc32b", $data), "\n";
Output
3421780262
cbf43926
cbf43926

The three lines are 3421780262, cbf43926 and cbf43926.

Example 3: Detecting accidental changes

Store the checksum next to a message, then recompute it later and compare the integers with ===.

Example
<?php
$payload = "hello";
$expected = 907060870;
echo json_encode([
    "valid" => crc32($payload) === $expected,
    "tampered" => crc32("hellp") === $expected,
]), "\n";
Output
{"valid":true,"tampered":false}

The result is {"valid":true,"tampered":false}. The changed string differs from the original by a single bit, and a CRC is designed to detect that kind of small error.

Edge cases

  • Empty input: crc32("") returns 0, so a zero checksum does not mean "missing" or "failed".
  • Binary data: null bytes and non-text bytes are fine because the function works on bytes.
  • Encoding matters: the same visible text saved in different encodings has different bytes and therefore a different checksum.
  • Collisions exist: only about 4.29 billion values are possible, so different inputs can share a checksum. That is normal for any 32-bit value.
  • Platform differences: on 64-bit PHP the integer is positive, while the manual notes that 32-bit builds may show negative numbers. Format with %u or %x when you need a stable text form.

Common mistakes

  1. Using it for security. A CRC is not a cryptographic hash. It is easy to craft different data with the same checksum, so do not use it for passwords, signatures or tamper-proofing against an attacker.
  2. Printing with echo and expecting hex. echo crc32($s) prints a decimal integer. Use dechex() or sprintf("%08x", ...) for hex.
  3. Forgetting padding. dechex() drops leading zeros, so a checksum can come out shorter than eight characters. Pad it with str_pad() or sprintf() when comparing to a fixed-width value.
  4. Comparing mixed forms. Do not compare a decimal integer with a hex string. Convert both sides to the same representation first.
  5. Assuming all hash() CRC names match. The manual documents crc32b as the algorithm that matches PHP's crc32() hex output. Check the algorithm name before substituting.
  • hash() generates digests with many algorithms, including crc32b, and returns a hex string.
  • md5() and sha1() return longer digests. They are still not recommended for password storage, but they have a much larger output space than a CRC.
  • sprintf(), printf() and dechex() format the checksum for display.

Recap

crc32() turns a string's bytes into a 32-bit integer checksum that is good for catching accidental corruption. Format it deliberately with %u or %08x, remember that 0 is a valid result, and choose a stronger algorithm through hash() when security is a concern.

Tested examples

Checksums of small strings
<?php
echo json_encode([crc32(""), crc32("hello"), crc32("123456789")]), "\n";
Output
[0,907060870,3421780262]
Decimal and hexadecimal formatting
<?php
$data = "123456789";
$checksum = crc32($data);
echo sprintf("%u", $checksum), "\n";
echo sprintf("%08x", $checksum), "\n";
echo hash("crc32b", $data), "\n";
Output
3421780262
cbf43926
cbf43926
Detecting accidental changes
<?php
$payload = "hello";
$expected = 907060870;
echo json_encode([
    "valid" => crc32($payload) === $expected,
    "tampered" => crc32("hellp") === $expected,
]), "\n";
Output
{"valid":true,"tampered":false}