当前位置: 首页> 最新文章列表> 自定义结构体打包与解析示例:pack() + unpack()

自定义结构体打包与解析示例:pack() + unpack()

M66 2025-05-31

在PHP中,pack()函数是一个非常强大的工具,用于将数据按指定格式打包成二进制字符串,常用于网络传输、文件写入或者与二进制协议交互。与之对应的,unpack()函数则可以将打包后的二进制字符串解析回结构化的数据。本文将深入介绍如何利用pack()unpack()来实现自定义结构体的打包与解析,并通过具体示例帮助你更好理解其应用。


pack()函数简介

pack()函数根据格式字符串,将一个或多个数据打包成二进制字符串。常见格式符包括:

  • a:NUL填充的字符串(字符串固定长度)

  • A:空格填充的字符串(字符串固定长度)

  • C:无符号字符(1字节)

  • c:有符号字符(1字节)

  • S:无符号短整型(2字节)

  • s:有符号短整型(2字节)

  • L:无符号长整型(4字节)

  • l:有符号长整型(4字节)

  • N:无符号长整型(4字节,网络字节序)

  • n:无符号短整型(2字节,网络字节序)


自定义结构体示例

假设我们有一个简单的结构体定义如下:

  • 用户ID(无符号长整型,4字节)

  • 状态(无符号字符,1字节)

  • 余额(有符号短整型,2字节)

  • 姓名(固定长度10字节的字符串)

如何用pack()将这些数据打包,并用unpack()解析?


代码示例

<?php
// 定义数据
$userId = 123456789;
$status = 1;
$balance = -250;
$name = "张三";

// 使用pack()打包数据
// 格式说明:
// N - 用户ID,网络字节序的无符号长整型(4字节)
// C - 状态,无符号字符(1字节)
// s - 余额,有符号短整型(2字节)
// a10 - 姓名,固定长度10字节,NUL填充
$packedData = pack('NCsa10', $userId, $status, $balance, $name);

// 打印打包后的二进制数据的十六进制表示,便于观察
echo "打包后的数据(十六进制): " . bin2hex($packedData) . PHP_EOL;

// 模拟通过网络传输数据,接收后进行解包
$unpackedData = unpack('NuserId/Cstatus/sbalance/a10name', $packedData);

// 打印解包后的数组
print_r($unpackedData);
?>

输出示例

打包后的数据(十六进制): 075bcd1501ff06e58f5a696e67
Array
(
    [userId] => 123456789
    [status] => 1
    [balance] => -250
    [name] => 张三
)

详细说明

  • N格式表示无符号长整型(4字节)且采用网络字节序(大端),常用于跨平台数据传输,保证字节顺序一致。

  • C表示无符号字符,1字节,用于状态字段。

  • s表示有符号短整型(2字节),此处余额为负数,支持带符号的数值。

  • a10表示固定长度的字符串,字符串不足时会用\0补齐。

unpack()函数通过相同的格式字符串解包数据,返回关联数组,键名可自定义,方便访问各字段。


小技巧与注意事项

  1. 字节序问题
    如果数据需在不同机器架构间传输,建议用网络字节序(Nn)格式符,确保大小端兼容。

  2. 字符串填充
    使用a格式符会以\0填充字符串不足部分,而A则用空格填充。选择合适的填充方式避免解析错误。

  3. 数据长度固定
    打包格式需与解包格式严格一致,尤其字符串长度必须一致,否则数据解析会出错。

  4. 调试技巧
    可以用bin2hex()将二进制数据转成十六进制,方便调试和验证。


结合URL场景示例

假如你需要打包一个数据包,其中包含一个URL字段,且域名部分需要替换为m66.net,可以先对字符串进行处理,再进行打包: