12

I've currently got strtoupper($_SERVER['REQUEST_METHOD']) in my code.

But is the strtoupper call necessary? Is $_SERVER['REQUEST_METHOD'] guaranteed to be uppercase already?

callum
  • 34,206
  • 35
  • 106
  • 163

6 Answers6

15

Short answer: no, it's not guaranteed, but normally receiving a non-uppercase HTTP method means that the client was in violation of spec.

Long answer:

If you're dealing with methods defined by W3 specs, like GET and POST, then you're guaranteed that a spec-compliant client will send you them in uppercase. This is because HTTP methods are defined as case-sensitive...

The Method token indicates the method to be performed on the resource identified by the Request-URI. The method is case-sensitive.

and the W3-defined methods like OPTIONS, GET, POST etc. are defined in uppercase.

However, if you're dealing with a non-spec-compliant client, neither your webserver nor PHP will magically coerce the value of $_SERVER['REQUEST_METHOD'] to uppercase for you. This can be demonstrated easily with a simple script like this...

<?php
    echo "The method used by your request was $_SERVER[REQUEST_METHOD]";
?>

If we hit that script with a HTTP request whose method is not uppercase, it will echo back the method in non-uppercase. Plenty of common tools will let us do this. For example, let's hit it from the UNIX shell:

$ curl http://localhost/echo_method.php -X GET -w "\n"
The method used by your request was GET
$ curl http://localhost/echo_method.php -X gEt -w "\n"
The method used by your request was gEt
$ curl http://localhost/echo_method.php -X fWoRbLeWoRbLe -w "\n"
The method used by your request was fWoRbLeWoRbLe

... or using Python:

>>> import httplib
>>> connection = httplib.HTTPConnection('localhost')
>>> connection.request('pOsT', '/echo_method.php')
>>> connection.getresponse().read()
'The method used by your request was pOsT'

"Okay", you might well say, "so there are potential problems if my API is being used by badly-written scripts or native applications. But my API is only used by AJAX calls triggered by JavaScript running in a web browser. Does this issue affect me?"

Unfortunately, yes. It seems that modern browsers coerce most of the standard HTTP methods to uppercase when sending AJAX, but do not currently do so for either custom HTTP methods or, notably, the PATCH method.

Hitting that same PHP script from before, this time at the Chrome JavaScript console...

var request;
request = new XMLHttpRequest();
request.open("GeT", "http://localhost/echo_method.php", true);
request.send();
request.onreadystatechange = function() {
    if (request.readyState == 4) {
        console.log(request.responseText);
    }
}

yields the result

The method used by your request was GET 

but changing the HTTP method to pATcH gives us

var request;
request = new XMLHttpRequest();
request.open("pATcH", "http://localhost/echo_method.php", true);
request.send();
request.onreadystatechange = function() {
    if (request.readyState == 4) {
        console.log(request.responseText);
    }
}

gives us

The method used by your request was pATcH

Worse, web browsers are not the only clients that will coerce all methods except the PATCH method to uppercase.

In conclusion: while the HTTP spec requires that requests include the HTTP method in uppercase (unless it's a custom method specifically defined in a different case), common web tools make it reasonably easy for front-end developers to get this wrong, and PHP's $_SERVER['REQUEST_METHOD'] variable will not magically coerce the method to uppercase for you if they do.

It's up to you, of course, whether you want to rely on your clients complying with spec, validate that the method is uppercase and respond with an appropriate status code (perhaps 400 or 405) and error message if it is not, or accept incorrectly-cased HTTP methods by coercing the method to uppercase yourself via strtoupper($_SERVER['REQUEST_METHOD']) like the question asker here originally was.

Community
  • 1
  • 1
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
5

RFC 3875 defines the REQUEST_METHOD variable as upper case, so it's okay to rely on it.

The REQUEST_METHOD meta-variable MUST be set to the method which should be used by the script to process the request ...

  REQUEST_METHOD   = method
  method           = "GET" | "POST" | "HEAD" | extension-method
  extension-method = "PUT" | "DELETE" | token

The method is case sensitive.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
strkol
  • 1,909
  • 15
  • 11
  • I've edited your answer to fix the broken link and include the quotes from RFC 3875 that I assume you thought supported your claim here, but in fact, they don't. While the standard methods like `GET` and `POST` are defined as uppercase, custom methods need not be, and most possible client languages (including, in the case of the PATCH method, AJAX requests from modern web browsers) are capable of sending AJAX requests with even the standard methods wrongly capitalized. While that *is* a spec violation, you might still wish to deal with it in some way in your PHP code. – Mark Amery Feb 02 '14 at 14:54
  • That something's in an RFC is **not** sufficient for relying on it, particularly in the world of HTTP. -1 – Lightness Races in Orbit Nov 21 '15 at 21:19
0

It's completely SAPI-specific, and as far as I know there is nothing in PHP "specification" that would force uppercase method name. Here's code snippet from AOL Server SAPI:

Ns_RegisterRequest(ctx->ns_server, "POST", value, php_ns_request_handler, NULL, ctx, 0);

If someone would change that POST into post it would be lowercase.

A single call to strtoupper() costs you absolutely nothing, so don't risk and just use it.

Crozin
  • 43,890
  • 13
  • 88
  • 135
  • 2
    a call to strtoupper call doesn't cost absolutely nothing, especially since the original string is not returned. At a minimum, the php code has to iterate over all of the characters of the original string and allocate memory for a new one. (while minimal, especially in this case, it isn't _absolutely_ nothing) – netfire May 26 '12 at 12:43
  • 1
    @netfire It is obvious that it need some time and resources to call `strtoupper()`, but if you take a look at a script as a whole - it won't change absolutely nothing. – Crozin May 26 '12 at 13:34
  • 1
    Crozin – the difference between "absolutely nothing" and "tiny" is sometimes important. If it's in a loop that runs 10 million times, then "tiny" becomes a problem, but "absolutely nothing" is still absolutely nothing. – callum May 28 '12 at 09:58
