PHP 变量变量不覆盖原始变量

PHP variable variable not overriding original variable

提问人:Brandon McConnell 提问时间:4/8/2021 更新时间:4/8/2021 访问量:230

问:

我试图使用变量变量覆盖我的 PHP 文件中的一些变量,但我得到了意想不到的结果,其中原始值从未被覆盖,但新的变量-变量值与原始变量对应值具有唯一值。

$case1 = (time() > strtotime('11/22/2020 07:00:00:000AM'));
$case2 = (time() > strtotime('11/16/2020 07:00:00:000AM'));
$case3 = (time() > strtotime('12/01/2020 12:00:00:000PM'));
$case4 = (time() > strtotime('04/24/2021 05:00:00:000AM'));
if (!empty($_GET['schedule_test'])) { $$_GET['schedule_test'] = true; }

如果有人访问了页面路径,上面的行应该覆盖变量,因为这等于使语句等价于 。/?schedule_test=case4$case4$_GET['schedule_test']case4$$_GET['schedule_test'] = true$case4 = true

但是,即使在访问 URL 路径时,我仍然会获得 的值。我var_dumped 和 的值,它们的值不同:/?schedule_test=case4false$case4$case4$$_GET['schedule_test']

echo $case4; // false
echo $$_GET['schedule_test']; // true

预期的目标是能够在任何设定的时间内测试这四种情况中的任何一种,并将 URL 参数设置为任何变量名称(例如 、 、 、 )。schedule_testcase1case2case3case4

php 变量 boolean 覆盖 variable-variables

评论

1赞 CBroe 4/8/2021
每当你开始在变量名中“编号”时,这是一个很好的指标,你实际上应该使用一个数组。这样做,至少可以消除你正在做的事情的潜在危险。(想象一下,在那之前,你的代码中的某个地方有一个变量,比如 set,因为我不是你网站的管理员,现在我用 ...看到问题了吗?$userIsAdminfalse/?schedule_test=userIsAdmin
0赞 Brandon McConnell 4/8/2021
@CBroe 我的实际变量确实有更有意义的名称;我只是使用编号变量来进一步概括我的问题,但最好记住这一点以备将来参考——谢谢!
0赞 Brandon McConnell 4/8/2021
@CBroe这也是关于某人使用变量名称(如 )的风险的一个非常有效的观点。我想我会调整我的代码以使用数组,以防止覆盖任何不相关的变量。再次感谢!$is_admin

答:

3赞 NineBerry 4/8/2021 #1

PHP文档

为了将变量变量与数组一起使用,您必须解决歧义问题。也就是说,如果你写了 $$a[1],那么解析器需要知道你是打算使用 $a[1] 作为变量,还是希望 $$a 作为变量,然后是该变量的 [1] 索引。解决这种歧义的语法是:第一种情况为 ${$a[1]},第二种情况为 ${$a}[1]。

所以,你应该使用

${$_GET['schedule_test']}

但是,我强烈建议不要直接使用用户输入来决定像这样编写哪个变量。允许攻击者更改代码的内部行为的风险非常高。

评论

0赞 Brandon McConnell 4/8/2021
这对我来说非常有效!感谢您提供额外的背景信息。我非常感谢您花时间深思熟虑地回答这个问题并提供额外的警告。我将调整我的代码,而不是使用用户输入来写入/覆盖变量,而是使用用户输入来设置数组变量值并检查它以防止覆盖控制代码行为的任何其他变量,正如您提到的。谢谢!
2赞 Kim Hallberg 4/8/2021 #2

由于是一个数组,你不能用来访问和获取变量的值,这与PHP的内部解析器不知道你是否要访问然后键或键,然后是变量,这在变量变量的文档中讨论过,上面的例子#1三段。要解决此问题,您必须用大括号包围您的括号。$_GET$$$_GET$$_GET$_GET$_GET

if (! empty($_GET['schedule_test'])) {
    ${$_GET['schedule_test']} = true;
}

echo $case4;
echo ${$_GET['schedule_test']};

评论

0赞 Brandon McConnell 4/8/2021
谢谢@Kim哈尔伯格!这是一个很好的解决方案。我非常感谢您的方法和您提供的例子。只是因为答案更快一些,并且提供了警告的额外上下文,我选择了 NineBerry 的第一个答案,但您的解决方案也很棒,我真的希望我能同时选择两个作为公认的答案。再次感谢!