Strings7 min readExamples run on PHP 8.5.10

hex2bin()

Learn how PHP 8.4 hex2bin() decodes a hexadecimal string into raw bytes, when it returns false, and how to validate input first.

Signature

hex2bin(string $string): string|false
Available since PHP 5.4.07.48.08.18.28.38.48.5All versions →

Purpose

hex2bin() turns a string of hexadecimal digits back into the raw bytes those digits describe. Every pair of hex characters becomes one byte, so "48" becomes the single character H. It is the inverse of bin2hex(), and it is commonly used for tokens, hashes, keys and binary identifiers that are stored or transmitted as readable text.

The name is easy to misread. The function does not convert a hexadecimal number into a binary number such as 11111111. It decodes hex-encoded data into a byte string. If you want number-base conversion, use base_convert() instead.

Signature

The function is available in PHP 5.4 and later, including PHP 8.4.

Parameters and defaults

  • $string: the hexadecimal representation of the data. It has no default, so it is required.

The input must contain an even number of characters, and each character must be a hexadecimal digit (0-9, a-f or A-F). Upper and lower case may be mixed. Spaces, a 0x prefix, colons and other separators are not hex digits, so they make the input invalid.

Return value and failure cases

On success the function returns a string of raw bytes. The result is half as long as the input. That string may contain bytes that are not printable or not valid UTF-8, so be careful when you echo it or pass it to functions that expect text.

On failure the function returns false and raises an E_WARNING. Two situations trigger this:

  • the input has an odd length;
  • the input contains a character that is not a hexadecimal digit.

Because a warning is emitted, untrusted input should be checked before decoding, or the failure must be handled deliberately.

Example 1: decoding readable text

The hex below spells out an ASCII sentence. var_dump() shows both the byte length and the content.

Example
<?php
$text = hex2bin("6578616d706c65206865782064617461");
var_dump($text);
Output
string(16) "example hex data"

The 32 hex characters become 16 bytes.

Example 2: working with non-printable bytes

Decoded data does not have to be text. Here the bytes are 0x00, 0xFF and 0x10. Inspecting them with strlen(), unpack() and bin2hex() is safer than echoing the raw string.

Example
<?php
$bytes = hex2bin("00ff10");
echo strlen($bytes), "\n";
echo json_encode(array_values(unpack("C*", $bytes))), "\n";
echo bin2hex($bytes), "\n";
Output
3
[0,255,16]
00ff10

The round trip through bin2hex() restores the original lowercase hex.

Example 3: validating before decoding

A small wrapper can reject bad input without triggering a warning. It checks for an empty value, odd length and non-hex characters, and returns null when the input cannot be decoded. Rejecting an empty string is a choice made by this wrapper, not a rule of hex2bin().

Example
<?php
function decodeHex(string $hex): ?string {
    if ($hex === '' || strlen($hex) % 2 !== 0 || !ctype_xdigit($hex)) {
        return null;
    }
    return hex2bin($hex);
}
echo json_encode([
    decodeHex("486921"),
    decodeHex("abc"),
    decodeHex("zz"),
    decodeHex("4A4b"),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["Hi!",null,null,"JK"]

Mixed-case input such as 4A4b is accepted.

Edge cases

  • Odd length: "abc" cannot be split into whole bytes, so decoding fails.
  • Prefixes and separators: "0xff", "ff ff" and "ff:ff" are all invalid. Strip or normalize them yourself first.
  • Case: "FF" and "ff" decode to the same byte.
  • Binary results: the returned string may hold null bytes or invalid UTF-8. Functions such as json_encode() can refuse such data, so encode it again (for example with bin2hex()) before showing or storing it as text.
  • Strict comparison: always compare the result with === false, since a valid result is a string.

Common mistakes

  1. Expecting a base conversion. hex2bin("ff") returns one byte with value 255, not the text "11111111". Use base_convert() for number bases.
  2. Ignoring false. Passing the result straight into other code can hide a decoding failure. Check it explicitly.
  3. Suppressing warnings instead of validating. The @ operator hides the message but does not make the input correct. Validating with a length check and ctype_xdigit() is clearer.
  4. Printing raw bytes. Decoded binary can corrupt terminal or browser output. Inspect it with bin2hex() or unpack().
  5. Leaving formatting in the input. Whitespace, newlines or prefixes copied from logs or documents make the string invalid.
  • bin2hex() converts raw bytes into hexadecimal text, the opposite direction.
  • unpack() reads values out of a binary string.
  • pack() builds binary strings from typed values.
  • base_convert() converts numbers between bases.
  • ctype_xdigit() checks whether a string contains only hexadecimal digits.

Recap

hex2bin() decodes pairs of hex digits into bytes and returns string|false. It needs even-length input made only of hex digits, otherwise it raises a warning and returns false. Validate untrusted input first, remember that the result is binary data rather than a number, and pair the function with bin2hex() for round trips.

Tested examples

Decode hex into readable text
<?php
$text = hex2bin("6578616d706c65206865782064617461");
var_dump($text);
Output
string(16) "example hex data"
Inspect non-printable bytes
<?php
$bytes = hex2bin("00ff10");
echo strlen($bytes), "\n";
echo json_encode(array_values(unpack("C*", $bytes))), "\n";
echo bin2hex($bytes), "\n";
Output
3
[0,255,16]
00ff10
Validate before decoding
<?php
function decodeHex(string $hex): ?string {
    if ($hex === '' || strlen($hex) % 2 !== 0 || !ctype_xdigit($hex)) {
        return null;
    }
    return hex2bin($hex);
}
echo json_encode([
    decodeHex("486921"),
    decodeHex("abc"),
    decodeHex("zz"),
    decodeHex("4A4b"),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["Hi!",null,null,"JK"]