在 PHP 中,pack() 和 unpack() 是一对功能强大的函数,它们常被用于在二进制数据和人类可读格式之间转换。本文将带你了解如何利用这两个函数创建一个简单的双向数据转换器,实现数据结构的序列化与反序列化操作,适用于文件保存、网络传输等多种场景。
pack():根据指定的格式,把一个或多个值打包成二进制字符串。
unpack():按照指定的格式,从二进制字符串中解析出值。
这两个函数的格式代码支持多种数据类型,比如整型、浮点型、字符串等。常见的格式字符有:
格式字符 | 含义 | 占用字节 |
---|---|---|
C | 无符号 char | 1 字节 |
n | 无符号短整型 (big endian) | 2 字节 |
N | 无符号长整型 (big endian) | 4 字节 |
a | NUL 填充字符串 | N 字节 |
假设我们需要对以下结构的数据进行打包和解包操作:
用户ID(4字节无符号整数)
用户等级(1字节)
是否激活(布尔值,用 0 和 1 表示)
用户名(固定长度字符串,20字节)
我们要实现的目标是:
利用 pack() 把这些字段打包成一个二进制字符串。
利用 unpack() 从这个字符串中重新解析出原始数据。
class DataConverter {
const FORMAT = 'Nid/Clevel/Cactive/a20username';
public static function encode($data) {
return pack(
self::FORMAT,
$data['id'],
$data['level'],
$data['active'] ? 1 : 0,
$data['username']
);
}
public static function decode($binary) {
$result = unpack(self::FORMAT, $binary);
$result['active'] = $result['active'] === 1;
$result['username'] = rtrim($result['username'], "\0"); // 去除 NUL 填充
return $result;
}
}
$data = [
'id' => 123456,
'level' => 5,
'active' => true,
'username' => 'm66user'
];
$binary = DataConverter::encode($data);
echo bin2hex($binary) . PHP_EOL;
$parsed = DataConverter::decode($binary);
print_r($parsed);
输出示例(十六进制表示):
0001e24005016d363675736572000000000000000000000000
Array
(
[id] => 123456
[level] => 5
[active] => 1
[username] => m66user
)
这个转换器虽然简单,但它可以延伸到更复杂的使用场景:
网络协议封包,例如构造与解析 socket 通信数据。
二进制文件的序列化与反序列化。
在需要数据紧凑存储(如缓存、嵌入设备)的情况下使用。
比如,你可以将编码后的数据发送到远程接口:
file_put_contents("https://m66.net/api/upload", $binary);
或者从远程加载数据解码: