Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Form validation with in_array in PHP

Jerry Stratton, July 17, 2010

I was looking at my web stats the other day, and noticed that my die roller page on the Biblyon Broadsheet had been accessed as “/Game/Dice/?dice=1&die=20+”. That “plus” sign was invalid, so I went to make sure I hadn’t put in a bad link somehow, and in the process noticed that the image of the d20 failed to load.

It was including the “+” in the HTML. That woke me up. I tried a couple of tests, and sure enough, I was able to inject code into the web page by including it after the die number.

Time to panic.

Thing is, I went into the code and it didn’t make sense. I was doing what I always do: validate against an array of valid options.

[toggle code]

  • $allowedDice = array(4, 6, 8, 10, 12, 20, 100, 'ability');
  • $formDie = $_GET['die'];
  • if (!in_array($formDie,$allowedDice)) {
    • $formDie = 20;
  • }

If the form data is in the array of allowed dice, it uses it, otherwise, it sets the die to d20.

What I first noticed is that this is not exactly what I prefer to do when validating against an array: I prefer to use the form data only to pull the real value from the array. Often, I will do this with keys, so that the form data is not the data I use in the code. In this case, it would look something like this:

[toggle code]

  • $allowedDice = array(
    • 'four'=>4,
    • 'six'=>6,
    • 'eight'=>8,
    • 'ten'=>10,
    • 'twelve'=>12,
    • 'twenty'=>20,
    • 'percent'=>100,
    • 'ability=>'ability',
  • );
  • $formDie = $allowedDice[$_GET['die']];
  • if (!$formDie) {
    • $formDie = 20;
  • }

But so what? Why would I want to use that more verbose and complicated form just for a bunch of dice? They’re either valid dice or they’re not!

Well, in this case, it turns out not. The reason is PHP’s type juggling. All form values come in as strings. By setting the dice in the array as integers, I was triggering automatic type conversion. The string “20HELLO”, or worse, “20” followed by HTML code will convert to the integer 20. This meant that it was in the array, because the integer 20 was in the array, even though the string “20HELLO” was not.

There are three solutions; the best is probably to use keys, as in the example above. Also a very good idea, when creating an array to validate form input, make sure every value in the array is a string, because that’s what the form value will be:

  • $allowedDice = array('4', '6', '8', '10', '12', '20', '100', 'ability');

Finally, when you’re expecting integer values, always convert to an integer as soon as you get it, using “intval”, for example, and use the converted variable rather than the value directly from the form.

  1. <- Command-line mail
  2. Non-filesystem URLs ->