引子
為什麼 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
字元。
補課簡單說明下 ascii 碼我們知道,計算機內部,所有資訊最終都是一個二進位制值。每一個二進位制位(bit)有0和1兩種狀態,因此八個二進位制位就可以組合出256種狀態,這被稱為一個位元組(byte)。也就是說,一個位元組一共可以用來表示256種不同的狀態,每一個狀態對應一個符號,就是256個符號,從
`00000000
到11111111
。上個世紀60年代,美國製定了一套字元編碼,對英語字元與二進位制位之間的關係,做了統一規定。這被稱為 ASCII 碼,一直沿用至今。
man ascii
ascii 碼前 33 個都是控制字元,比如我們最熟悉的換行
,都是不可見的字元。
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";
輸出結果
abc
d
abc
d
abc
d
abc
d
ascii 碼第一個\0
則表示空字元
,所以執行
echo "abc\0d";
輸出的就是abcd
。到這裡上面的長度計算想必大家都弄明白了吧。
這裡再留個大家一個思考題,strlen
和mb_strlen
有什麼區別?
有興趣的可以看看我這篇部落格 https://mengkang.net/1129.html
C 實驗
#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 也會遇到類似的問題麼?我怎麼從來遇到過。下面兩個例子。
案例1
<?php
echo date("Y\0/m/d");
案例來源:https://stackoverflow.com/que...線上執行結果 https://3v4l.org/dqXhf
可以看出來date
函式是把入參"0/m/d"去掉了,不過在 php7 裡修復了該問題。
案例2
<?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...
課後思考
下面這個兩個計算長度分辨是多少,下次課我們一起分析 php 和 c 裡面單引號和雙引號的區別。
<?php
echo strlen("123\0456");
echo strlen('123\0456');
安利
背景介紹
你是否一直有這樣的經歷,使用 php 作為主語言開發已經有兩三年了,一直想學習好 C 語言來作為自己的技術壁壘,卻又難以突破。每次自學都是堅持幾天,if else 資料型別看得滾瓜爛熟,看到晦澀的指標,深奧的記憶體,就偃旗息鼓。
又苦沒有什麼實戰專案,最後只能放棄。每每過些時日,拒絕平庸的你,騷動的內心,又拿起那本被遺忘在角落的《21 天 C 語言從......》擦拭掉封面上的塵土,翻開了第一頁,信誓旦旦,迴圈反覆,但卻依舊如初,一直在 C 語言大門之外徘徊,技術一直止步不前。
安利推薦
作為泥腿子的我,把自己學習過程中總結的一些經驗結合 php 語言特色和 c 語言對比學習,結合專案實戰,總結成一個系列課,也許非常適合你,歡迎上車。《C 語言零基礎 phper 翻身仗》https://segmentfault.com/ls/1...