PHP被称为"二进制安全"的功能是什么?这些"非二进制安全"函数向哪些库移除字符串?为什么?

PHP*_*Fan 10 php string php-internals

我正在使用Windows 10 Home Single Language Edition,它是我机器上的64位操作系统.

我安装了最新版本的XAMPP,它在我的机器上安装了PHP 7.2.7.

我根据PHP手册中的摘录问这个问题:

PHP中的字符串实现为字节数组和表示缓冲区长度的整数.它没有关于这些字节如何转换为字符的信息,将该任务留给程序员.字符串可以组成的值没有限制; 特别是,字符串中的任何地方都允许使用值为0的字节("NUL字节")(但是,本手册中称为"二进制安全"的一些函数)可能会将字符串移交给忽略数据后的数据库. NUL字节.)

我非常理解PHP中二进制安全函数和非二进制安全函数之间的区别.我心中怀疑.请以一对一的方式回答它们,并附上适当的解释和适当的例子.

  • PHP中是否存在"非二进制安全"和"二进制安全"函数的现象,因为整个PHP解析器都是用C语言编写的?
  • 在处理包含任何值的字符串(包括NUL字节)时,C和PHP之间有什么区别?
  • 我想要PHP中的完整功能列表,这些功能是"非二进制安全的"并且是"二进制安全的".
  • 是"非二进制安全"和"二进制安全"只适用于操纵在串并不能适用于其他类型的PHP处理PHP函数功能的特点呢?
  • 为什么非二进制安全函数将字符串移交给库?
  • 只有当它们处理的字符串包含NUL字节时,非二进制安全函数才会将字符串移交给库吗?
  • 那些"非二进制安全"函数将这些字符串移交给哪些库?
  • 这些库如何处理从"非二进制安全"函数接收的字符串?
  • 在将包含NUL字节的字符串移交给某个库之后,"非二进制安全"函数是否像"二进制安全"函数一样工作?

LBe*_*ear 9

像arkascha解释的那样,"二元安全"和"非二元安全"问题与语言无关.

使用空字节(0x00)来表示字符串的结尾更简单(这可能就是C随之而来的原因),但缺点是你不能在字符串中的任何地方都有一个空字节,这是一个很大的限制,如果你必须能够处理各种数据.将长度存储为字符串的元数据部分更复杂,如Pete所示,但它允许您处理任何类型的数据.

关于哪些函数是"二进制安全"或"非二进制安全",请使用函数之前阅读PHP手册.我就是做这个的.不需要构建列表,因为PHP手册已经解释了您需要了解的有关函数的内容,包括它们是否是二进制安全的.

我相信,你的大多数帖子都是由于误解了你引用的PHP手册的解释,特别是这一部分:

但是,在本手册中称为"二进制安全"的一些函数可能会将字符串移交给在NUL字节后忽略数据的库.

让我尝试通过添加一些我自己的话来更清楚:

但是,在本手册中称为"二进制安全"的一些函数是可以将字符串移交给在NUL字节之后忽略数据的库的函数.

所以它真的没有说"非二进制安全函数将字符串移交给库",这是一种误解.这意味着"可以将字符串移交给在NUL字节后忽略数据的库的函数,在本手册中称为非二进制安全".

"移交给图书馆"只是说"从其他图书馆调用功能"的另一种方式."忽略NUL字节后的数据"是一种被称为非二进制安全的行为.

另一种方式是:

本手册中的一些函数被称为"二进制安全",因为它们可能调用其他也不是"二进制安全"的函数(在NUL字节之后忽略数据的函数).

我希望这能为你解决这个问题.


Pet*_*ete 5

传统上有两种表示字符串的方法:通过使用特殊字符发信号通知字符串的结尾,或者将其长度与字符串数据一起存储.C使用前者; 字符串是一个char数组,末尾有一个空字符.但是,这有一个限制,即C中的字符串不能在其他地方使用空字符,而是在最后.

为克服此限制,PHP引擎使用此结构来表示字符串:

struct _zend_string {
    zend_refcounted_h gc; /* refcount struct */
    zend_ulong        h;  /* hash value */
    size_t            len; /* length of string */
    char              val[1]; /* array of chars (using struct "hack") */
};
Run Code Online (Sandbox Code Playgroud)

如您所见,PHP开发人员选择存储字符串的长度及其数据.

现在如果混合"二进制安全"和"非二进制安全"功能会发生什么?

考虑编写PHP扩展时可能使用的以下C代码:

zend_string *a = zend_string_init("a\0b", /* string length */ 3, 0);
zend_string *b = zend_string_init("a\0c", /* string length */ 3, 0);

if (strcmp(a->val, b->val) == 0) {
    php_printf("Strings are equal!");
}
Run Code Online (Sandbox Code Playgroud)

你认为会发生什么?此代码输出"字符串相等!" 虽然他们显然不平等.由于strcmp不考虑字符串的长度,因此它是非二进制安全函数.

C的大多数标准库字符串函数可以归类为"非二进制安全",因为它依赖于空终止字符.

处理zend_string扩展代码时,应该使用Zend字符串函数(zend_string_*)而不是C的字符串库.

要修复以前的代码:

if (zend_string_equals(a, b)) {
    php_printf("Equal!");
} else {
    php_printf("Not equal");
}
Run Code Online (Sandbox Code Playgroud)

这现在正确打印"不相等".