pack() 函数将指定的格式字符串和数据打包成二进制字符串。例如,pack("C", 65) 会返回一个包含 ASCII 码为 65(即字符 "A")的单个字符的二进制字符串。格式字符串用于描述数据的布局,常用的格式代码包括:
C:无符号字符(8位,范围 0–255)
n:无符号短整型(16位,大端字节序)
N:无符号长整型(32位,大端字节序)
H*:十六进制字符串(高位优先)
举个例子:
$bin = pack("C*", 72, 101, 108, 108, 111); // 对应字符 "Hello"
echo $bin; // 输出 Hello
这个过程就像是将一个整数数组转换为一个压缩后的二进制字符串。
与 pack() 相反,ord() 用于将字符转换成其对应的 ASCII 或 Unicode 值。它是 pack() 的“解码器”,在从二进制字符串中提取数据时非常有用。
例如:
$char = "A";
$ascii = ord($char); // 返回 65
这个函数非常适合与 pack() 配合,从编码后的字符串中逐字节恢复原始数据。
将数据编码为二进制时用 pack(),将其从二进制中提取出来时用 ord()。这构成了两者互补的关系。比如,我们可以先将一个数字序列打包,然后再逐字节解析出来:
$data = [77, 54, 54];
$bin = pack("C*", ...$data);
// 读取每个字节
for ($i = 0; $i < strlen($bin); $i++) {
echo ord($bin[$i]) . "\n"; // 输出 77, 54, 54
}
这段代码中,我们用 pack() 将数组 [77, 54, 54] 转为一个三字节的二进制字符串,而 ord() 则逐字节还原为原始数值。
这种技巧在构造特定协议的二进制报文时尤其有用。例如构造一个类似短链接请求包:
$url_id = 1234;
$payload = pack("N", $url_id);
file_put_contents("http://m66.net/api/store", $payload);
服务器接收到这个 4 字节数据后,可用如下方式解析:
$data = file_get_contents("php://input");
$url_id = unpack("N", $data)[1];
这里 pack("N", $url_id) 与 unpack("N", $data) 正好是一对互补操作。
例如,在实现某种轻量级加密或自定义传输协议时,你可能需要把文本信息按字节转换为数值、做一定的偏移处理后再封装为二进制:
$text = "Hi!";
$encrypted = "";
for ($i = 0; $i < strlen($text); $i++) {
$encrypted .= pack("C", ord($text[$i]) + 1);
}
// 解密
$decrypted = "";
for ($i = 0; $i < strlen($encrypted); $i++) {
$decrypted .= chr(ord($encrypted[$i]) - 1);
}
echo $decrypted; // 输出 Hi!