Bitten by $_REQUEST
Totally unrelated to The Vampire Rule,1 today I got a practical lesson in PHP request precedence.
I’ve seen for years recommendations not to use the superglobal $_REQUEST
along with a variety of explanations why to avoid it. These explanations stem from the possibility that one could be confused about the source of the information from $_REQUEST
and end up getting some data other than the data one expects to see. It was exactly this reason that I have been using $_REQUEST
: I have been retrieving information from a mixture of GET
and POST
sources in form submissions. Depending on context, I might switch the data from GET
to POST
or theoretically vice-versa.
In this project I’m trying to fix, there is a piece of data that in some circumstances just wasn’t getting saved out correct. Instead another piece of data was saved in its place. I did all sorts of logical juggling to enforce precedence, because this piece of information could come from multiple places and might have some conflicts. I know what order of precedence I want: get the data out of the cookie for convenience, but if a form sets that value, take the value set explicitly by the form. And if there is a URL-encoded form, use that over all other options.
Why would I want this? Well, I’d like to have the value set and then if the user does something crazy like go to another page and then type the URL for the site back in, I want the data to still be set for that user. Also, when testing (or for the convenience of being able to send someone a URL with the specific value set) I’d like to manually just type the value to the end of the URL. Easy peasy. Convenient.
Which means the order of precedence I want is: GPC
or «GET
, POST
, COOKIE
» In all the places where I set this particular value, I was very clear about where I was getting each and which to choose in the case of conflict.
Except one place where I set the value with, you guessed it, $_REQUEST
.
This possibly should have been an easy problem to diagnose. I knew about this, but from documentation and online discussions I knew that in PHP 5.3 and newer that the default setting for request_order
is GP
. Which means the cookie is never looked at. That’s not GPC
but that’s perfectly OK. I’m more than happy to explicitly get the cookie data only when I explicitly ask for it. The website with this thorny issue is running PHP 5.3, so this kind of precedence couldn’t possibly be the problem. Right?
Of course not.
See, PHP 5.3 has a default configuration that it’s shipped with that includes the line:
request_order = GP
However, I’m not running a default configuration. The PHP was upgraded some time ago. And request_order = GP
is not a global default in PHP 5.3, it’s a line included in the default configuration file. Not the same thing. I had no request_order
directive at all. As it says clearly in the documentation if request_order
is not set, the value defaults to whatever is set for variables_order
. variables_order
is EGPCS
which means… well, it’s not GP
, let’s leave it at that.
Am I going to stop using $_REQUEST
? No, I’m not. It’s still a handy way for me to get at the data I want. In fact, now that I know I can explicitly set the value it might even be more handy. But I now have a finer appreciation for the reason so many people suggest not to use it.
- The Vampire Rule states that one must be invited in by one’s victim before commencing any unpleasantness. ↩