php中的数组冲突

时间:2014-04-02 23:47:03

标签: php arrays performance security

小评论

阅读max_input_vars变量让我读了很多关于PHP处理数组的内部信息。这不是一个真正的问题,而是answering my own question"为什么我们真的需要这个max_input_var"。它没有本地化,实际上与许多其他编程语言有关,而不仅仅是php。

问题:

比较这两个小的PHP脚本:

$data = array();
for ($key = 0; $key <= 1073709056; $key += 32767){
    $data[$key] = 0;
}

可以查看it here。一切正常,没什么意外。执行时间接近于0.

这大致相同(差异在1)

$data = array();
for ($key = 0; $key <= 1073709056; $key += 32768){
    $data[$key] = 0;
}

检查it here。没有什么是正常的,一切都是意外的。你超过了执行时间。所以它至少慢3000倍

问题是它为什么会发生?

我在这里一起发布了答案,因为这极大地提高了我对php内部的知识,并且我学到了关于安全性的新知识。

2 个答案:

答案 0 :(得分:3)

问题不在循环中,问题在于PHP和许多其他语言(Java,Python,ASP.Net)如何在散列数据结构中存储键/值对。 PHP使用哈希表来存储数组(这使得它们在理论上非常快速地存储和检索来自该数组O(1)的数据)。当多个值被映射到相同的密钥从而产生哈希冲突时,会出现问题。将元素插入到这样的密钥中变得更加昂贵O(n)因此插入n个密钥从O(n)跳转到O(n ^ 2)。

这正是这里发生的事情。当数字从32767更改为32768时,它会更改密钥,从无冲突到所有内容冲突到同一个密钥。

就是这种情况,因为php数组在C语言中实现的方式。数组的大小为2的幂。(915元素的数组将被分配大小为16)的数组。此外,如果数组键是整数,则散列将是一个整数,其顶部有一个掩码。掩码为二进制size of the array - 1。这意味着如果有人试图在关联数组0, 32, 64, 128, 256, ...中插入以下键,依此类推,它们将被映射到相同的键,因此哈希将具有链表。上面的例子恰好创建了这个。

这需要大量的CPU来处理,因此您会看到大量的时间增加。这意味着开发人员在接受来自外部的一些数据时应该非常小心,他们将被解析为数组(人们可以轻松地创建数据并将DOS作为服务器)。这些数据可以是$_GET$_POST个请求(这就是您可以使用max_input_vars限制数量的原因),XMLJSON

以下是我用来了解这些事情的资源:

答案 1 :(得分:1)

我对PHP没有特别的了解,但32767将是2字节数字的最大值。将它增加到32768将使得使用3字节数字(从未使用它因此它将是4字节),这反过来会使一切变慢。