A slip betwixt $HTTP_RAW_POST_DATA and $_POST

The curious case of the missing post: An interesting bug came across my desk today. We have some hacky PHP code that receives data from cpanel, which is written in Perl. The bug came out after an update to cpanel. Suddenly we started getting blank requests: PHP’s $_REQUEST variable was blank. A good deal of (unnecessary?) debugging showed that the $_POST variable was just as blank. Eventually, when printing out the entire $GLOBALS array, I found the data hiding away in $HTTP_RAW_POST_DATA. Yay! Now, why was it there?

Time to check stuff: did something update PHP on this box to some other version?

$ php -r 'phpinfo();' | grep -i version | head
PHP Version => 5.1.8

Well, not, but wow! That’s rather old. Is there a bug in this version that will cause it not to populate $_POST from the posted data? Googled it. Nope. Oh wait. Maybe I should yahoo it! Still nope. There was a bug in php 4.2, but it was fixed. So what’s up?

I never looked at the actual request, since this thing is over SSL and I didn’t feel like setting up a man in the middle, but here’s what it seems to be going on: the cpanel perl client side is not sending a valid Content-Type header. Something like this:

POST /scripts2/synczones_local HTTP/1.0
User-Agent: Cpanel::PublicAPI (perl) 1.1\
Content-Type: application/x-www-form-urlencoded

zone=mcgill.org.za&zonedata=...

By parsing $HTTP_RAW_POST_DATA, we get the bits we were missing, and voila it works:

if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
    parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $postdatawithbadheaders);
    foreach($postdatawithbadheaders as $k=>$v) {
        if (!isset($_REQUEST[$k])) { 
            $_POST[$k]=$v;
            $_REQUEST[$k]=$v;
        }
    }
}

This entry was posted in Stuff and tagged , , . Bookmark the permalink.