很多時候,數據並不是用文本的方式保存的,這就需要將二進制數據讀取出來,還原成我們需要的格式。PHP在二進制處理方面也提供了強大的支持。
任務
下面以讀取並分析一個PNG圖像的文件頭為例,講解如何使用PHP讀取和分析二進制文件。
涉及函數
PNG格式簡介
為了完成任務,下面簡單介紹一下PNG文件格式。 PNG是一種無損壓縮的圖像文件格式,該格式的第1-8字節保存着PNG署名域,內容如下:
- 十進制: 137 80 78 71 13 10 26 10
- 十六進制: 89 50 4e 47 0d 0a 1a 0a
我們的任務就是將這個文件頭讀取出來。
更詳細的關於PNG格式的介紹: * http://www.w3.org/TR/2003/REC-PNG-20031110/ * http://www.libpng.org/pub/png/
讀取文件
1 2 3 4 5 6 |
$filePath = "icon.png"; //必須使用rb來讀取文件,這樣能保證跨平台二進制數據的讀取安全 $fh = fopen($filePath, "rb"); //僅讀取前面的8個字節 $head = fread($fh, 8); fclose($fh); |
上面的代碼已經把我們需要的8個字節讀入變量head中了。head是一個保存二進制數據的數組,我們還需要對它做一些操作才能得到我們需要的數據。
unpack
unpack可以將二進制數據解析成關系數組,它接受2個參數,第一個提供解析方式字符串(見下方),第二個參數就提供我們前面讀出的head變量就可以了。
- a:NULL填充的字節串
- A:空格填充的字節串
- h:十六進制數,低四位字節優先
- H:十六進制數,高四位字節優先
- c:有符號字符
- C:無符號字符
- s:有符號短整型(總是16位,機器字節序)
- S:無符號短整型(總是16位,機器字節序)
- n:無符號短整型(總是16位,大尾字節序)
- v:無符號短整型(總是16位,小尾字節序)
- I:有符號整型(機器相關大小和字節序)
- I:無符號整型(機器相關大小和字節序)
- l:有符號長整型(總是32位,機器字節序)
- L:無符號長整型(總是32位,機器字節序)
- N:無符號長整型(總是32位,大尾字節序)
- V:無符號長整型(總是32位,小尾字節序)
- f:浮點數(機器相關大小和表示)
- d:雙精度數(機器相關大小和表示)
- x:空字節
- X:倒退一個字節
- @:用NULL填充絕對位置
unpack的第一個參數在在使用上有一點點小技巧,下面是范例:
- C 讀取1個字符,返回的數組索引為1
- C4 讀取4個字節,每個字節一個字符,返回的數組索引為1,2,3,4
- C4head 讀取4個字符,每個字節一個字符,返回的數組索引為head1,head2,head3,head4
- Chead 讀取1個字符,返回的數組索引為head
現在試着讀取第1個字節:
讀取所有的8個字節,用斜杠可以分隔:
1 2 3 |
$arr = unpack("Chead/C3string/C4number", $head); print_r($arr); //Array ( [head] => 137 [string1] => 80 [string2] => 78 [string3] => 71 [number1] => 13 [number2] => 10 [number3] => 26 [number4] => 10 ) |
把string開頭的鍵拼成字符串:
1 2 3 4 5 6 7 |
$arr = unpack("Chead/C3string/C4number", $head); for($i=1;$i<=3;$i++) { $type.=chr($arr['string'.$i]); } echo $type; //PNG |
bin2hex
上面使用print_r打印出來的內容,都是十進制數字,如果希望直接得到十六進制值,可以使用bin2hex函數。
1 2 |
echo bin2hex($head[0]); //89 |
注意,使用這種方法得到的是字符串,並不是數字。因此下面的條件是不成立的:
1 2 3 4 |
if(bin2hex($head[0]) == 0x89) { echo 'match!'; } |