PHP: pack/unpack补遗

pack/unpack的介绍和使用加上这篇就第三篇了。确实知识点比较多,这篇算是收尾之做吧。仔细去文档上看pack/unpack的格式化字符说明,就会发现s, S, i, I, l, L, f, d都没有对应的大端序和小端序的格式化字符,因此有须要的时候必须本身实现。这个真不知道PHP开发项目组是怎么想的!php

并且确实有人在stackoverflow上这么问了,详见:php-pack-format-for-signed-32-int-big-endian 。stackoverflow上的答案比较巧妙,因此我在这里进行借鉴。shell

L表示无符号长整型,按主机字节序。N表示无符号长整型,大端序。它们都是32位的,因此若是用L和N对同一个整数进行打包,若是结果相等,则本机字节序就是大端序,不然就是小端序。代码以下:函数

<?php
define('BIG_ENDIAN', pack('L', 1) === pack('N', 1));

if (BIG_ENDIAN)
{
	echo "大端序";
}
else
{
	echo "小端序";
}

echo "\n";

$ php -f test.php
小端序

大端序和小端序事实上是相反的字节序,好比要实现无符号短整型的大端序和小端序,能够用s格式化字符先进行打包,再判断大小端来决定是否须要反转字符串,代码以下:spa

<?php
define('BIG_ENDIAN', pack('L', 1) === pack('N', 1));

// 有符号16位整型大端序
function pack_int16s_be($num)
{
	if (BIG_ENDIAN)
	{
		return pack("s", $num);
	}

	return strrev(pack("s", $num));
}

// 有符号16位整型小端序
function pack_int16_le($num)
{
	if (BIG_ENDIAN)
	{
		return strrev(pack("s", $num));
	}

	return pack("s", $num);
}

其它几个也是相似如此实现。可是须要注意的是还须要实现相应版本的unpack,可参考我以前的一篇文章:PHP: chr和pack、unpack那些事.net

对于实现这几个函数倒不是难事,但在实际打包解包的时候就比较麻烦了。pack还比较好,只是分开打包,再做字符串链接。可是对unpack来讲,须要根据协议长度,将字节流拆分而后分别解包,确实有点坑。code

本篇文章基本上也就这些知识点,pack/unpack就告一段落了,欢迎你们一块儿交流~orm