0

I am trying to override some variables in my PHP file using variable variables, but I am getting unexpected results, where the original value is never overwritten, but where the new variable-variable value has a unique value from that of its original variable counterpart.

$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; }

If someone someone visits the page path /?schedule_test=case4, the above line should overwrite the variable $case4, because $_GET['schedule_test'] would equal case4 making the statement $$_GET['schedule_test'] = true the equivalent of $case4 = true.

However, even when visiting the URL path /?schedule_test=case4 I still get the value false for $case4. I var_dumped the values for both $case4 and $$_GET['schedule_test'], and their values are different:

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

The desired goal is to be able to test any of these four cases for any set times with the URL parameter schedule_test being set to any of the variable names (e.g. case1, case2, case3, case4).

Brandon McConnell
  • 5,776
  • 1
  • 20
  • 36
  • 1
    Whenever you start “numbering” in variable names, that is a pretty good indicator, that you should actually be using an array. And doing that, would at least take the potential **danger** out of what you are doing. (Imagine you had a variable like `$userIsAdmin` set in your code somewhere before that point, to `false`, because I am not an admin on your site, and now I call your script with `/?schedule_test=userIsAdmin` … see the problem?) – CBroe Apr 08 '21 at 07:46
  • @CBroe My actual variables do have more meaningful names; I just used numbered variables to further generalize my question, but that is something good to keep in mind for future reference — thanks! – Brandon McConnell Apr 08 '21 at 12:49
  • @CBroe that is also a very valid point about the risk of someone using a variable name like `$is_admin`. I think I'll adjust my code to use an array after all, so as to prevent overwriting any unrelated variables. Thanks again! – Brandon McConnell Apr 08 '21 at 12:54

2 Answers2

3

PHP documentation says

In order to use variable variables with arrays, you have to resolve an ambiguity problem. That is, if you write $$a[1] then the parser needs to know if you meant to use $a[1] as a variable, or if you wanted $$a as the variable and then the [1] index from that variable. The syntax for resolving this ambiguity is: ${$a[1]} for the first case and ${$a}[1] for the second.

So, you should use

${$_GET['schedule_test']}

However, I would strongly advise against using user input directly to decide which variable to write like this. There is a very high risk of allowing attackers to change the internal behaviour of your code.

NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • This worked perfectly for me! Thanks for that additional context. I really appreciate the time you took to answer this thoughtfully and provide the additional warning. I'll adjust my code to, instead of using the user-input to write/overwrite a variable, use the user-input to set an array variable value and check for that to prevent any overwriting of any other variables that control the behavior of my code, as you mentioned. Thanks! – Brandon McConnell Apr 08 '21 at 12:57
2

Since $_GET is an array, you cannot use $$ to access the value of $_GET and get the variable, this has to do with PHPs internal parser not knowing if you want to access $$_GET and then the key or $_GET the key and then the variable, this is talked about in the documentation for variable variables three paragraphs above example #1. To fix this you have to surround your $_GET with curly brackets.

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

echo $case4;
echo ${$_GET['schedule_test']};
Kim Hallberg
  • 1,165
  • 1
  • 9
  • 18
  • Thanks @Kim Hallberg! This is a great solution. I really appreciate your approach and the example you provided. Only because the answer was a bit quicker and provided an additional context of the warning, I selected the first answer by NineBerry, but your solution is great as well, and I really wish I could choose both as accepted answers. Thanks again! – Brandon McConnell Apr 08 '21 at 13:02