一、bin2hex()的转换逻辑
bin2hex()做一件事:把字符串中每个字节按十六进制表示出来,返回一个只含0-9和a-f的字符串。
语法:
string bin2hex ( string $str )
参数$str为必填,传入待转换的字符串。返回值为十六进制字符串,长度是原字符串字节数的两倍。
这里要区分一个概念:bin2hex()处理的是字节,不是字符。对ASCII字符来说,一个字符就是一个字节,转换结果直观。但对UTF-8中文、emoji等多字节字符,每个字符会展开成多个字节的十六进制,结果长度不等于字符数乘以2。这是很多初学者第一次接触时容易误解的地方。
核心关键词:PHPbin2hex、字符串转十六进制、ASCII转hex、二进制转十六进制。
二、基础示例:ASCII字符串转换
代码号学习编程建议先跑一个最简单的例子,观察输入与输出的对应关系。
<?php
$str = "Hello World!";
echo "原始字符串:" . $str;
echo "<br>";
echo "bin2hex 结果:" . bin2hex($str);
?>
输出:
原始字符串:Hello World!
bin2hex 结果:48656c6c6f20576f726c6421
拆开看对照关系:
| 字符 | ASCII码(十进制) | 十六进制 |
|---|---|---|
| H | 72 | 48 |
| e | 101 | 65 |
| l | 108 | 6c |
| o | 111 | 6f |
| 空格 | 32 | 20 |
| W | 87 | 57 |
48656c6c6f20576f726c6421拼起来就是48656c6c6f20576f726c6421。转换过程本质是逐字节的进制映射,没有加密含义,也不涉及压缩。
三、还原转换:pack()与hex2bin()
bin2hex()的逆操作有两条路。
方式一:pack("H*",$hex)
<?php
$str = "Hello world!";
$hex = bin2hex($str);
echo "十六进制值:" . $hex . "<br>";
echo "pack 还原:" . pack("H*", $hex);
?>
输出:
十六进制值:48656c6c6f20776f726c6421
pack 还原:Hello world!
pack("H*",...)中的H表示高四位优先的十六进制,*表示读取到字符串末尾。
方式二:hex2bin()
PHP5.4之后提供了更直接的hex2bin():
<?php
$hex = bin2hex("代码号学习编程");
echo "hex:" . $hex . "<br>";
echo "hex2bin 还原:" . hex2bin($hex);
?>
输出:
hex:e4bba3e7a081e58fb7e5ada6e4b9a0e7bc96e7a88b
hex2bin 还原:代码号学习编程
注意中文的输出:代码号学习编程是7个汉字,UTF-8下每个汉字3字节,共21字节,所以hex字符串长度是42。如果用strlen($hex)/2去推算字符数,会得到21,而不是7。这一点在写长度校验逻辑时必须留意。
个人建议:新项目还原十六进制字符串优先用hex2bin(),语义清晰,比pack("H*")更直观。pack()更适合处理混合格式的二进制打包场景。
四、二进制字符串转十六进制:bindec()+dechex()
bin2hex()处理的是字符串字节,而bindec()处理的是二进制数字字符串。两者容易混淆,但用途不同。
<?php
$binary = "11111001";
echo "二进制值:" . $binary . "<br>";
$hex = dechex(bindec($binary));
echo "转换为十六进制:" . $hex;
?>
输出:
二进制值:11111001
转换为十六进制:f9
拆解过程:
-
bindec("11111001")把二进制字符串转为十进制整数,结果是249。 -
dechex(249)把十进制整数转为十六进制字符串,结果是f9。
这条链路适合处理数值型二进制,比如权限位、标志位、协议字段。而bin2hex()适合处理字节流,比如哈希值、随机字节、加密结果的可读化。
对比表:
| 函数 | 输入类型 | 输出 | 典型场景 |
|---|---|---|---|
| bin2hex() | 字符串(字节流) | 十六进制字符串 | 哈希展示、token编码 |
| bindec() | 二进制数字字符串 | 十进制整数 | 位运算、权限解析 |
| dechex() | 十进制整数 | 十六进制字符串 | 数值格式化 |
踩坑经历:曾在一个设备通信项目里,把二进制协议字段当成字节流丢给bin2hex(),结果输出不对。后来才意识到协议里给的是二进制数字字符串"1010",应该走bindec()+dechex()。先判断数据是"字节流"还是"数值字符串",再选函数,这个判断顺序能省下不少调试时间。
五、项目场景
场景一:生成随机token的可读形式
<?php
$bytes = random_bytes(8);
$token = bin2hex($bytes);
echo "Token:" . $token;
?>
random_bytes()返回二进制字节,直接输出会乱码,用bin2hex()转成可打印字符串后,便于存入数据库或放入URL。这是bin2hex()在现在PHP中最常见的用法之一。
场景二:哈希值的十六进制展示
<?php
$data = "代码号学习编程";
echo "SHA-1:" . bin2hex(sha1($data, true));
echo "<br>";
echo "MD5:" . bin2hex(md5($data, true));
?>
sha1()和md5()的第二个参数设为true时返回原始二进制,再用bin2hex()转成常见的十六进制形式。如果第二个参数用默认的false,函数本身就会返回十六进制字符串,不需要再套bin2hex()。这里容易多此一举,写代码前先查一下函数签名。
场景三:调试二进制数据
处理图像、压缩包、加密数据时,直接打印二进制会污染终端。用bin2hex()转一下,能安全地观察字节分布。
六、本节课程知识要点
-
bin2hex()按字节转换,返回长度为原字节数两倍的十六进制字符串。
-
多字节字符(中文、emoji)转换后长度不等于字符数乘以2。
-
还原优先用hex2bin(),pack("H*")适合混合二进制打包场景。
-
bindec()+dechex()处理的是数值型二进制字符串,与bin2hex()用途不同。
-
生成随机token、展示哈希值时,bin2hex()是常用手段。
-
使用md5()/sha1()时注意第二个参数,避免重复转hex。
七、常见问题
Q:bin2hex()能用来加密吗?
A:不能。它只是进制转换,没有密钥,任何人拿到hex字符串都能还原。加密需要用openssl_encrypt()、sodium_crypto等专用函数。
Q:bin2hex()和dechex()有什么区别?
A:bin2hex()输入是字符串,逐字节转hex;dechex()输入是十进制整数,输出该整数的十六进制表示。前者处理字节流,后者处理数值。
Q:hex2bin()报错"Hexadecimalinputstringmusthaveanevenlength"怎么处理?
A:十六进制字符串长度必须是偶数,每两个字符代表一个字节。检查来源数据是否被截断,或补零对齐。
bin2hex()是PHP中处理字节流与十六进制字符串互转的基础函数,逻辑直白但边界需要注意:它按字节工作,不按字符;它不做加密,只做表示形式的转换。配合hex2bin()、random_bytes()、hash函数使用,能覆盖token生成、哈希展示、二进制调试等常见需求。遇到二进制数字字符串时,先分清是"字节流"还是"数值",再决定用bin2hex()还是bindec()+dechex(),这个判断习惯比记住函数名更有价值。