小评论
阅读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内部的知识,并且我学到了关于安全性的新知识。
答案 0 :(得分:3)
问题不在循环中,问题在于PHP和许多其他语言(Java,Python,ASP.Net)如何在散列数据结构中存储键/值对。 PHP使用哈希表来存储数组(这使得它们在理论上非常快速地存储和检索来自该数组O(1)
的数据)。当多个值被映射到相同的密钥从而产生哈希冲突时,会出现问题。将元素插入到这样的密钥中变得更加昂贵O(n)
因此插入n个密钥从O(n)跳转到O(n ^ 2)。
这正是这里发生的事情。当数字从32767
更改为32768
时,它会更改密钥,从无冲突到所有内容冲突到同一个密钥。
就是这种情况,因为php数组在C语言中实现的方式。数组的大小为2的幂。(9
和15
元素的数组将被分配大小为16
)的数组。此外,如果数组键是整数,则散列将是一个整数,其顶部有一个掩码。掩码为二进制size of the array - 1
。这意味着如果有人试图在关联数组0, 32, 64, 128, 256, ...
中插入以下键,依此类推,它们将被映射到相同的键,因此哈希将具有链表。上面的例子恰好创建了这个。
这需要大量的CPU来处理,因此您会看到大量的时间增加。这意味着开发人员在接受来自外部的一些数据时应该非常小心,他们将被解析为数组(人们可以轻松地创建数据并将DOS作为服务器)。这些数据可以是$_GET
,$_POST
个请求(这就是您可以使用max_input_vars
限制数量的原因),XML
,JSON
。
以下是我用来了解这些事情的资源:
答案 1 :(得分:1)
我对PHP没有特别的了解,但32767将是2字节数字的最大值。将它增加到32768将使得使用3字节数字(从未使用它因此它将是4字节),这反过来会使一切变慢。