作者:书友37715123 | 来源:互联网 | 2023-10-16 20:16
PHP函数二进制安全有关问题:PHP函数二进制安全问题本文主要从三个角度来阐述php的二进制安全:1.什么叫php的二进制安全;2.什么结构确保了php的二进制安全;3.这种结构还
PHP函数二进制安全问题
本文主要从三个角度来阐述php的二进制安全:1. 什么叫php的二进制安全;2. 什么结构确保了php的二进制安全;3. 这种结构还有哪些其它方面的应用?
做到知其然,也知其所以然。
一句话解释:
php的内部函数在操作二进制数据时能保证达到预期的结果,例如str_replace、stristr、strcmp等函数,我们就说这些函数是二进制安全的。
举个列子:
我们来对比一下C和php下的strcmp函数。
C代码如下
[objc] view plaincopy
- 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代码如下
[php] view plaincopy
php会根据type的值来决定访问value的哪个成员,为字符串时,我们会访问红框标识的str结构,这便是底层字符串的存储结构,它有两个值,一个是指向字符串的指针val,另一个是记录字符串长度的len值,就是因为有len这个值,导致了php是二进制安全的:因为它不需要像C一样通过是否遇到'\0'结尾符来判断整个字符串是否读取完毕,而是通过len这个值指定的长度进行读取。
可见一个小小的数据结构改进,为我们带来了更多想象的空间,可谓是结构的一小步,功能的一大步。
拓展:
这么好用的结构,显然会被到处使用,我们常用的redis,在底层存储数据时就用到了这种结构,Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将 SDS 用作 Redis 的默认字符串表示
看下SDS的结构定义
[plain] view plaincopy
虽然数据库一般用于保存文本数据,但使用数据库来保存二进制数据的场景也不少见,因此,为了确保 Redis 可以适用于各种不同的使用场景,SDS 的 API 都是二进制安全的(binary-safe):所有 SDS API 都会以处理二进制的方式来处理 SDS 存放在 buf
数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设 ——数据在写入时是什么样的,它被读取时就是什么样。
这也是我们将 SDS 的 buf
属性称为字节数组的原因 ——Redis 不是用这个数组来保存字符,而是用它来保存一系列二进制数据。
比如说,使用 SDS 来保存之前提到的特殊数据格式就没有任何问题,因为 SDS 使用 len
属性的值而不是空字符来判断字符串是否结束,如图 2-18 所示。
buf"]; buf [label = " { 'R' | 'e' | 'd' | 'i' | 's' | '\\0' | 'C' | 'l' | 'u' | 's' | 't' | 'e' | 'r' | '\\0' | '\\0' } "]; // sdshdr:buf -> buf;}" />
通过使用二进制安全的 SDS ,而不是 C 字符串,使得 Redis 不仅可以保存文本数据,还可以保存任意格式的二进制数据。