亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > PHP > 正文

PHP中的pack函數和unpack函數的詳細介紹(附代碼)

2024-09-04 11:49:44
字體:
來源:轉載
供稿:網友

本篇文章給大家帶來的內容是關于PHP中的pack函數和unpack函數的詳細介紹(附代碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

PHP有兩個重要的冷門函數:pack和unpack。在網絡編程,讀寫圖像文件等場景,這兩個函數幾乎必不可少。鑒于文件讀寫/網絡編程,或者說字節流處理的重要性,掌握這兩個函數是邁向高級PHP編程的基礎。

本文先介紹字節和字符的區別,說明兩個函數存在的必要性和重要性。然后介紹基本用法和使用場景,讓讀者對其有大體了解,為實際使用中奠定基礎。

字節和字符:

PHP的優勢是簡單易用,熟練運用 字符串 和 數組 相關函數就能抗住一般的需求。日常工作中多用到字符串,所以PHP開發對字符都比較熟悉,稍微資深點基本能也能弄清字符編碼。但字符的伴生概念:字節,不少PHP開發并不知曉/熟悉。

這不怪他們。PHP世界里極少出現“字節(流)”的概念:沒有byte關鍵字(當然也沒有char),官方文檔也沒提字節;沒有原生的數組支持(常用的array其實是hashtable);當然字符串(string)能表達其他語言中的字節數組(Byte Array, byte[])。

字節和字符有什么聯系和區別呢?簡單來說字節是計算機存儲和操作的最小單位,字符是人們閱讀的最小單位;字節是存儲(物理)概念,字符是邏輯概念;字節代表數據(內涵和本質),字符代表其含義;字符由字節組成。

舉幾個例子說明兩者區別:“中國”包含2個字符,GBK編碼表示需要4個字節,UTF-8編碼需要6個字節;數字“1234567890”,包含10個字符,用int32類型表示只需4個字節;下面的圖片占用42582個字節,用字符表示是“我老婆”,只占用3個字符:

再舉一個常用的例子說明字符和字節的區別。開發中我們常用md5算法獲取數據的哈希值,算法返回一個128位(bit)的數據(16個字節)。為方便查看其值,人們約定成俗地用十六進制表示,結果就是我們熟知的32位長度的字符串(不區分大小寫)。32長度字符串不是md5算法的必然結果,16字節數據才是其本質。如果你愿意,可以用一個小于2^128的數字表示哈希結果,也可以將16字節base64編碼后作為其結果。所以常用的32位哈希值與md5返回的16字節關系為:一個是字符表示,另一個則是其本質(字符數組)(PHP的md5函數第二個參數值為true便可得到16字節數據,或hash函數第三個參數為true)。

相關概念還有字節序、字符編碼等,本文不做展開。

引言:

PHP中專門處理字符串的函數有幾十個,加上正則、時間等函數,字符串處理的函數不下百個。相比之下字節處理門庭冷落,相關函數寥寥無幾。除了常用的ord/chr,哈希加密函數返回的原始字節、openssl庫的openssl_random_pseudo_bytes等函數真正處理或返回 字節外,最重要的兩個字節處理函數是pack和unpack。

本節從問題引出pack函數的使用。

問題:

考慮一個簡單的問題:宇宙的終極答案42在內存中是如何表示的(或者說怎么獲取其字節數組)?

因為42是一個整數,根據硬件不同,其占用字節大小可能為1, 2, 4, 8等。這里我們限定一個整數占用4個字節,于是問題的等價表述為:怎樣將一個整數轉換成字節數組(本機序,4個字節)?

分析:

因為是多字節,所以要考慮字節序的問題。42不超過255,只占用一個字節,故而其他三個字節都是0。據此得到結論:如果是大端序(低位字節存放在地址高位),四個字節分別是:0 0 0 42;如果是小端序,結果則是:42 0 0 0。

那怎么知道機器的字節序呢?PHP沒有提供相關功能,也不能像C語言直接取地址訪問字節數據。無所不能的PHP該怎么搞定字節序,或者說完成數據向字節的轉換?

方案:

PHP應用層面,數據向字節(數組)的轉換是pack的專場,字節(數組)向數據的轉換則是unpack的專場。除這兩個函數,字節數組(或二進制數據)向數據的轉換幾無可能(如果有請不吝指教)。

現在我們用pack函數獲取42在內存中的字節數組。相關代碼如下:

  1. function intToBytes(int $num) : string { 
  2.  
  3.     return pack("l"$num); 
  4.  
  5. } 
  6.  
  7. function outputBytes(string $bytes) { 
  8.  
  9.     echo "bytes: "
  10.  
  11.     for ($i = 0; $i < strlen($bytes); ++ $i) { 
  12.  
  13.         echo ord($bytes[$i]), " "
  14.  
  15.     } 
  16.  
  17.     echo PHP_EOL; 
  18.  
  19.  
  20. //Vevb.com 
  21.  
  22. outputBytes(intToBytes(42)); 
  23.  
  24. // 程序輸出: 
  25.  
  26. bytes: 42 0 0 0 

本人計算機用的英特爾的CPU,x86架構是小端序,所以程序輸出符合預期。

延伸一下,怎么判斷機器的字節序?有了pack函數,答案非常簡單:

  1. function bigEndian() : bool { 
  2.  
  3.     $data = 0x1200; 
  4.  
  5.     $bytes = pack("s"$data); 
  6.  
  7.  
  8.  
  9.     return ord($bytes[0]) === 0x12; 
  10.  

調用函數便返回本機是否大端序。

上述是pack函數簡單的使用場景,接下來分別介紹pack和unpack函數。

pack和unpack

pack函數

pack是“打包/封包”的意思。如其名,pack函數的工作是將數據按照格式打包成字節數組。函數原型為:

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

形式上與printf系列函數相同:第一個參數是格式字符串,其余參數是要格式化的參數。不同之處在于pack函數的格式中不能出現元字符和量詞外的其他字符,所以不需要%符號。

上文的例子中使用了"l"和"s"兩個格式化元字符,pack函數的元字符主要分為三類:

字符串:a、A等;將數據轉成字符串,功能上與sprintf類似,例如整數32轉換成字符串"32";

字節:h和H;對字節進行16進制編碼,區別在于低位還是高位在前,功能上與dechex等函數類似;

char/short/int/long/float/double六種基本類型:c/s/i/l等;將數據轉換成對應類型的字節數組,除char類型外(暫)沒有其他函數可替代;

注意:char和a/A等的區別是a/A等輸入為字符(串),而's/S'的輸入要求是小于256的整數,輸入字符會得到0。

量詞比較簡單:數字和""兩種。例如"i2"表示將兩個參數按照整數轉換,"c"表示后續都按照char類型轉換。

unpack

unpack是pack的反向操作:將字節數組解析成有意義的數據。其函數原型為:

unpack ( string $format , string $data [, int $offset = 0 ] ) : array

unpack函數需要注意的是第一個參數和返回值。返回值好理解,pack函數相當于將除格式化參數外的參數數組(想象成call_user_func_array的參數)變成一個字節數組;unpack做相反的事情:釋放數據,得到輸入時的參數數組。

返回一個數組,其鍵分別是什么呢?這便是格式化參數($format)在pack和unpack的不同之處:unpack應該對釋放出來的數據命名,用"/"分隔各組數據。由于格式化參數允許有非元字符和量詞外的字符,為了區分數據,不同數據間的"/"分隔符必不可少。

一個例子:

  1. $bytes = pack("iaa*", 42, ":""The answer to life, the universe and everything"); 
  2.  
  3. outputBytes($bytes); 
  4.  
  5. $result = unpack("inumber/acolon/a*word"$bytes); 
  6.  
  7. print_r($result); 
  8.  
  9. // 程序輸出: 
  10.  
  11. bytes: 42 0 0 0 58 84 104 101 32 97 110 115 119 101 114 32 116 111 32 108 105 102 101 44 32 116 104 101 32 117 110 105 118 101 114 115 101 32 97 110 100 32 101 118 101 114 121 116 104 105 110 103 
  12. //Vevb.com 
  13. Array 
  14.  
  15.  
  16.     [num] => 42 
  17.  
  18.     [colon] => : 
  19.  
  20.     [word] => The answer to life, the universe and everything 
  21.  

如果不對釋放出來的數據命名會怎么樣?例如上例中unpack的格式化參數為:"i/a/a*",結果是什么呢?其結果為:

  1. Array 
  2.  
  3.  
  4.     [1] => The answer to life, the universe and everything 
  5.  

為何?官方文檔上如是說:

Caution If you do not name an element, numeric indices starting from 1 are used. Be aware that if you have more than one unnamed element, some data is overwritten because the numbering restarts from 1 for each element.

翻譯過來就是:如果你不對數據命名,默認的1, 2, 3...就用來當作鍵值。如果有多組數據,每組都用同樣的下標,會導致數據覆蓋。

所以能理解 "i/a/a*" 為何只剩最后一組數據了吧?

應用場景:

讀取圖像、word/excel文件,解析binlog、二進制ip數據庫文件等場合,pack和unpack幾乎必不可少。本文舉例說一下pack和unpack在網絡編程時協議解析的用途。

假設我們的tcp包格式為:前四個字節表示包大小,其余字節為數據內容。于是客戶(發送)端的send函數可以長這樣:

  1. public function send($data) { 
  2.  
  3.   // 這里假設$data已經做了序列化、加密等操作,是字節數組 
  4.  
  5.   // 計算報文長度,封裝報文 
  6.  
  7.   $len = strlen($data); 
  8.  
  9.   $header = pack("L"$len); 
  10.  
  11.   // 轉換成網絡(大端)序 
  12.  
  13.   $header = xxx 
  14.  
  15.   // 封包 
  16.  
  17.   $binary = $header . $data
  18.  
  19.   // 調用fwrite/socket_send等將數據寫入內核緩沖區 
  20.  
  21.   ... 
  22.  

服務(接收)端根據協議解析接收到的數據流:

  1. public function decodable($session$buffer) { 
  2.  
  3.   $dataLen = strlen($buffer); 
  4.  
  5.   // 非法數據包 
  6.  
  7.   if ($dataLen < 4) { 
  8.  
  9.     // 關閉連接、記錄ip等 
  10.  
  11.     .... 
  12.  
  13.     return NOT_OK; 
  14.  
  15.   } 
  16.  
  17.   // 獲取前四個字節 
  18.  
  19.   $header = substr($buffer, 0, 4); 
  20.  
  21.   // 轉換成主機序 
  22.  
  23.   $header = xxx 
  24.  
  25.   // 解析數據長度 
  26.  
  27.   $len = unpack("L"$header); 
  28.  
  29.   // 單個報文不能超過8M,例如限制上傳的圖像大小 
  30.  
  31.   if ($len > 8 * 1024 * 1024) { 
  32.  
  33.     // 關閉連接等 
  34.  
  35.     return NOT_OK; 
  36.  
  37.   } 
  38.  
  39.  
  40.  
  41.   // 檢查數據包是否滿足協議要求 
  42.  
  43.   if ($dataLen - 4 >= $len) { 
  44.  
  45.     return OK; 
  46.  
  47.   } 
  48.  
  49.   // 數據未全部到達,繼續等待 
  50.  
  51.   return NEED_DATA; 
  52.  

通過pack和unpack,我們順利的處理報文協議和二進制字節流的發送和解析。

如果你用/n作為報文分隔符,pack和unpack也許用不到。但在網絡通訊中直接傳遞字符畢竟少數(相當于明文傳送),大多數情況下的二進制數據流的解析還是要靠pack和unpack。

總結:

除分配內存,最重要的系統調用莫過于文件讀寫和網絡連接,而兩者的本質操作對象都是字節流。pack和unpack為PHP提供了底層字節操作的能力,在二進制數據處理中十分有用。有志于跳出web編程的PHP開發應該都要掌握這兩個函數。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色婷婷综合成人av| 色先锋资源久久综合5566| 国产亚洲一区精品| 欧美国产日本在线| 成人免费视频在线观看超级碰| 欧美日韩在线免费观看| 国产精品精品一区二区三区午夜版| 欧美尺度大的性做爰视频| 欧美成人在线影院| 国产精品尤物福利片在线观看| 国产精品视频资源| 国产亚洲精品综合一区91| 国产精品自产拍高潮在线观看| 国产精品高精视频免费| 日韩在线视频中文字幕| 国产在线高清精品| 亚洲少妇激情视频| 日韩av在线看| 97精品一区二区视频在线观看| 69国产精品成人在线播放| 国产成人在线精品| 欧美另类高清videos| 欧美限制级电影在线观看| 黑人精品xxx一区| 992tv成人免费视频| 亚洲国内高清视频| 欧美激情亚洲另类| 免费91麻豆精品国产自产在线观看| 日本人成精品视频在线| 国产成+人+综合+亚洲欧美丁香花| 激情久久av一区av二区av三区| 亚洲女人被黑人巨大进入| 精品中文字幕久久久久久| 欧美天堂在线观看| 亚洲精品国产拍免费91在线| 亚洲成人网av| 久久99精品久久久久久青青91| 国产一区二区三区精品久久久| 日韩中文字幕在线| 久久综合色88| 日韩精品在线观看视频| 欧美激情一区二区久久久| 欧洲精品毛片网站| 日日狠狠久久偷偷四色综合免费| 欧美日韩午夜视频在线观看| 亚洲第一页自拍| 精品国产1区2区| 亚洲精品中文字| 国产成人一区二区三区小说| 国产精品久久久999| 国产69精品久久久久9999| 国产成人久久久| 国产v综合ⅴ日韩v欧美大片| 日本伊人精品一区二区三区介绍| 久久精品99久久久香蕉| 欧美二区乱c黑人| 色狠狠久久aa北条麻妃| 91在线视频成人| 欧美另类极品videosbest最新版本| 中文字幕国产亚洲2019| 一区二区三区亚洲| 亚洲精品一区二区久| 国产精品91久久| 亚洲午夜久久久久久久| 国产精品久久久久久久久久久不卡| 国产成人综合亚洲| 亚洲国产日韩一区| 精品在线观看国产| 国产精品欧美一区二区三区奶水| 日韩中文在线视频| 国产成人精品免高潮在线观看| 中文字幕精品在线视频| 国产精品91在线| 69久久夜色精品国产69| 成人欧美一区二区三区黑人孕妇| 一区二区三区精品99久久| 精品性高朝久久久久久久| 国产精品久久久亚洲| 国产精品成人品| 欧美一区二区三区精品电影| 国产中文欧美精品| 国产精品一区二区三区久久久| 亚洲国产日韩精品在线| 美女久久久久久久| 精品久久久中文| 久久99精品久久久久久琪琪| 欧美理论电影在线观看| 性欧美亚洲xxxx乳在线观看| 欧美亚洲另类制服自拍| 日韩欧美精品网址| 亚洲欧美日韩视频一区| 国产视频精品一区二区三区| 97av视频在线| 日韩在线播放一区| 国产精品入口夜色视频大尺度| 欧美丝袜一区二区三区| 26uuu另类亚洲欧美日本老年| 91九色精品视频| 亚州成人av在线| 日韩av在线播放资源| 97精品一区二区视频在线观看| 国产精品高潮粉嫩av| 在线亚洲男人天堂| 91成人在线播放| 亚洲一区美女视频在线观看免费| 国产精品久久久久久亚洲影视| 日韩欧美在线播放| 亚洲成人av在线| 国产精品美女www| 17婷婷久久www| 清纯唯美日韩制服另类| 欧美另类精品xxxx孕妇| 久久福利网址导航| 136fldh精品导航福利| 992tv成人免费影院| 久久精品国产精品亚洲| 色综合伊人色综合网站| 国产精品情侣自拍| 97久久精品视频| 日韩小视频在线观看| 国产999在线观看| 欧美亚洲视频在线看网址| 亚洲色图国产精品| 亚洲电影天堂av| 韩国精品美女www爽爽爽视频| 中文字幕av一区中文字幕天堂| 日韩av免费在线看| 亚洲综合中文字幕68页| 亚洲性视频网站| 91久久久久久| 亚洲在线免费视频| 国产视频久久久久久久| 亚洲欧美综合图区| 狠狠久久亚洲欧美专区| 91免费看片在线| 亚洲一区二区三区视频播放| 亚洲成av人影院在线观看| 91在线色戒在线| 亚洲人成电影在线| 日韩av在线直播| 91深夜福利视频| 福利视频导航一区| 中文字幕精品av| 岛国av午夜精品| www.国产精品一二区| 亚洲欧洲国产一区| 欧美在线视频a| 欧美噜噜久久久xxx| 亚洲国产精品美女| 亚洲人成电影网站色| 国产美女久久久| 亚洲xxxx3d| 欧美小视频在线观看| 亚洲精品自产拍| 亚洲国产成人精品久久久国产成人一区| 欧美高清videos高潮hd| 欧美激情videos| 欧美日韩国产色视频| 欧美一级黄色网| 国产91免费观看| 日韩av一卡二卡| 久久艹在线视频| 亚洲精品视频网上网址在线观看| 韩剧1988免费观看全集|