php的二進位安全
本文主要從三個角度來闡述php的二進位安全:1. 什麼叫php的二進位安全;2. 什麼結構確保了php的二進位安全;3. 這種結構還有哪些其它方面的應用?
做到知其然,也知其所以然。
一句話解釋:
php的內建函式在操作位元據時能保證達到預期的結果,例如str_replace、stristr、strcmp等函數,我們就說這些函數是二進位安全的。
舉個列子:
我們來對比一下C和php下的strcmp函數。
C代碼如下
main(){ char ab[] = "aa\0b"; char ac[] = "aa\0c"; printf("%d\n", strcmp(ab, ac)); printf("%d\n", strlen(ab)); }
結果:
0
2
解讀:
也就是說C語言認為ab和ac這兩個字串是相等的,而且ab的長度為2.
php代碼如下
結果:
int(-1)
int(4)
解讀:
也就是php語言認為ab和ac這兩個字串是相等的,而且ab的長度為4。
聰明的你,應該已經發現問題在哪了吧,不錯,對於c語言‘\0’是字串的結束符,所以在C語言中對於字串“aa\0b”,它讀到'\0'就會預設字元讀取已經結束,而拋掉後面的字串'b',導致我們看到strlen(“aa\0b”)的值為2
那問題又來了,php都是C來開發的,為什麼php做到了二進位安全呢?
先來看看php的變數儲存zval結構
php會根據type的值來決定訪問value的哪個成員,為字串時,我們會訪問紅框標識的str結構,這便是底層字串的儲存結構,它有兩個值,一個是指向字串的指標val,另一個是記錄字串長度的len值,就是因為有len這個值,導致了php是二進位安全的:因為它不需要像C一樣通過是否遇到'\0'結尾符來判斷整個字串是否讀取完畢,而是通過len這個值指定的長度進行讀取。
可見一個小小的資料結構改進,為我們帶來了更多想象的空間,可謂是
結構的一小步,功能的一大步。
拓展:
這麼好用的結構,顯然會被到處使用,我們常用的redis,在底層儲存資料時就用到了這種結構,Redis 沒有直接使用 C 語言傳統的字串表示(以Null 字元結尾的字元數組),而是自己構建了一種名為簡單動態字串(simple dynamic string,SDS)的抽象類別型,並將 SDS 用作 Redis 的預設字串表示
看下SDS的結構定義
struct sdshdr { // 記錄 buf 數組中已使用位元組的數量 // 等於 SDS 所儲存字串的長度 int len; // 記錄 buf 數組中未使用位元組的數量 int free; // 位元組數組,用於儲存字串 char buf[];};可以看到,我們又見到了熟悉的len值,又是它保證了redis的儲存是二進位安全的
以下內容足以闡明這一點:(摘自http://redisbook.com/preview/sds/different_between_sds_and_c_string.html#id6)
C 字串中的字元必須符合某種編碼(比如 ASCII),並且除了字串的末尾之外,字串裡面不能包含Null 字元,否則最先被程式讀入的Null 字元將被誤認為是字串結尾 ——這些限制使得 C 字串只能儲存文本資料,而不能儲存像圖片、音頻、視頻、壓縮檔這樣的位元據。
舉個例子,如果有一種使用Null 字元來分割多個單詞的特殊資料格式, 2-17 所示,那麼這種格式就不能使用 C 字串來儲存,因為 C 字串所用的函數只會識別出其中的"Redis" ,而忽略之後的 "Cluster" 。
雖然資料庫一般用於儲存文本資料,但使用資料庫來儲存位元據的情境也不少見,因此,為了確保 Redis 可以適用於各種不同的使用情境,SDS 的 API 都是二進位安全的(binary-safe):所有 SDS API 都會以處理二進位的方式來處理 SDS 存放在buf 數組裡的資料,程式不會對其中的資料做任何限制、過濾、或者假設 ——資料在寫入時是什麼樣的,它被讀取時就是什麼樣。
這也是我們將 SDS 的 buf 屬性稱為位元組數組的原因 ——Redis 不是用這個數組來儲存字元,而是用它來儲存一系列位元據。
比如說,使用 SDS 來儲存之前提到的特殊資料格式就沒有任何問題,因為 SDS 使用 len 屬性的值而不是Null 字元來判斷字串是否結束, 2-18 所示。
buf"]; buf [label = " { 'R' | 'e' | 'd' | 'i' | 's' | '\\0' | 'C' | 'l' | 'u' | 's' | 't' | 'e' | 'r' | '\\0' | '\\0' } "]; // sdshdr:buf -> buf;}">
通過使用二進位安全的 SDS ,而不是 C 字串,使得 Redis 不僅可以儲存文本資料,還可以儲存任意格式的位元據。
http://www.bkjia.com/PHPjc/925226.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/925226.htmlTechArticlephp的二進位安全 本文主要從三個角度來闡述php的二進位安全:1. 什麼叫php的二進位安全;2. 什麼結構確保了php的二進位安全;3. 這種結構還...