【问题标题】:Array collisions in phpphp中的数组冲突
【发布时间】:2014-04-02 23:47:02
【问题描述】:

小备注

阅读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 内部知识的了解,并且我学到了有关安全性的新知识。

【问题讨论】:

  • 我写道,区别在于$key旁边的数字。数字相差 1。

标签: php arrays performance security


【解决方案1】:

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

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

情况就是这样,因为 php 数组是在 C 中实现的。数组的大小是 2 的幂。(915 元素的数组将分配给大小为 @ 的数组987654332@)。此外,如果数组键是整数,则哈希将是一个带有掩码的整数。掩码是二进制的size of the array - 1。这意味着如果有人试图在关联数组0, 32, 64, 128, 256, ... 中插入以下键,以此类推,它们都将映射到同一个键,因此散列将具有链表。上面的示例正是创建了这个。

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

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

【讨论】:

    【解决方案2】:

    我对 php 一无所知,但 32767 将是 2 字节数的最大值。将其增加到 32768 将需要使用 3 字节数(从未使用过,因此它将是 4 字节),这反过来会使一切变慢。

    【讨论】:

    • 不,这不是正确的答案。如果你用 32769 运行它(把你放在同一个 3 byte number 中)也会非常快。因此这个答案是错误的。我正在完成正确的答案,几分钟后它就会出现在这里。
    • 嗯,这让我有点意外,期待你的正确回答。
    猜你喜欢
    • 2014-05-14
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 2019-12-11
    相关资源
    最近更新 更多