PHP中pack、unpack的用法

pack

string pack ( string format \[, mixed args [, mixed $... ]] )

该函数用来将对应的参数($args)打包成二进制字符串。

其中第一个参数$format,有如下选项:

a 以NUL字节填充字符串空白

A 以SPACE(空格)填充字符串

h 十六进制字符串,低位在前

H 十六进制字符串,高位在前

c 有符号字符

C 无符号字符

s 有符号短整型(16位,主机字节序)

S 无符号短整型(16位,主机字节序)

n 无符号短整型(16位,大端字节序)

v 无符号短整型(16位,小端字节序)

i 有符号整型(机器相关大小字节序)

I 无符号整型(机器相关大小字节序)

l 有符号长整型(32位,主机字节序)

L 无符号长整型(32位,主机字节序)

N 无符号长整型(32位,大端字节序)

V 无符号长整型(32位,小端字节序)

q 有符号长长整型(64位,主机字节序)

Q 无符号长长整型(64位,主机字节序)

J 无符号长长整型(64位,大端字节序)

P 无符号长长整型(64位,小端字节序)

f 单精度浮点型(机器相关大小)

d 双精度浮点型(机器相关大小)

x NUL字节

X 回退一字节

Z 以NUL字节填充字符串空白(new in PHP 5.5)

@ NUL填充到绝对位置

高/低位字节

比如字符串AB,左高右低,A为高字节,B为低字节

高/低地址

假设0x123456是按从高位到底位的顺序储存,内存中是这样存放的:

高地址 -> 低地址

12 -> 34 -> 56

大端字节序(网络字节序)

大端就是将高位字节放到内存的低地址端,低位字节放到高地址端。网络传输中(比如TCP/IP)低地址端(高位字节)放在流的开始,对于2个字节的字符串(AB),传输顺序为:A(0-7bit)、B(8-15bit)。

那么小端字节序自然和大端相反。

主机字节序

表示当前机器的字节序(网络字节序是确定的,主机字节序是依机器确定的),一般为小端字节序。

a和A(打包字符串,用NUL或者空格填充)

$string = pack('a6', 'china');

var_dump($string); //输出结果: string(6) "china",最后一个字节是不可见的NUL

echo ord($string[5]); //输出结果: 0(ASCII码中0对应的就是nul)

//A同理

$string = pack('A6', 'china');

var_dump($string); //输出结果: string(6) "china ",最后一个字节是空格

echo ord($string[5]); //输出结果: 32(ASCII码中32对应的就是空格)

h和H

$string = pack('H3', 281);

var_dump($string); //输出结果: string(2) "("

for(i=0;i<strlen(string);i++) {

echo ord(string\[i]) . PHP_EOL;

}

//输出结果: 40 16

h和H需要特殊说明一下,它们是将对应的参数看做十六进制字符然后打包。什么意思呢?比如上面的281,打包前会将281转换为0x281,因为十六进制的一位对应二进制的四位,上面的0x281只有1.5个字节,后面会默认补0变成0x2810,0x28对应的十进制为40((),0x10对应的十进制为16(dle不可见字符),懂了吧?不懂可以给我留言。。

c和C

$string = pack('c3', 67, 68, -1);

var_dump($string); //输出:string(3) "CD�"

for(i=0;i<strlen(string);i++) {

echo ord(string\[i]) . PHP_EOL;

}

//输出: 67 68 255

最后输出本能应该觉得是67 68 -1

ord获取的是字符的ASCII码(范围0-255),这时-1(0000 0001)对应的字符将以补码的形式输出也就是255(1111 1110 + 0000 0001 = 1111 1111)

整型相关

所有的整型类型使用方法完全一样,主要注意它们的位和字节序就可以了,下面以L作为例子展示

$string = pack('L', 123456789);

var_dump($string); //输出:string(4) "�["

for(i=0;i<strlen(string);i++) {

echo ord(string\[i]) . PHP_EOL;

}

//输出: 21 205 91 7

f和d

$string = pack('f', 12345.123);

var_dump($string);

//输出:string(4) "~�@F"

var_dump(unpack('f', $string)); //这里提前用到了unpack,后面会讲解

//输出:float(12345.123046875)

f和d是针对浮点数打包,至于为什么打包前是12345.123解包后是12345.123046875,这个和浮点数的储存有关系

x、X、Z、@

$string = pack('x'); //打包一个nul字符串

echo ord($string); //输出: 0

关于X(大写X),试了N次,没搞明白怎么用,有清楚的童鞋可以给我留言,多谢。

$string = pack('Z2', 'abc5'); //其实就是将从Z后面的数字位置开始,全部设置为nul

var_dump($string); //输出:string(2) "a"

for(i=0;i<strlen(string);i++) {

echo ord(string\[i]) . PHP_EOL;

}

//输出: 97 0

$string = pack('@4'); //我理解为填充N个nul

var_dump($string); //输出: string(4) ""

for(i=0;i<strlen(string);i++) {

echo ord(string\[i]) . PHP_EOL;

}

//输出: 0 0 0 0

unpack

array unpack ( string format , string data )

unpack的使用相当简单,就是讲pack打包的数据解包,打包的时候用的什么参数,就用什么参数解包,具体使用懒得说了,列几个小例子

$string = pack('L4', 1, 2, 3, 4);

var_dump(unpack('L4', $string));

//输出:

array(4) {

1\]=\> int(1) \[2\]=\> int(2) \[3\]=\> int(3) \[4\]=\> int(4) } $string = pack('L4', 1, 2, 3, 4); var_dump(unpack('Ll1/Ll2/Ll3/Ll4', $string)); //可以指定key,用/分割 //输出: array(4) { \["l1"\]=\> int(1) \["l2"\]=\> int(2) \["l3"\]=\> int(3) \["l4"\]=\> int(4) } 这两个函数到底有啥用途? 数据通信(通过二进制格式与其它语言通信) 数据加密(如果不告诉第三方你的打包方式,对方解包的难度就相对很大) 节省空间(比如比较大的数字按字符串储存会浪费很多空间,打包成二进制格式才需要4位\<32位数字\>)

相关推荐
JaguarJack9 小时前
FrankenPHP 原生支持 Windows 了
后端·php·服务端
BingoGo9 小时前
FrankenPHP 原生支持 Windows 了
后端·php
JaguarJack1 天前
PHP 的异步编程 该怎么选择
后端·php·服务端
BingoGo1 天前
PHP 的异步编程 该怎么选择
后端·php
JaguarJack2 天前
为什么 PHP 闭包要加 static?
后端·php·服务端
ServBay3 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954483 天前
CTF 伪协议
php
BingoGo5 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack5 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo6 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php