當前位置: 首頁> 最新文章列表> 自定義結構體打包與解析示例: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. 字節序問題<br> 如果數據需在不同機器架構間傳輸,建議用網絡字節序( Nn )格式符,確保大小端兼容

  2. 字符串填充<br> 使用a格式符會以\0填充字符串不足部分,而A則用空格填充選擇合適的填充方式避免解析錯誤。

  3. 數據長度固定<br> 打包格式需與解包格式嚴格一致,尤其字符串長度必須一致,否則數據解析會出錯

  4. 調試技巧<br> 可以用bin2hex()將二進制數據轉成十六進制,方便調試和驗證


結合URL場景示例

假如你需要打包一個數據包,其中包含一個URL字段,且域名部分需要替換為m66.net ,可以先對字符串進行處理,再進行打包: