爲何 php 手冊裏常常說某個函數是二進制安全的?咱們日常使用函數的時候也沒發現有什麼區別呀,那麼二進制安全究竟是什麼意思呢?php
<?php echo strlen("abc"); // 3 echo strlen("abc\0"); // 4 echo strlen("abc\0d"); // 5 echo strlen("abc\0def"); // 7
從上面的規律能夠看出\0
被認爲是一個字符,其實在上面的式子中\0
是一個ascii
字符。html
補課簡單說明下 ascii 碼安全
咱們知道,計算機內部,全部信息最終都是一個二進制值。每個二進制位(bit)有0和1兩種狀態,所以八個二進制位就能夠組合出256種狀態,這被稱爲一個字節(byte)。也就是說,一個字節一共能夠用來表示256種不一樣的狀態,每個狀態對應一個符號,就是256個符號,從
00000000
到11111111
。php7上個世紀60年代,美國製定了一套字符編碼,對英語字符與二進制位之間的關係,作了統一規定。這被稱爲 ASCII 碼,一直沿用至今。函數
man ascii
ascii 碼前 33 個都是控制字符,好比咱們最熟悉的換行
,都是不可見的字符。ui
Oct Dec Hex Char Oct Dec Hex Char ──────────────────────────────────────────────────────────────────────── 000 0 00 NUL '\0' 100 64 40 @ 001 1 01 SOH (start of heading) 101 65 41 A 002 2 02 STX (start of text) 102 66 42 B 003 3 03 ETX (end of text) 103 67 43 C 004 4 04 EOT (end of transmission) 104 68 44 D 005 5 05 ENQ (enquiry) 105 69 45 E 006 6 06 ACK (acknowledge) 106 70 46 F 007 7 07 BEL '\a' (bell) 107 71 47 G 010 8 08 BS '\b' (backspace) 110 72 48 H 011 9 09 HT '\t' (horizontal tab) 111 73 49 I 012 10 0A LF '\n' (new line) 112 74 4A J
從上面的表中能夠看到八進制012
和十六進制0A
都表示換行編碼
echo "abc\012d"; echo "\n"; echo "abc\x0Ad"; echo "\n"; echo "abc\x0ad"; echo "\n"; echo "abc\nd"; echo "\n";
輸出結果url
abc d abc d abc d abc d
ascii 碼第一個\0
則表示空字符
,因此執行spa
echo "abc\0d";
輸出的就是abcd
。到這裏上面的長度計算想必你們都弄明白了吧。.net
這裏再留個你們一個思考題,
strlen
和mb_strlen
有什麼區別?
有興趣的能夠看看我這篇博客 https://mengkang.net/1129.html
#include <stdio.h> #include <string.h> int main(){ printf("%d\n",strlen("abc")); // 3 printf("%d\n",strlen("abc\0")); // 3 printf("%d\n",strlen("abc\0d")); // 3 printf("%d\n",strlen("abc\0def")); // 3 }
經過上面的例子能夠觀察到\0
及其之後都不在strlen
的計算範圍內。在C語言裏字符串都以\0
做爲結束符。
#include <stdio.h> #include <string.h> int main(){ printf("%s\n","abc\0def"); // abc }
因此,由於字符串中間有\0
而影響程序邏輯和結果的狀況,叫非二進制安全。
經過上面的兩個實驗發現只有C裏面咱們才須要關注函數的二進制安全問題嘛,PHP 也會遇到相似的問題麼?我怎麼歷來遇到過。下面兩個例子。
<?php echo date("Y\0/m/d");
在線執行結果 https://3v4l.org/dqXhf
能夠看出來date
函數是把入參"0/m/d"去掉了,不過在 php7 裏修復了該問題。
<?php var_export(strcoll("a\0b","a")); var_export(strcmp("a\0b","a"));
這兩個函數都是比較字符串「大小」,strcoll
會根據環境變量 LC_COLLATE
所指定的文字排列次序來比較兩字符串的大小,默認 LC_COLLATE 爲"POSIX"或"C",strcoll() 和 strcmp() 同樣根據ASCII比較字符串大小。
strcoll 函數是官方手冊在線說明了的非二進制安全的函數。https://www.php.net/manual/en/function.strcoll.php
下面這個兩個計算長度分辨是多少,下次課咱們一塊兒分析 php 和 c 裏面單引號和雙引號的區別。
<?php echo strlen("123\0456"); echo strlen('123\0456');
本文爲雲棲社區原創內容,未經容許不得轉載。