POST Data going missing in PHP

I came across an incredibly frustrating issue earlier today, whilst building a class to parse data and insert it into a database I discovered some serious data loss. Sniffing the traffic showed the data was being submitted, but when I tried to access it in PHP bits were missing!

Consider the following

Raw Post data: foo=blah+blah+blah&bar=This+is+a+block+of+text%0D%3Cbr%3EThis+is+line+2&zulu=bah

So in PHP, you'd expect that;

  1. echo $_POST['foo'] would give "blah blah blah"
  2. echo $_POST['bar'] would give "This is a block of text<br>This is line 2"
  3. echo $_POST['zulu'] would give "bah"

Unfortunately, this isn't the case! Instead number 2 returns "<br>This is line 2". How very frustrating, but thankfully I eventually found the solution

 

So we'll assume our code was



echo $_POST['foo']; //Gives 'blah blah blah'
echo $POST['bar']; //Gives '<br>This is line 2'
echo $_POST['zulu']; // Gives 'bah'

It turns out there's a minor issue with urldecode (which appears to be used to decode the values in $_POST ). The important part of the raw POST data is %0D which signifies a carriage return, for some reason urldecode will ignore any part of the data before that character sequence (so if we added a third line, only that would be displayed).

There is a way around it, but unfortunately it does mean we can't rely on the superglobal $_POST



function getFullPOST() {
    $pairs = explode("&", file_get_contents("php://input"));
    $vars = array();
    foreach ($pairs as $pair) {
        $nv = explode("=", $pair);
        $name = urldecode($nv[0]);
        $value = urldecode(str_replace("%0D","",$nv[1]));
 
$vars[$name] = "$value";
    }
    return $vars;
}

And then in our function rather than simply using $_POST we need to do



$post_data = getFullPOST;
echo $post_data['foo']; //Gives 'blah blah blah'
echo $post_data['bar']; //Gives 'This is a block of text<br>This is line 2'
echo $post_data['zulu']; // Gives 'bah'

It's incredible irritating but that's the way around it if you've little to no control over the input data itself. So if you find that urldecode is losing data, or $_POST is incomplete it might just be worth checking the raw input data for %0D. You may also find that the other ASCII device control characters (%00-%1f) cause issues as well, but I've not had cause to check just yet. I'd assume the same goes for $_GET as well!