Turns out php will tinker with names of HTTP request parameters in some circumstances. The reason is historical: register globals was a dumb idea that allowed request parameters to be converted into php variables. A request parameters is something like ?id=42 in a GET request, or the name of a form input in a POST request, to use common examples. The problem was, register globals couldn’t convert a variable with a space or dot in the name into a valid php variable because dot and space are not allowed in php variable names. In other words ?object.id=42 would become in $_GET object_id with a value of 42. Eventhough the use of register globals is frowned upon today because its a security vulnerability, the behavior of PHP remains unchanged as far as tinkering with request parameter names.
So how can you get at the raw values? I found these two mechanisms. For HTTP GET requests you can read the raw query string from $_SERVER[‘QUERY_STRING’]. For POST requests you have to call file_get_contents(‘php://input’), which is a trick I learned from this post.