PHP里的pack和unpack函数详解

标签: PHP pack unpack 高级函数 PHP架构师高手进阶,恭喜你已经掌握了PHP架构师的基础知识

PHP里的pack和unpack函数详解

帖子NT流人 于 2010年 1月 19日 11:39

pack

压缩资料到位字符串之中。

语法: string pack(string format, mixed [args]...);

返回值: 字符串

函数种类: 资料处理


内容说明

本函数用来将资料压缩打包到位的字符串之中。本函数和 Perl 的同名函数功能用法完全相同。参数 format 为压缩的格式,见下表

a 将字符串空白以 NULL 字符填满
A 将字符串空白以 SPACE 字符 (空格) 填满
h 十六进位字符串,低位在前
H 十六进位字符串,高位在前
c 有号字符
C 无号字符
s 有号短整数 (十六位,依计算机的位顺序)
S 无号短整数 (十六位,依计算机的位顺序)
n 无号短整数 (十六位, 高位在后的顺序)
v 无号短整数 (十六位, 低位在后的顺序)
i 有号整数 (依计算机的顺序及范围)
I 无号整数 (依计算机的顺序及范围)
l 有号长整数 (卅二位,依计算机的位顺序)
L 无号长整数 (卅二位,依计算机的位顺序)
N 无号短整数 (卅二位, 高位在后的顺序)
V 无号短整数 (卅二位, 低位在后的顺序)
f 单精确浮点数 (依计算机的范围)
d 倍精确浮点数 (依计算机的范围)
x 空位
X 倒回一位
@ 填入 NULL 字符到绝对位置


例子 1

代码: 全选
<?php

echo pack("C3",80,72,80);

?>


输出:

PHP

例子 2

代码: 全选
<?php

echo pack("C*",80,72,80);

?>

输出:

PHP

unpack

解压缩位字符串资料。

语法: string pack(string format, mixed [args]...);

返回值: 数组

函数种类: 资料处理


内容说明

本函数用来将位的字符串的资料解压缩。本函数和 Perl 的同名函数功能用法完全相同。参数 format 为压缩的格式,参见 pack 的格式表。


例子 1

代码: 全选
<?php

$data = "PHP";

print_r(unpack("C*",$data));

?>


输出:

Array

(

[1] => 80

[2] => 72

[3] => 80

)

例子 2

代码: 全选
<?php

$data = "PHP";

print_r(unpack("C*myint",$data));

?>


输出:

Array

(

[myint1] => 80

[myint2] => 72

[myint3] => 80

)

例子 3

代码: 全选
<?php

$bin = pack("c2n2",0x1234,0x5678,65,66);

print_r(unpack("c2chars/n2int",$bin));

?>


输出:

Array

(

[chars1] => 52

[chars2] => 120

[int1] => 65

[int2] => 66

)

玩了玩 PHP 的 pack/unpack !还是蛮简单的

2007-07-04 16:34

这几天要做双向的加解密,因为加密后的结果都是二进制的,不得不了解一下它了

小try了一把pack/unpack,基本用法还是蛮简单的,下面的例子基本上是给了个做数据库的原型(嘻嘻,不能用PHP5了,只好用PHP4的语法写)

<?php

/**

* 这是一个测试pack/unpack操作的东西

* @author 张心灵

* Email: zhangsilly@gmail.com

*

* 一下文件存储如下几个字段

* 姓名: 长度 8 字节

* 年龄: unsigned int

* Email: 长度 30 字节

*/

class Person_Data

{

/**

* 数据库文件路径

*

* @var string

*/

var $_database = './wps.db';

/**

* 打开一个数据库文件

*

* @param string $file 数据库文件名

*/

function openDb($file = './wps.db')

{

$this->_database = $file;

$this->_database = fopen($this->_database, 'ab+');

}

/**

* 向数据库中写入一条记录

*

* @param array $data PHP4真的丑死了

* @return void

*/

function writeRecord($data)

{

$name = pack('a8', $data['name']);

$age = pack('S', $data['age']);

$email = pack('a30', $data['email']);

fwrite($this->_database, $name . $age . $email);

}

/**

* 读取一条记录

*

* @param int $count optional default to 0 记录id数

* @return array

*/

function read($count = 0)

{

rewind($this->_database);

fseek($this->_database, 40 * $count);

$return = array();

$return['name'] = unpack('a8', fread($this->_database, 8));

$return['name'] = $return['name'][1];

$return['age'] = unpack('S', fread($this->_database, 2));

$return['age'] = $return['age'][1];

$return['email'] = unpack('a30', fread($this->_database, 30));

$return['email'] = $return['email'][1];

return $return;

}

}

代码: 全选
$me = array(    'name' => '张心灵', 

                'age'  => 23,

                'email' => 'zhangsilly@gmail.com');

$data = new Person_Data();

$data->openDb('./wps.db');

//$data->writeRecord($me);

print_r($data->read(1));


以上文件运行了两侧,写入了两行记录,最后我读取第二行记录(索引自然从 1 开始)

运行一切正常:

Array

(

[name] => 张心灵

[age] => 23

[email] => zhangsilly@gmail.com

)

2009-03-15 22:11

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

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

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

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

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


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


一些规则:

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

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


下面还是用例子来说明用法会容易理解一点:

关于Pack:

下面的第一部分把数字值包装成字节:

代码: 全选
$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 = pack("CCxxCC", 65, 66, 67, 68);      # $out 等于 "AB\0\0CD"


打包你的短整数并不意味着你就可移植了:

代码: 全选
$out = pack("s2", 1, 2);       

# 在小头在前的机器上是 "\1\0\2\0"

# 在大头在前的机器上是 "\0\1\0\2"

在二进制和十六进制包装上,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\0\0\0\0\0\0"


关于unpack:

代码: 全选
array unpack ( string $format, string $data )

$data = "010000020007";

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

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


最后本文开头讲到的协议使用pack/unpack 举例程序代码为 :
代码: 全选
$lastact   = pack('SCSa32a32',0x0040, 0x00, 0x0006, $username, $passwd );

unpack('Sint1/Cchar1/Sint2/Cchar2/',$lastmessage);
在指尖流浪
1. Everything changes and ends. 所有的事情在变化,都有终结
2. Things do not always go according to plan. 事情总会出乎意料(计划)之外
3. Life is not always fair. 生活并不总是公平
4. Pain is part of life. 痛苦是生活的一部分
5. People are not loving and loyal all the time. 人们并不总是热爱和忠诚
头像
NT流人
网站管理员
 
帖子: 744
加入时间: 2008年 1月 2日 13:15

回到 PHP高手区

在线用户

正在浏览此版面的用户:没有注册用户 和 1 位游客