<p>很多时候,数据并不是用文本的方式保存的,这就需要将二进制数据读取出来,还原成我们需要的格式。PHP在二进制处理方面也提供了强大的支持。</p><p></p><p>任务</p><p>下面以读取并分析一个PNG图像的文件头为例,讲解如何使用PHP读取和分析二进制文件。</p><p>涉及函数</p><p>fopen</p><p>fread</p><p>unpack</p><p>bin2hex</p><p>PNG格式简介</p><p>为了完成任务,下面简单介绍一下PNG文件格式。 PNG是一种无损压缩的图像文件格式,该格式的第1-8字节保存着PNG署名域,内容如下:</p><p>十进制: 137 80 78 71 13 10 26 10</p><p>十六进制: 89 50 4e 47 0d 0a 1a 0a</p><p>我们的任务就是将这个文件头读取出来。</p><p>更详细的关于PNG格式的介绍: * http://www.w3.org/TR/2003/REC-PNG-20031110/ * http://www.libpng.org/pub/png/</p><p>读取文件</p><p>$filePath = &quot;icon.png&quot;;</p><p>//必须使用rb来读取文件,这样能保证跨平台二进制数据的读取安全</p><p>$fh = fopen($filePath, &quot;rb&quot;);</p><p>//仅读取前面的8个字节</p><p>$head = fread($fh, 8);</p><p>fclose($fh);</p><p>上面的代码已经把我们需要的8个字节读入变量head中了。head是一个保存二进制数据的数组,我们还需要对它做一些操作才能得到我们需要的数据。</p><p>unpack</p><p>unpack可以将二进制数据解析成关系数组,它接受2个参数,第一个提供解析方式字符串(见下方),第二个参数就提供我们前面读出的head变量就可以了。</p><p>a:NULL填充的字节串</p><p>A:空格填充的字节串</p><p>h:十六进制数,低四位字节优先</p><p>H:十六进制数,高四位字节优先</p><p>c:有符号字符</p><p>C:无符号字符</p><p>s:有符号短整型(总是16位,机器字节序)</p><p>S:无符号短整型(总是16位,机器字节序)</p><p>n:无符号短整型(总是16位,大尾字节序)</p><p>v:无符号短整型(总是16位,小尾字节序)</p><p>I:有符号整型(机器相关大小和字节序)</p><p>I:无符号整型(机器相关大小和字节序)</p><p>l:有符号长整型(总是32位,机器字节序)</p><p>L:无符号长整型(总是32位,机器字节序)</p><p>N:无符号长整型(总是32位,大尾字节序)</p><p>V:无符号长整型(总是32位,小尾字节序)</p><p>f:浮点数(机器相关大小和表示)</p><p>d:双精度数(机器相关大小和表示)</p><p>x:空字节</p><p>X:倒退一个字节</p><p>@:用NULL填充绝对位置</p><p>unpack的第一个参数在在使用上有一点点小技巧,下面是范例:</p><p>C 读取1个字符,返回的数组索引为1</p><p>C4 读取4个字节,每个字节一个字符,返回的数组索引为1,2,3,4</p><p>C4head 读取4个字符,每个字节一个字符,返回的数组索引为head1,head2,head3,head4</p><p>Chead 读取1个字符,返回的数组索引为head</p><p>现在试着读取第1个字节:</p><pre class="brush:bash;toolbar:false">$arr=unpack(&quot;Chead&quot;,$head); print_r($arr); //Array([head]=&gt;137)</pre><p>读取所有的8个字节,用斜杠可以分隔:</p><pre class="brush:bash;toolbar:false">$arr=unpack(&quot;Chead/C3string/C4number&quot;,$head); print_r($arr); //Array([head]=&gt;137[string1]=&gt;80[string2]=&gt;78[string3]=&gt;71[number1]=&gt;13[number2]=&gt;10[number3]=&gt;26[number4]=&gt;10)</pre><p>把string开头的键拼成字符串:</p><pre class="brush:bash;toolbar:false">$arr=unpack(&quot;Chead/C3string/C4number&quot;,$head); for($i=1;$i&lt;=3;$i++) { $type.=chr($arr[&#39;string&#39;.$i]); } echo$type; //PNG bin2hex</pre><p>上面使用print_r打印出来的内容,都是十进制数字,如果希望直接得到十六进制值,可以使用bin2hex函数。</p><pre class="brush:bash;toolbar:false">echobin2hex($head[0]); //89</pre><p>注意,使用这种方法得到的是字符串,并不是数字。因此下面的条件是不成立的:</p><pre class="brush:bash;toolbar:false">if(bin2hex($head[0])==0x89) { echo&#39;match!&#39;; }</pre>
返回顶部 留言