问题 $ _SERVER ['REQUEST_METHOD']是否保证是大写的?


我现在有 strtoupper($_SERVER['REQUEST_METHOD']) 在我的代码中。

但是是 strtoupper 必要的电话?是 $_SERVER['REQUEST_METHOD'] 保证已经大写?


12513
2018-05-26 12:30


起源

接受的答案是错误的。我建议你接受我的吗? - Mark Amery


答案:


RFC 3875 定义了 REQUEST_METHOD 变量为大写,因此可以依赖它。

REQUEST_METHOD元变量必须设置为方法      应该由脚本用来处理请求...

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

该方法区分大小写。


4
2018-05-26 12:39



我已经编辑了你的答案来修复损坏的链接,并包含RFC 3875的引用,我认为你认为这支持了你的声明,但事实上,他们没有。而标准的方法就像 GET 和 POST 被定义为大写,自定义方法不需要,并且大多数可能的客户端语言(包括,在PATCH方法的情况下,来自现代Web浏览器的AJAX请求)能够发送AJAX请求,甚至标准方法错误地大写。那时候 是 违反规范,您可能仍希望在PHP代码中以某种方式处理它。 - Mark Amery
RFC中的某些东西是 不 足以依赖它,特别是在HTTP世界中。 -1 - Lightness Races in Orbit


简短的回答:不,它不能保证,但通常接收非大写的HTTP方法意味着客户端违反了规范。

答案很长:

如果你正在处理W3规范定义的方法,比如GET和POST,那么你可以保证a 规格兼容 客户端将以大写形式发送给您。这是因为HTTP方法 定义为区分大小写...

Method标记指示要对Request-URI标识的资源执行的方法。该方法区分大小写。

和W3定义的方法一样 OPTIONS,GET,POST等 以大写形式定义。

但是,如果您正在处理不符合规范的客户端,那么您的网络服务器和PHP都不会神奇地强迫 $_SERVER['REQUEST_METHOD'] 为你大写。这可以通过像这样的简单脚本轻松演示......

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

如果我们使用方法不是大写的HTTP请求命中该脚本,它将以非大写形式回显该方法。许多常用工具将让我们这样做。例如,让我们从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

...或使用Python:

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

“好的”你可能会说, “如果我的API被糟糕编写的脚本或本机应用程序使用,那么就存在潜在的问题。但我的API仅用于在Web浏览器中运行的JavaScript触发的AJAX调用。这个问题会影响我吗?”

不幸的是,是的。似乎现代浏览器强迫  发送AJAX时标准HTTP方法大写,但目前对于自定义HTTP方法,或者特别是 PATCH方法

从以前点击相同的PHP脚本,这次是在Chrome JavaScript控制台...

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);
    }
}

产生结果

The method used by your request was GET 

但是将HTTP方法更改为 pATcH 给我们

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);
    }
}

给我们

The method used by your request was pATcH

更糟糕的是,Web浏览器并不是唯一的客户端 将强制除PATCH方法之外的所有方法 大写。

总结:虽然HTTP规范要求请求包含大写的HTTP方法(除非它是在不同情况下专门定义的自定义方法),但常见的Web工具使前端开发人员很容易弄错,而且PHP的 $_SERVER['REQUEST_METHOD'] 变量会  如果他们这样做的话,会神奇地将方法强制为大写。

当然,这取决于您是否要依赖客户遵守规范,验证方法是否为大写并使用适当的状态代码(可能是400或405)进行响应,如果不是,则回复错误消息,或者接受错误基于HTTP的方法,通过强制方法将自己变为大写 strtoupper($_SERVER['REQUEST_METHOD'])就像这里的提问者一样。


13
2018-02-02 14:44





它完全是SAPI特有的,据我所知,PHP“规范”中没有任何内容可以强制使用大写方法名称。以下是AOL Server SAPI的代码片段:

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

如果有人改变了 POST 成 post 它会是小写的。

一次打电话给 strtoupper() 你绝对没有任何成本,所以不要冒险而且只是使用它。


0
2018-05-26 12:39



对strtoupper调用的调用不会花费任何费用,特别是因为不返回原始字符串。至少,php代码必须遍历原始字符串的所有字符并为新字符分配内存。 (虽然很小,特别是在这种情况下,它不是 绝对 没有) - netfire
@netfire很明显,它需要一些时间和资源来调用 strtoupper(),但如果你看一下整个剧本 - 它绝对不会改变。 - Crozin
Crozin - “绝对没有”和“微小”之间的区别有时很重要。如果它处于一个运行1000万次的循环中,那么“微小”就成了问题,但“绝对没有”仍然绝对没有。 - callum


是的,这就是PHP内部在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")) {

它从服务器提供这些值,但如果它不符合 规范 为了传递数据,它是一个性能很差的服务器......但是HTTP RFC仅表示大写。所以,它永远不会成为一个问题。

由于这些原因,保证大写。


0
2018-05-26 13:07



HTTP规范 不 假设HTTP方法必须只是大写。它 不 说它们区分大小写,并以大写形式定义所有标准的(如GET,POST等),但这并不完全等效。如果有人发送gET或pOsT请求(打算将其作为标准的GET或POST请求),那就是发件人的错误 - 据我所知,服务器根据规范没有任何责任将该方法强制为大写并将其视为GET或POST请求。 - Mark Amery
“HTTP RFC仅表示大写。因此,它永远不会成为一个问题。” ROFL - Lightness Races in Orbit
为了充实@ LightnessRacesinOrbit的评论,上面说:认为因为规范规定客户必须以大写形式发送标准方法,没有客户端会犯这个错误,这是天真的。也许这是一个很好的理由来争论套管错误 不是你的问题 作为服务器端程序员,但绝对不意味着HTTP方法案例永远不会导致问题;这取决于客户端程序员是否正确的套管。没有规范可以保证你在实践中没有客户端程序员错误的世界,你可能想要原谅它。 - Mark Amery


它通常是,但我不会指望它100%。这样的事情可能会在新的软件版本或不同的配置中发生变化。您不需要像服务器升级那样破坏代码的小东西。如果要比较它,请始终确保两个字符串都是小写或大写。


-1
2018-05-26 12:35





php文档 似乎表明这个变量有四个可能的值:GET,HEAD,POST或PUT,所有这些都是大写的。你可以随时做一个strcasecmp而不是==比较。


-2
2018-05-26 12:39



文档确实说出你声称的内容(变量将始终具有这四个值中的一个),但文档是错误的,这可以很容易地证明。这只是一个错字或是由一个不知道'eg'之间的区别的人写的和'即'。它的 很标准 在PHP中使用此变量来检测例如DELETE或OPTIONS请求,这样做很好。 - Mark Amery
@MarkAmery 3年后,给我一个+1谷歌“ie和eg之间的区别” - Ken Sherman