【问题标题】:Is $_SERVER['REQUEST_METHOD'] guaranteed to be uppercase?$_SERVER['REQUEST_METHOD'] 是否保证为大写?
【发布时间】:2012-05-26 12:30:55
【问题描述】:

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

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

【问题讨论】:

  • 接受的答案是错误的。我可以建议你接受我的吗?

标签: php


【解决方案1】:

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

长答案:

如果您正在处理 W3 规范定义的方法,例如 GET 和 POST,那么您可以保证符合 规范 的客户端会以大写形式向您发送它们。这是因为 HTTP 方法是 defined as case-sensitive...

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

W3 定义的方法如OPTIONS, GET, POST etc. 以大写形式定义。

但是,如果您处理的是不符合规范的客户端,您的网络服务器和 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 method 都没有这样做。

与之前相同的 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

更糟糕的是,网络浏览器并不是唯一将will coerce all methods except the PATCH method 转换为大写的客户端。

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

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

【讨论】:

    【解决方案2】:

    RFC 3875 将REQUEST_METHOD 变量定义为大写,所以可以依赖它。

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

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

    该方法区分大小写。

    【讨论】:

    • 我已经编辑了您的答案以修复损坏的链接,并包含了 RFC 3875 中的引用,我认为您认为这些引用支持您的声明,但事实上,它们并不支持。虽然GET 和POST 等标准方法被定义为大写,但自定义方法不必如此,并且大多数可能的客户端语言(包括,在 PATCH 方法的情况下,来自现代 Web 浏览器的 AJAX 请求)都能够发送即使是标准方法的 AJAX 请求也被错误地大写。虽然这是违反规范的,但您可能仍希望在 PHP 代码中以某种方式处理它。
    • RFC 中的某些内容不够足以依赖它,尤其是在 HTTP 的世界中。 -1
    【解决方案3】:

    它完全是特定于 SAPI 的,据我所知,PHP“规范”中没有任何内容会强制使用大写的方法名称。这是来自 AOL Server SAPI 的代码 sn-p:

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

    如果有人将 POST 更改为 post,它将是小写。

    一次调用strtoupper() 绝对不会花费您任何费用,所以不要冒险,直接使用它。

    【讨论】:

    • 对 strtoupper 的调用绝对不会花费任何成本,尤其是因为未返回原始字符串。至少,php 代码必须遍历原始字符串的所有字符并为新字符串分配内存。 (虽然极少,尤其是在这种情况下,但并不是绝对什么都没有)
    • @netfire 很明显,调用strtoupper() 需要一些时间和资源,但是如果你看一下整个脚本 - 它绝对不会改变任何东西。
    • Crozin – “绝对没有”和“微小”之间的区别有时很重要。如果它在一个运行 1000 万次的循环中,那么“tiny”就会成为问题,但“absolutely nothing”仍然是绝对没有。
    【解决方案4】:

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

    它是从服务器提供这些值的,但如果它不符合 the spec 传递数据的要求,那么它就是一个行为不良的服务器......但 HTTP RFC 只说大写。所以,这永远不会成为一个问题。

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

    【讨论】:

    • HTTP 规范没有说 HTTP 方法只能是大写的。它确实说它们区分大小写,并以大写定义所有标准的(如 GET、POST 等),但这并不完全等同。如果有人发送一个 gET 或 pOsT 请求(打算它是一个标准的 GET 或 POST 请求),那是发件人的错误——据我所知,根据规范,服务器没有任何责任将方法强制为大写并将其视为 GET 或 POST 请求。
    • “HTTP RFC 只表示大写。所以,这永远不会成为问题。” rofl
    • 充实上面@LightnessRacesinOrbit 的评论:认为由于规范规定客户端必须以大写形式发送标准方法,因此没有客户端会出错,这是天真的想法。作为服务器端程序员,争论大小写错误不是你的问题也许是一个很好的理由,但这绝对不意味着 HTTP 方法案例永远不会导致问题;这取决于客户程序员是否正确地使用了他们的外壳。没有规范可以保证您在实践中没有客户端程序员错误,您可能希望原谅它。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      php documentation 似乎表明该变量有四个可能的值:GET、HEAD、POST 或 PUT,它们都是大写的。可以肯定的是,您总是可以进行 strcasecmp 而不是 == 比较。

      【讨论】:

      • 文档确实说出了您声称的内容(变量将始终具有这四个值之一),但是文档是错误的,这可以很容易地证明。这只是一个错字,或者是由不知道“例如”之间区别的人写的和“即”。在 PHP 中是 pretty standard 使用这个变量来检测例如DELETE 或 OPTIONS 请求,这样做效果很好。
      • @MarkAmery 3 年后,一个 +1 让我在谷歌上搜索“i.e. 和 e.g. 之间的差异”
      • 我已经向一位文档维护者提交了一张票来解决这个问题:bugs.php.net/bug.php?id=77807
      猜你喜欢
      • 2014-12-17
      • 1970-01-01
      • 2022-06-21
      • 2010-09-29
      • 2012-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多