Signature
bin2hex(string $string): stringPurpose
bin2hex() converts a string into its hexadecimal representation. PHP strings are sequences of bytes, and the function reads them one byte at a time. Each byte becomes two hexadecimal characters, with the high nibble (the upper four bits) written first. The result contains only ASCII characters, so it is safe to print, log, put in JSON or compare visually even when the original data contains NUL bytes, control characters or invalid UTF-8.
Typical uses include displaying binary values such as hashes or tokens, debugging what a string really contains, and building text-safe identifiers from raw bytes.
Signature
Parameters and defaults
$string: the data to encode. It has no default and is required. The function treats the value as raw bytes and ignores any character encoding.
There are no optional parameters. You cannot choose uppercase output, a separator or a grouping size; if you want those, post-process the result with functions such as strtoupper() or str_split().
Return value and failure cases
The function returns a string whose length is always exactly twice the byte length of the input. The digits a to f are produced in lowercase. An empty string produces an empty string.
There is no false return for normal input, so you do not need to check for failure. The only practical error is a type problem: with declare(strict_types=1), passing a non-string such as an integer throws a TypeError. Without strict types, scalar values are coerced to strings first, so the integer 255 is treated as the three characters "255", not as the single byte 0xFF. That surprises many people.
Example 1: basic text
Each ASCII character is one byte, so the output has two hex digits per character. An empty string gives an empty result, shown here between a line start and a pipe character.
echo bin2hex('Hello'), "\n";
echo bin2hex('AB'), "\n";
echo bin2hex(''), "|\n";48656c6c6f 4142 |
H is byte 0x48, e is 0x65, and so on. A is 0x41 and B is 0x42.
Example 2: bytes, not characters
The function does not know about characters. A single accented letter in UTF-8 uses two bytes, so you get four hex digits. Bytes that are not printable, such as NUL, still produce readable output.
$text = "\u{00E9}";
echo bin2hex($text), "\n";
echo strlen($text), "\n";
echo bin2hex("\x00\xFF\x10"), "\n";c3a9 2 00ff10
The escape \u{00E9} creates the UTF-8 encoding of the letter, which is the byte pair c3 a9. This is why strlen() reports 2, and why the length of a bin2hex() result is a count of bytes times two, never a count of characters times two.
Example 3: formatting and round trip
Because the output is always made of two-digit pairs, you can split it into bytes with str_split($hex, 2). The inverse function hex2bin() restores the original bytes.
$bytes = chr(1) . chr(127) . chr(128) . chr(255);
$hex = bin2hex($bytes);
echo json_encode([
'hex' => $hex,
'length' => strlen($hex),
'pairs' => str_split($hex, 2),
'roundTrip' => hex2bin($hex) === $bytes,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"hex":"017f80ff","length":8,"pairs":["01","7f","80","ff"],"roundTrip":true}
Note that single-digit byte values are padded with a leading zero, so 0x01 appears as 01. That fixed width is what makes the encoding reversible and easy to split.
Edge cases
- Empty input: returns
"", andhex2bin('')also gives an empty string. - Binary safety: NUL bytes and bytes above
0x7Fare handled like any other byte. - Multibyte text: the output reflects the bytes actually stored in the string, which depends on how the string was created or encoded.
- Size: the result needs twice as much memory as the input, which matters for very large strings.
- Case: output is lowercase. Hex comparisons against uppercase values should normalize case first, for example with
strtolower().
Common mistakes
- Using it to convert numbers.
bin2hex(255)encodes the text"255". To write an integer in base 16, usedechex()instead. - Treating the result as encryption. Hex is only a reversible representation. It hides nothing and adds no security.
- Counting characters. The length of the result equals twice the number of bytes, not characters. Use
strlen()for bytes and a multibyte function when you really need characters. - Expecting separators or uppercase. There is no option for either; format the string yourself afterwards.
- Feeding odd-length hex to the inverse. A valid
bin2hex()result always has an even length, but hand-written hex may not, andhex2bin()will reject it with a warning.
Related functions
hex2bin()decodes a hexadecimal string back into bytes.pack()builds binary strings from typed values.dechex()converts an integer to a hexadecimal number string.base64_encode()is a more compact text-safe encoding for binary data.str_split()helps group the hex pairs for display.
Recap
bin2hex(string $string): string encodes every byte as two lowercase hex digits, high nibble first. The output is ASCII, always twice as long as the input in bytes, and reversible with hex2bin(). Remember that it works on bytes rather than characters or numbers, and that it is an encoding, not protection.
Tested examples
echo bin2hex('Hello'), "\n";
echo bin2hex('AB'), "\n";
echo bin2hex(''), "|\n";48656c6c6f 4142 |
$text = "\u{00E9}";
echo bin2hex($text), "\n";
echo strlen($text), "\n";
echo bin2hex("\x00\xFF\x10"), "\n";c3a9 2 00ff10
$bytes = chr(1) . chr(127) . chr(128) . chr(255);
$hex = bin2hex($bytes);
echo json_encode([
'hex' => $hex,
'length' => strlen($hex),
'pairs' => str_split($hex, 2),
'roundTrip' => hex2bin($hex) === $bytes,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"hex":"017f80ff","length":8,"pairs":["01","7f","80","ff"],"roundTrip":true}