PHP通过GET参数使用可变变量覆盖原有变量未生效
问题根因
你遇到的赋值无效、两个变量值对不上的问题,是两个原因叠加导致的:
- 第一是可变变量的语法解析歧义:你写的
$$_GET['schedule_test']没有用大括号明确界定范围,PHP的词法解析器不会按照你的预期逻辑运行。当可变变量和数组下标混写且没有大括号包裹时,PHP会按照固定优先级解析为
${$_GET}['schedule_test']:也就是先取整个$_GET超全局数组的值(数组类型),将其隐式转成字符串"Array"作为变量名,找到名为$Array的变量后,再给这个变量的['schedule_test']键赋值为true。
这就是为什么你打印$case4还是原来的false,而打印$$_GET['schedule_test']能得到true——你实际读写的根本不是$case4,是$Array['schedule_test'],两者没有任何关联。 - 第二是缺少安全校验:直接把用户可控的URL参数当变量名使用,哪怕语法写对了,也存在任意变量覆盖的风险,容易被恶意传参篡改业务逻辑。
修复方案
按两步调整代码即可:
- 修正可变变量的语法歧义:只要可变变量的变量名来自数组取值、表达式计算,必须用大括号
{}把可变变量的计算范围包裹起来,明确告诉PHP哪部分逻辑是用来生成最终变量名的 - 增加参数白名单校验:只允许传入预先定义好的四个case变量名,其他输入值直接忽略,从根源上杜绝任意变量覆盖的安全问题
参考修正代码
$case1 = (time() > strtotime('11/22/2020 07:00:00')); $case2 = (time() > strtotime('11/16/2020 07:00:00')); $case3 = (time() > strtotime('12/01/2020 12:00:00')); $case4 = (time() > strtotime('04/24/2021 05:00:00')); if (!empty($_GET['schedule_test'])) { // 白名单:仅允许覆盖这四个预设的case变量 $allow_list = ['case1', 'case2', 'case3', 'case4']; $target = $_GET['schedule_test']; if (in_array($target, $allow_list)) { // 大括号明确界定解析范围:取$target的值作为变量名,赋值为true ${$target} = true; } } // 调试输出 var_dump($case1, $case2, $case3, $case4);
注意事项
- 日常开发中,只要可变变量的变量名不是直接的字面量、简单变量,必须加大括号明确解析范围,避免因为优先级问题产生隐蔽bug
- 永远不要把用户可控的输入(URL参数、表单值、Cookie值)直接作为可变变量的变量名,必须加白名单限制,否则攻击者可以通过传参覆盖代码中的任意全局变量,造成安全风险
内容的提问来源于stack exchange,提问作者Brandon McConnell
相关产品推荐
相关产品推荐

