Phper 學 C 興趣入門 - 爲何 php 手冊裏常常說某個字符串函數是二進制安全的

引子

爲何 php 手冊裏常常說某個函數是二進制安全的?咱們日常使用函數的時候也沒發現有什麼區別呀,那麼二進制安全究竟是什麼意思呢?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個符號,從0000000011111111php7

上個世紀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

這裏再留個你們一個思考題,strlenmb_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/questions/36933837/why-are-there-binary-safe-and-binary-unsafe-functions-in-php

在線執行結果 https://3v4l.org/dqXhf

image.png

能夠看出來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/function.strcoll.php

課後思考

下面這個兩個計算長度分辨是多少,下次課咱們一塊兒分析 php 和 c 裏面單引號和雙引號的區別。

<?php
echo strlen("123\0456");
echo strlen('123\0456');

 

原文連接

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索