程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> php的二進制安全

php的二進制安全

編輯:關於PHP編程

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 語言傳統的字符串表示(以空字符結尾的字符數組),而是自己構建了一種名為簡單動態字符串(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),並且除了字符串的末尾之外,字符串裡面不能包含空字符,否則最先被程序讀入的空字符將被誤認為是字符串結尾 ——這些限制使得 C 字符串只能保存文本數據,而不能保存像圖片、音頻、視頻、壓縮文件這樣的二進制數據。

舉個例子,如果有一種使用空字符來分割多個單詞的特殊數據格式,如圖 2-17 所示,那麼這種格式就不能使用 C 字符串來保存,因為 C 字符串所用的函數只會識別出其中的 "Redis" ,而忽略之後的 "Cluster"

digraph {    label =

雖然數據庫一般用於保存文本數據,但使用數據庫來保存二進制數據的場景也不少見,因此,為了確保 Redis 可以適用於各種不同的使用場景,SDS 的 API 都是二進制安全的(binary-safe):所有 SDS API 都會以處理二進制的方式來處理 SDS 存放在 buf 數組裡的數據,程序不會對其中的數據做任何限制、過濾、或者假設 ——數據在寫入時是什麼樣的,它被讀取時就是什麼樣。

這也是我們將 SDS 的 buf 屬性稱為字節數組的原因 ——Redis 不是用這個數組來保存字符,而是用它來保存一系列二進制數據。

比如說,使用 SDS 來保存之前提到的特殊數據格式就沒有任何問題,因為 SDS 使用 len 屬性的值而不是空字符來判斷字符串是否結束,如圖 2-18 所示。

digraph {    label = buf;}">

通過使用二進制安全的 SDS ,而不是 C 字符串,使得 Redis 不僅可以保存文本數據,還可以保存任意格式的二進制數據。



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved