ホームページ > バックエンド開発 > PHPチュートリアル > php_PHP チュートリアルのバイナリ セキュリティ

php_PHP チュートリアルのバイナリ セキュリティ

WBOY
リリース: 2016-07-13 10:12:01
オリジナル
1253 人が閲覧しました

php的二进制安全

本文主要从三个角度来阐述php的二进制安全:1. 什么叫php的二进制安全;2. 什么结构确保了php的二进制安全;3. 这种结构还有哪些其它方面的应用?

做到知其然,也知其所以然。

一句话解释:

php的内部函数在操作二进制数据时能保证达到预期的结果,例如str_replace、stristr、strcmp等函数,我们就说这些函数是二进制安全的。

举个列子:

我们来对比一下C和php下的strcmp函数。

C代码如下

main(){
    char ab[] = "aaphp_PHP チュートリアルのバイナリ セキュリティ0b";
    char ac[] = "aaphp_PHP チュートリアルのバイナリ セキュリティ0c";
    printf("%dphp_PHP チュートリアルのバイナリ セキュリティn", strcmp(ab, ac));
    printf("%dphp_PHP チュートリアルのバイナリ セキュリティn", strlen(ab));
 }
ログイン後にコピー

结果:

0

2

解读:

也就是说C语言认为ab和ac这两个字符串是相等的,而且ab的长度为2.


php代码如下

<?php
    $ab = "aaphp_PHP チュートリアルのバイナリ セキュリティ0b"; 
    $ac = "aaphp_PHP チュートリアルのバイナリ セキュリティ0c";
    var_dump(strcmp($ab, $ac));
    var_dump(strlen($ab));
&#160;?>
ログイン後にコピー
结果:

int(-1)

int(4)

解读:

也就是php语言认为ab和ac这两个字符串是相等的,而且ab的长度为4。

聪明的你,应该已经发现问题在哪了吧,不错,对于c语言‘php_PHP チュートリアルのバイナリ セキュリティ0’是字符串的结束符,所以在C语言中对于字符串“aaphp_PHP チュートリアルのバイナリ セキュリティ0b”,它读到'php_PHP チュートリアルのバイナリ セキュリティ0'就会默认字符读取已经结束,而抛掉后面的字符串'b',导致我们看到strlen(“aaphp_PHP チュートリアルのバイナリ セキュリティ0b”)的值为2

那问题又来了,php都是C来开发的,为什么php做到了二进制安全呢?

先来看看php的变量存储zval结构

php_PHP チュートリアルのバイナリ セキュリティ

php会根据type的值来决定访问value的哪个成员,为字符串时,我们会访问红框标识的str结构,这便是底层字符串的存储结构,它有两个值,一个是指向字符串的指针val,另一个是记录字符串长度的len值,就是因为有len这个值,导致了php是二进制安全的:因为它不需要像C一样通过是否遇到'php_PHP チュートリアルのバイナリ セキュリティ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 不是用这个数组来保存字符,而是用它来保存一系列二进制数据。

たとえば、図 2-18 に示すように、SDS はヌル文字の代わりに len 属性の値を使用して文字列が終了するかどうかを判断するため、前述の特殊なデータ形式を保存するために SDS を使用することに問題はありません。

digraph {    label = ]; buf [{ 'R' | 'd' | 'C' | ' s' | 't' | 'r' | 'php_PHP チュートリアルのバイナリ セキュリティ0' } "]; // sdshdr:buf;}">

C 文字列の代わりにバイナリセーフ SDS を使用することにより、Redis はテキスト データだけでなくバイナリ データも任意の形式で保存できます。



http://www.bkjia.com/PHPjc/925226.htmlwww.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/925226.html技術記事 php のバイナリ セキュリティ この記事では、主に 1. php のバイナリ セキュリティとは何か、2. php のバイナリ セキュリティはどのような構造で確保されているのか、3. この構造も...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート