【发布时间】:2012-05-26 12:30:55
【问题描述】:
我的代码中目前有strtoupper($_SERVER['REQUEST_METHOD'])。
但是strtoupper 电话有必要吗? $_SERVER['REQUEST_METHOD'] 已经保证是大写了吗?
【问题讨论】:
-
接受的答案是错误的。我可以建议你接受我的吗?
标签: php
我的代码中目前有strtoupper($_SERVER['REQUEST_METHOD'])。
但是strtoupper 电话有必要吗? $_SERVER['REQUEST_METHOD'] 已经保证是大写了吗?
【问题讨论】:
标签: php
简短回答:不,不能保证,但通常接收非大写 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 方法,就像这里最初的提问者一样。
【讨论】:
RFC 3875 将REQUEST_METHOD 变量定义为大写,所以可以依赖它。
REQUEST_METHOD 元变量必须设置为 脚本应该使用它来处理请求...
REQUEST_METHOD = method method = "GET" | "POST" | "HEAD" | extension-method extension-method = "PUT" | "DELETE" | token该方法区分大小写。
【讨论】:
GET 和POST 等标准方法被定义为大写,但自定义方法不必如此,并且大多数可能的客户端语言(包括,在 PATCH 方法的情况下,来自现代 Web 浏览器的 AJAX 请求)都能够发送即使是标准方法的 AJAX 请求也被错误地大写。虽然这是违反规范的,但您可能仍希望在 PHP 代码中以某种方式处理它。
它完全是特定于 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 在 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 只说大写。所以,这永远不会成为一个问题。
由于这些原因,保证大写。
【讨论】:
通常是这样,但我不会 100% 指望它。这样的事情可能会在新的软件版本或不同的配置中发生变化。您真的不希望通过服务器升级破坏您的代码这么小的东西。如果要比较它,请始终确保两个字符串都是小写或大写。
【讨论】:
php documentation 似乎表明该变量有四个可能的值:GET、HEAD、POST 或 PUT,它们都是大写的。可以肯定的是,您总是可以进行 strcasecmp 而不是 == 比较。
【讨论】: