当前位置:首页 > 娱乐星闻

unpack PHP中的pack和unpack函数

PHP有两个重要的冷门功能:打包和解包。在网络编程、读写图像文件等场景中,这两个功能几乎是不可或缺的。鉴于文件读写/网络编程,或者字节流处理的重要性,掌握这两个功能是高级PHP编程的基础。

本文首先介绍了字节和字符的区别,并说明了这两种函数存在的必要性和重要性。然后介绍基本用法和使用场景,让读者对其有个大概的了解,为实际使用打下基础。

字节和字符

PHP的优点是使用方便,熟练使用字符串和数组相关函数可以抵抗一般要求。日常工作中经常用到字符串,所以PHP开发对字符比较熟悉,有一点点经验基本就能看懂字符编码。但是,很多PHP开发人员并不熟悉伴随而来的字符概念:字节。

这不是他们的错。“字节(stream)”的概念在PHP世界里很少出现:没有字节关键字(当然没有char),官方文档也没有提到字节;没有原生数组支持(常用的数组其实是hashtable);;当然字符串可以用其他语言表示字节数组(byte [])。

字节和字符有什么联系和区别?简单来说,字节是计算机存储和运算的最小单位,字符是读取的最小单位;字节是存储(物理)概念,字符是逻辑概念。字节代表数据(内涵和本质),字符代表其意义;字符由字节组成。

举几个例子说明两者的区别:“中国”包含2个字符,GBK编码意味着4个字节,UTF-8编码需要6个字节;包含10个字符的数字“1234567890”,用int32类型表示时只需要4个字节;下图占用42582字节,表示带字符的“我老婆”,只占用3个字符:

再举一个常见的例子来说明字符和字节的区别。在开发中,我们经常使用md5算法来获取数据的哈希值,该算法返回一个128位的数据(16字节)。为了方便查看其值,同意用十六进制表示,结果是32位字符串(不区分大小写)。32长度的字符串不是md5算法的必然结果,但16字节的数据才是其本质。如果您愿意,您可以使用小于2 128的数字来表示哈希结果,或者您可以将16字节的base64编码为结果。所以常用的32位哈希值和md5返回的16字节的关系是:一个是字符表示,一个是其本质(字符数组)(PHP中md5函数的第二个参数值为true得到16字节的数据,或者hash函数的第三个参数为true)。

相关概念包括字节顺序、字符编码等等,本文不展开。有兴趣的读者可以参考我之前的博客《文件与字符编码》或者相关资料。

向前

PHP中处理字符串的函数有几十个,处理字符串的函数不下100个,包括正则函数和时间函数。相对于字节处理,相关函数很少。除了常用的order/chr、hash加密函数返回的原始字节、openssl库的openssl _ random _ pseudo _ bytes等真正处理或返回字节的函数外,最重要的两个字节处理函数是pack和解包。

本节从问题出发介绍了pack函数的使用。

问题

考虑一个简单的问题:宇宙的最终答案42在内存中是如何表示的(或者说如何得到它的字节数组)?

因为42是整数,所以它占用的字节大小可能是1、2、4、8等。根据不同的硬件。这里我们限制一个整数占用4个字节,那么问题的等价表达式是:如何将一个整数转换成字节数组(原生顺序,4个字节)?

分析

因为是多字节,所以要考虑字节顺序。42不超过255,只占一个字节,所以其他三个字节都是0。据此得出结论,如果是大端序(低位字节存储在高位地址),则四个字节为:0.0042;如果是小端序,结果是42 0 0 0。

你怎么知道机器的字节顺序?PHP不提供相关功能,不能像C语言那样直接访问字节数据。万能的PHP如何得到字节顺序,或者说完成数据到字节的转换?

计划

在PHP的应用层,数据到字节(数组)的转换是打包的特殊事件,字节(数组)到数据的转换是解包的特殊事件。除了这两个功能,字节数组(或者二进制数据)转换成数据几乎是不可能的(请不吝赐教)。

现在我们使用pack函数来获取内存中的42字节数组。相关代码如下:

函数intToBytes(int $num) : string {

退货包(“l”、$ num);

}

函数outputBytes(字符串$bytes) {

echo " bytes:";

for($ I = 0;$i <。strlen($ bytes);++ $i) {

echo order($ bytes[$ I]),“”;

}

echo PHP _ EOL

}

output bytes(intToBytes(42));

//程序输出:

字节:42 0 0 0

我电脑用的Intel CPU x86架构比较小,程序输出符合预期。

扩展了,怎么判断机器的字节顺序?使用打包功能,答案很简单:

函数bigEndian() : bool {

$ data = 0x1200

$bytes = pack("s ",$ data);

返回顺序($ bytes[0])= = = 0x 12;

}

调用函数返回这个机器大不大。

以上是pack函数的简单使用场景。接下来,分别介绍了打包和解包功能。

打包和解包功能

Pack的意思是“包/包”。顾名思义,函数包根据格式将数据打包成字节数组。功能原型是:

pack ( string $format [,mixed $… ] ) : string

形式和printf系列函数一样:第一个参数是格式字符串,其他参数是要格式化的参数。区别在于pack函数的格式不能包含元字符和除量词以外的其他字符,所以不需要%符号。

在上例中,使用了两个格式化的元字符“l”和“s”,pack函数的元字符主要分为三类:

字符串: a 、 A 等;将数据转成字符串,功能上与 sprintf 类似,例如整数32转换成字符串”32″;字节: h 和 H ;对字节进行16进制编码,区别在于低位还是高位在前,功能上与 dechex 等函数类似;char/short/int/long/float/double六种基本类型: c/s/i/l 等;将数据转换成对应类型的字节数组,除 char 类型外(暂)没有其他函数可替代;

注意:char和a/A的区别在于a/A是作为字符(字符串)输入的,而' s/S '的输入要求是小于256的整数,输入的字符会得到0。

量词很简单:数字和" "。比如“I2”表示按照整数转换两个参数,“C”表示后面按照char类型转换。

打开取出东西

解包是打包的逆操作:将字节数组解析成有意义的数据。其功能的原型是:

解包(string $格式,string $data [,int $offset = 0 ]):数组

解包函数需要注意第一个参数和返回值。返回值很好理解,pack函数相当于把除了格式化参数(想象call_user_func_array的参数)以外的参数数组改成字节数组;解包则相反:释放数据,得到输入参数数组。

返回一个数组。它的钥匙是什么?这就是pack和unpack中的format参数($format)的区别:unpack应该为发布的数据命名,并用“/”分隔每组数据。因为格式化参数允许非元字符和除量词之外的字符,所以不同数据之间的“/”分隔符对于区分数据是必要的。

一个例子:

$bytes = pack("iaa* ",42,":"生命、宇宙、万物的答案");

output bytes($ bytes);

$ result = unpack(" in number/acolon/a * word ",$ bytes);

print _ r($ result);

//程序输出:

字节:42 0 0 0 58 84 104 101 32 97 110 115 119 101 114 32 116 111 32 108 105 102 101 44 32 116 104 101 32 117 110 105 118 101 114 115 101 32 97 110 100 32 101 118 101 114 121 1111

数组

[num] = >四十二岁

[冒号] = >:

[word] = >生命、宇宙和一切的答案

)

发布的数据不点名会怎么样?例如,在前面的例子中,解包的格式参数是“i/a/a*”,结果是什么?结果是:

数组

[1] = >生命、宇宙和一切的答案

)

为什么?根据官方文件:

警告如果没有命名元素,则使用从1开始的数字索引。请注意,如果您有多个未命名的元素,某些数据会被覆盖,因为每个元素的编号都从1开始。

如果您没有命名数据,默认的1,2,3…将被用作键值。如果有多组数据,每组使用相同的下标,这将导致数据覆盖。

那么你能理解为什么“i/a/a*”里只剩下最后一组数据了吗?

应用场景

当读取图像、word/excel文件和解析binlog和二进制ip数据库文件时,打包和解包几乎是必需的。本文给出了一个在网络编程中使用打包和解包进行协议解析的例子。

让我们假设我们的tcp包格式是:前四个字节代表包的大小,其余的字节是数据内容。因此,客户端(发送方)的发送功能可能如下所示:

公共函数send($data) {

//假设$data已经序列化加密,是字节数组。

//计算消息长度,封装消息

$ len = strlen($ data);

$header = pack("L ",$ len);

//转换成网络(大端)序列

$header = xxx

//数据包

$binary = $header。$ data

//调用fwrite/socket_send等。将数据写入内核缓冲区

...

}

业务(接收)端根据协议解析接收到的数据流:

公共函数可解码($session,$buffer) {

$ DataLen = strlen($ buffer);

//非法数据包

if($ Datalen & lt;4) {

//关闭连接,记录ip等

....

返回NOT _ OK

}

//获取前四个字节

$header = substr($buffer,0,4);

//转换为主机序列

$header = xxx

//解析数据长度

$len =解包(“L”,$ header);

//单个消息不能超过8M,比如限制上传图片的大小

if ($len >;8 * 1024 * 1024) {

//关闭连接等

返回NOT _ OK

}

//检查数据包是否符合协议要求

if($ Datalen-4 >;= $len) {

返回确定;

}

//数据还没有全部到达,继续等待

返回需求数据;

}

通过打包和解包,我们成功地处理了消息协议和二进制字节流的发送和解析。

如果使用n作为消息分隔符,则可能不使用打包和解包。但是网络通信中直接传输的字符很少(相当于明文传输),大多数情况下二进制数据流的解析还是要靠打包和解包。

总结

除了内存分配,最重要的系统调用是文件读写和网络连接,两者的本质操作对象都是字节流。打包和解包为PHP提供了操作底层字节的能力,这在二进制数据处理中非常有用。有兴趣跳出web编程的PHP开发者,应该掌握这两个功能。

文件和字符编码PHP Manual: packPHP Manual: unpackHandling binary data in PHP with pack() and unpack()PHP: 深入pack/unpack

1.《unpack PHP中的pack和unpack函数》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《unpack PHP中的pack和unpack函数》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/1535357.html

上一篇

法国特色菜 法餐并不只有松露,鹅肝,盘点那些接地气的法国特色菜

下一篇

眼霜的正确使用时间是什么时候

vlookup两个条件匹配 Vlookup函数实现多条件查找,又有新方法了!

  • vlookup两个条件匹配 Vlookup函数实现多条件查找,又有新方法了!
  • vlookup两个条件匹配 Vlookup函数实现多条件查找,又有新方法了!
  • vlookup两个条件匹配 Vlookup函数实现多条件查找,又有新方法了!

近似值 Excel中用什么函数取到近似值

  • 近似值 Excel中用什么函数取到近似值
  • 近似值 Excel中用什么函数取到近似值
  • 近似值 Excel中用什么函数取到近似值
武汉合众易宝科技有限公司 一克商评丨字节跳动拿下支付牌照,抖音或将成为电商赛道强劲搅局者

武汉合众易宝科技有限公司 一克商评丨字节跳动拿下支付牌照,抖音或将成为电商赛道强劲搅局者

9月3日,湖北省首家获证互联网支付企业武汉何忠易宝科技有限公司股东钟发实业有限公司退股,天津同荣电子商务有限公司接管100%股份。天津同荣电子商务有限公司是北京市北科技有限公司的全资子公司,经过渗透,字节跳动创始人张一...

中国独角兽公司排名 《2020中国独角兽企业品牌榜》发布,蚂蚁集团、字节跳动、滴滴出行排名前三

中国独角兽公司排名 《2020中国独角兽企业品牌榜》发布,蚂蚁集团、字节跳动、滴滴出行排名前三

8月26日,在四川省网办和四川日报报业集团的指导下,在国家新经济研究院的学术支持下,2020年新经济大会将在成都召开。会上发布了《2020中国独角兽企业品牌榜》和《2020封面准独角兽企业品牌榜》两个重量级榜单。202...

字节跳动市值 字节跳动投资者被曝洽购TikTok,给出500亿美元估值

TikTok似乎并不缺乏买家。据路透社7月29日报道,字节跳动一些投资者正寻求获得TikTok的多数股权,这些投资者对TikTok的估值约为500亿美元,高于Snap等社交媒体平台。TikTok是字节跳动的一个短片产品...

字节跳动估值 字节跳动投资者被曝洽购TikTok,给出500亿美元估值

字节跳动估值 字节跳动投资者被曝洽购TikTok,给出500亿美元估值

TikTok似乎并不缺乏买家。据路透社7月29日报道,字节跳动一些投资者正寻求获得TikTok的多数股权,这些投资者对TikTok的估值约为500亿美元,高于Snap等社交媒体平台。TikTok是字节跳动的一个短片产品...

转义符 html中常用的转义字符总结

html中常用的转义字符总结如下: & ampnbsp。不连续运行的空单元格 & ampensp半方形空网格 & ampemsp整个广场的空情况 & amplt。小于 & ampgt。大于>: & ampamp。& a...

转义字符 html中常用的转义字符总结

转义字符 html中常用的转义字符总结

html中常用的转义字符总结如下: & ampnbsp。不连续运行的空单元格 & ampensp半方形空网格 & ampemsp整个广场的空情况 & amplt。小于 & ampgt。大于>: & ampamp。& a...