0

Yes, that's what PHP internally looks for under php 5.4

http://lxr.php.net/opengrok/xref/PHP_5_4/main/SAPI.c#456

454     if (SG(server_context)) {
455         if (PG(enable_post_data_reading) && SG(request_info).request_method) {
456             if (SG(request_info).content_type && !strcmp(SG(request_info).request_method, "POST")) {

http://lxr.php.net/opengrok/xref/PHP_5_4/main/SAPI.c#797

796                     } else if (SG(request_info).proto_num > 1000 &&
797                        SG(request_info).request_method &&
798                        strcmp(SG(request_info).request_method, "HEAD") &&
799                        strcmp(SG(request_info).request_method, "GET")) {

It's fed those values from the server, but if it's not conforming to the spec for passing the data it's a badly behaving server... but the HTTP RFC says upper case only. So, it's not really going to be an issue, ever.

Upper case is guaranteed because of these things.

Incognito
  • 20,537
  • 15
  • 80
  • 120
  • The HTTP spec *doesn't* say that HTTP methods must be uppercase only. It *does* say that they are case sensitive, and define all the standard ones (like GET, POST, etc.) in uppercase, but that isn't quite equivalent. If somebody sends a gET or pOsT request (intending it to be a standard GET or POST request), that's the sender's error - the server doesn't have any responsibility under spec, as far as I can find, to coerce the method to uppercase and treat it as a GET or POST request. – Mark Amery Feb 02 '14 at 15:08
  • _"the HTTP RFC says upper case only. So, it's not really going to be an issue, ever."_ rofl – Lightness Races in Orbit Nov 21 '15 at 21:20
  • To flesh out @LightnessRacesinOrbit's comment, above: it's naive to think that because the spec dictates that clients must send the standard methods in uppercase, that no client will ever get this wrong. Maybe it's good justification for arguing that casing mistakes are *not your problem* as the serverside programmer, but that absolutely doesn't mean that HTTP method case will never cause an issue; that depends upon whether the client programmer gets their casing right. No spec can guarantee you a world free from client programmer error in practice, and you may want to be forgiving of it. – Mark Amery Dec 13 '15 at 00:34
-1

It usually is, but I wouldn't count on it 100%. Something like this can change in a new software version or different configuration. You don't really want something as small as this breaking your code with a server upgrade. If you want to compare it, then always make sure that both strings are either lower or uppercase.

chucktator
  • 1,828
  • 12
  • 16
-2

The php documentation seems to indicate that there are four possible values for this variable: GET, HEAD, POST or PUT, all of which are uppercase. You could always do a strcasecmp instead of a == comparison to be sure.

netfire
  • 158
  • 8
  • 2
    The docs do indeed say what you claim (that the variable will always have one of those four values), but the docs are wrong and this can be demonstrated easily. It's just a typo or was written by somebody who doesn't know the difference between 'e.g.' and 'i.e.'. It's [pretty standard](http://stackoverflow.com/questions/359047/php-detecting-request-type-get-post-put-or-delete) in PHP to use this variable for detecting e.g. DELETE or OPTIONS requests, and doing so works fine. – Mark Amery Feb 02 '14 at 15:01
  • 1
    @MarkAmery 3 years later, a +1 for making me google "difference between i.e. and e.g." – Ken Sherman Apr 06 '17 at 01:46
  • I have gone ahead and submitted a ticket for one of the docs maintainers to fix this: https://bugs.php.net/bug.php?id=77807 – Mark Amery Mar 27 '19 at 13:36