1. php的二进制安全 binary-safe
php的内部函数在操作二进制数据时能保证达到预期的结果,例如 str_replace
、stristr
、strcmp
等函数,我们就说这些函数是二进制安全的。
下面通过 c 语言 和 php 的对比 来看 他们对二进制数据的处理
#include "stdio.h"
#include "string.h"
int main(){
char a[] = "aa\0b";
char b[] = "aa\0c";
printf("%d\n", strcmp(a, b));
printf("%ld\n", strlen(a));
}
/* 0 2 */
可以看出来 c语言 "\0"
是字符串结束,所以认为 "aa\0b'
和 "aa\0c"
是一样的,长度为2 抛弃了 "\0b"
和 "\0c"
.
<?php
/**
* Created by PhpStorm.
* User: leon
* Date: 17/11/6
* Time: 上午10:24
*/
$a = "aa\0b";
$b = "aa\0c";
$c = "\0\0";
$d = 'a';
$e = 'a';
var_dump(strcmp($a, $b));
var_dump(strcmp($c, $d));
var_dump(strlen($a));
var_dump(strlen($c));
# res : int(-1) int(0) int(4) int(2)
php "aa\0b"
和 "aa\0c"
是不同的 ,并且长度为4
2. php实现二进制安全的原理
PHP中字符串通过 zend_string
表示:
PHP中 变量 zend_value
表示:
- gc: 变量引用信息,比如当前value的引用数,所有用到引用计数的变量类型都会有这个结构,3.1节会详细分析
- h: 哈希值,数组中计算索引时会用到
- len: 字符串长度,通过这个值保证二进制安全
- val: 字符串内容,变长struct,分配时按len长度申请内存
len: 字符串长度,通过这个值保证二进制安全 ,它不需要像C 一样用哟 ‘\0’ 结尾符来判断字符串的结束,而是通过len
3.SDS
C : 以 ’\0’
为结束符,所以c的字符串不能包含文本,图片、音频、视频、压缩文件这样的二进制数据。
Php : 记录 len
SDS : simple dynamic string 简单动态字符串的抽象类型,应用到字符表示:
SDS 数据结构:
struct sdshdr {
# 记录 buf 数组中已使用字节的数量
# 等于 SDS 所保存字符串的长度
int len;
# 记录 buf 数组中未使用字节的数量
int free;
# 字节数组,用于保存字符串
char buf[];
};
redis 的结构定义中也记录了SDS所保存字符串的长度,通过这个值保证二进制安全,SDS 的 API 都会用 字符串的len 属性来判断字符串是否结束