php pack()函数与unpack()详解与示例

作者: aries 分类: PHP 发布时间: 2014-12-05 15:54 ė 2241次浏览 6 0评论

pack和unpack在一般的程序中还真的不容易见到,但是如果你用过很久以前的php生成excel你就会知道了。他的excel的头就是pack出来的

最近在尝试与C交互的时候又用上了这玩意,所以不得不再看看。其实就是C要求我一定要有包头。。。其实纯字符串也不错嘛。干嘛非得搞个包头呢?真纠结 .。

手册上有pack与unpack的介绍,但都是英文的。。。

任何一款拥有socket操作能力的语言都有一个专门用于组包的函数,php也不例外!         

用了很久php了却很少有机会用php进行一些二进制操作。 最近用php写一个socket客户端连接一个用C++语言开发的游戏服务端。 服务器端开发人员使用了二进制的形式来定义协议的格式。协议格式如下:

包头(2bytes)+加密(1byte)+命令码(2bytes)+帧内容

1.包头的内容是记录帧内容的长度;

  1. 加密:0表示不加密,1表示加密;

  2. 命令码为服务端命令识别符号;

    一开始不了解php原来有pack可以来组装二进制包, 走了弯路,让服务端开发人员用C语言帮忙开发了的几个内存操作函数,按照协议规则返回二进制包,然后我将这几个方法编译成一组扩展函数供php使用。

    话归正题,本文是介绍如何使用pack和unpack这两个方法的。php官方手册举例太少,不能很容易理解,特别是那些格式化参数的使用。

转摘的参数中文说明:

pack/unpack 的摸板字符字符 含义

a 一个填充空的字节串

A 一个填充空格的字节串

b 一个位串,在每个字节里位的顺序都是升序

B 一个位串,在每个字节里位的顺序都是降序

c 一个有符号 char(8位整数)值

C 一个无符号 char(8位整数)值;关于 Unicode 参阅 U

d 本机格式的双精度浮点数

f 本机格式的单精度浮点数

h 一个十六进制串,低四位在前

H 一个十六进制串,高四位在前

i 一个有符号整数值,本机格式

I 一个无符号整数值,本机格式

l 一个有符号长整形,总是 32 位

L 一个无符号长整形,总是 32 位

n 一个 16位短整形,“网络”字节序(大头在前)

N 一个 32 位短整形,“网络”字节序(大头在前)

p 一个指向空结尾的字串的指针

P 一个指向定长字串的指针

q 一个有符号四倍(64位整数)值

Q 一个无符号四倍(64位整数)值

s 一个有符号短整数值,总是 16 位

S 一个无符号短整数值,总是 16 位,字节序跟机器芯片有关

u 一个无编码的字串

U 一个 Unicode 字符数字

v 一个“VAX”字节序(小头在前)的 16 位短整数

V 一个“VAX”字节序(小头在前)的 32 位短整数

w 一个 BER 压缩的整数

x 一个空字节(向前忽略一个字节)

X 备份一个字节

Z 一个空结束的(和空填充的)字节串
@ 用空字节填充绝对位置

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

一些规则:

1.每个字母后面都可以跟着一个数字,表示 count(计数),如果 count 是一个 * 表示剩下的所有东西。

2.如果你提供的参数比 format 要求的少,pack 假设缺的都是空值。如果你提供的参数比 format 要求的多,那么多余的参数被忽略。

下面还是用例子来说明用法会容易理解一点:
下面的第一部分把数字值包装成字节:
$out = pack("CCCC", 65, 66, 67, 68);      # $out 等于"ABCD"
$out = pack("C4", 65, 66, 67, 68);         # 一样的东西

下面的对 Unicode 的循环字母做同样的事情:
  $foo = pack("U4", 0x24b6, 0x24b7, 0x24b8, 0x24b9);

下面的做类似的事情,增加了一些空:
out</span> <span class="highlight-o">=</span> <span class="highlight-nx">pack</span><span class="highlight-p">(</span><span class="highlight-s2">&#34;CCxxCC&#34;</span><span class="highlight-p">,</span> <span class="highlight-mi">65</span><span class="highlight-p">,</span> <span class="highlight-mi">66</span><span class="highlight-p">,</span> <span class="highlight-mi">67</span><span class="highlight-p">,</span> <span class="highlight-mi">68</span><span class="highlight-p">);</span> <span class="highlight-c1"># out 等于 "ABCD"

打包你的短整数并不意味着你就可移植了:
$out = pack("s2", 1, 2);
# 在小头在前的机器上是 "12"
# 在大头在前的机器上是 "12"

在二进制和十六进制包装上,count 指的是位或者半字节的数量,而不是生成的字节数量:
$out = pack("B32", "...");
$out = pack("H8", "5065726c"); # 都生成“Perl”

a 域里的长度只应用于一个字串:
$out = pack("a4", "abcd", "x", "y", "z"); # "abcd"

要绕开这个限制,使用多倍声明:
$out = pack("aaaa", "abcd", "x", "y", "z"); # "axyz"
$out = pack("a" x 4, "abcd", "x", "y", "z"); # "axyz"

a 格式做空填充:
$out = pack("a14", "abcdefg"); # " abcdefg"

关于unpack:

array unpack ( string format</span><span class="highlight-p">,</span> <span class="highlight-nx">string</span> <span class="highlight-nv">data )

$data = "010000020007";
unpack("Sint1/Cchar1/Sint2/Cchar2",$data);

## array('int1'=>1, 'char1'=>'0','int2'=>2,'char2'=>7);

最后本文开头讲到的协议使用pack/unpack 举例程序代码为

lastact</span> <span class="highlight-o">=</span> <span class="highlight-nx">pack</span><span class="highlight-p">(</span><span class="highlight-s1">&#39;SCSa32a32&#39;</span><span class="highlight-p">,</span><span class="highlight-mh">0x0040</span><span class="highlight-p">,</span> <span class="highlight-mh">0x00</span><span class="highlight-p">,</span> <span class="highlight-mh">0x0006</span><span class="highlight-p">,</span> <span class="highlight-nv">username, $passwd )

unpack('Sint1/Cchar1/Sint2/Cchar2/',$lastmessage)

来自:http://blog.sina.com.cn/s/blog_3eba8f1c0100nq9r.html

0 packunpack
换一个
暂无评论
Ɣ回顶部