分享

关于 php 中 pack 、unpack、 ord 的理解和用法

 yliu277 2016-03-10

pack函数说明:本函数用来将资料压缩打包到位的字符串之中。

首先  pack的 格式 为  pack('最原始数据使用的格式,'原始数据'');

pack('a1','h')或者pack('a*','h');

每个字母(比如上面的a)后面都可以跟着一个数字,表示count(计数)来解释成某种形式的重复计数或者长度(换算后字符长度发生了改变),具体情况取决于格式。除了a,A,b,B,h,H,P,和 Z 之外,所有格式的count 都是重复次数(也就是说 上面的这几个字符后面的“计数”指的是获取字符串的长度),ack('a*','h')字母(比如上面的a)后面都可以跟着一个数字,表示count(计数),解释成某种形式的重复计数或者长度,具体情况取决于格式。除了a,A,b,B,h,H,P,和 Z 之外,所有格式的count 都是重复次数(也就是说 上面的这几个字符后面的“计数”指的是获取字符串的长度),因此 pack 从 LIST 里吃进那么多数值(除了第一个参数,剩下的参数可以理解成都在一个列表中)。如果 count 是一个 *表示剩下的所有东西。【pack('a*',100,20) :只取第一个参数的所有字符  ,pack('C*',100,101,102):把这三个参数都换算pack('Cf'',224,3.14,100)  :C:换算244,f:换算剩下所有的参数】

理解:pack 返回的数据 都用通过 ASCII码换算过后的,如果单纯理解ASCII换算的话 ,可以用一个php函数  ord():返回字符串第一个字符的 ASCII 值。

比如 ord(‘h’)和ord(‘hello’)都是返回一个十进制数:114【占用三个字节】,而pack('a*','h')也返回114, 但是在ord的基础上对字节进行了 增加或者减少(也就是对位的增加减少)当前这个列子上没有增加也没减少   比如pack('C',100)  返回 一个字节为:d。

上面的'a' 指的是转成什么字符,“*”指的是剩下的所有东西,如果改成‘a1’的话 ,就是获取原始数据的第一个字符转成a格式的字符。

下面是pack所有的格式(网上全部都是列出来的,虽然一看见这么多 觉着恶心):

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 一个空结束的(和空填充的)字节串
@ 用空字节填充绝对位置


通过下面的代码 可以看出他们的不同:

//A字符
$str=(pack('A*', '中国'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//H字符
$str=(pack('H*', 'fffe'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//C字符
$str=(pack('C*', '55','56','57'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str);
//i字符 短整形 32位 4个字节 64位8个字节
$str=(pack('i', '100'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//s字符 短整形 2个字节
$str=(pack('s', '100'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//l字符 长整形 4个字节
$str=(pack('l', '100'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//f字符 单精度浮点 4个字节
$str=(pack('f', '100'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


//d字符 双精度浮点 8个字节
$str=(pack('d', '100'));
echo $str,'=',strlen($str),'字节\n';
getAscill($str); 


function getAscill($str)
{
$arr=str_split($str);
foreach ($arr as $v)
{
echo $v,'=',ord($v),'\n';
}
echo '=============\r\n\r\n';
}

/*pack作用:节省空间、加密格式 */

$code=array(
'username'=>array('A20','张三adfb12'),
'pass'=>array('A10','asdf*#1'),
'age'=>array('C','23'), //转成一个字节  节省了空间
'birthday'=>array('I','19900101'), //转成4个字节,想象一下 如果第二个参数长度一直增大比如‘199001010001256325’ ,到那时就更可以看出节省的空间了(因为不论多大 都是占用4个字节)
'email'=>array('A50','zhangsan@163.com')); //进行了加密
$stream=join('\0',packByArr($code));
echo $stream,strlen($stream);

file_put_contents('c:/1.txt',$stream);    //将流保存起来便于下面读取

function packByArr($arr)  {
         $atArr=array();
         foreach ($arr as $k=>$v) {
                  $atArr[]=pack($v[0],$v[1]);
         }
         return $atArr;
}
function getAscill($str) {
         $arr=str_split($str);
         foreach ($arr as $v) {
                  echo $v,'=',ord($v),'\n';
         }
}


Unpack解包
解包需要按照,打包方式读取,该读取多长,该用什么类型读取,必须与打包规定一样。
$code=array(
'username'=>array('A20'),
'pass'=>array('A10'),
'age'=>array('C'),
'birthday'=>array('I'),
'email'=>array('A50'));
$stream=file_get_contents('c:/1.txt');
var_dump(packByArr($stream,$code));
function packByArr($str,$code) {
         $Arr=explode('\0',$str);
         $atArr=array();
         $i=0;
         foreach ($code as $k=>$v) {
                  $atArr[$k]=unpack($v[0],$Arr[$i]);
                  $i ;
         }
         return $atArr;
}





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多