做了一个类似开心/校内/facebook开放服务的rest 接口,即:用http请求,并将请求参数用密钥加密后传输。

服务端进行校验的代码如下:

define("KEY","密钥");
 
$str=KEY;
foreach ($_REQUEST as $name => $value) {
    if ($name != 'sig')
        $str .= $name.$value;
}
 
// 如果加密结果不符合,则算鉴权失败。
if(md5($str)!=$_REQUEST["sig"])
       header("status: 400");

发现经常会有请求鉴权失败。经查,发现$_REQUEST里面带上了$_COOKIE中的值,如:PHPSESSIONID, __utma, __utmz等, 故在foreach的遍历中,加了很多和鉴权无关的参数。但是这些代码在自己的PC上又无法重现。

看php文档,对$_REQUEST的解释:An associative array that by default contains the contents of $_GET, $_POST and $_COOKIE. 即 确实是包含了cookie。

但是在自己机器上,确又无法重现:

root@codigg:~# cat dumpreq.php
<?php
print_r($_REQUEST);
?>
root@codigg:~# curl -b "c=3" -d"b=2" "http://localhost/rest.php?a=1"
Array
(
    [a] => 1
    [b] => 2
)

原来这是通过php.ini中的request_order配置来控制的。
在5.3.0之前的php版本中,这个配置没有设置,默认为与variable_order相同,即:GPCS
而5.3.0之后,默认的php.ini中写了 request_order=”GP”

故:
< 5.3.0 $_REQUEST=$_GET+$_POST+$_COOKIE+$_SERVER
>=5.3.0 $_REQUEST=$_GET+$_POST

有问题的服务器,php版本正好是5.2.x。

知道了原因,修改方法就简单了,将foreach语句改成:
foreach (array_merge($_GET,$_POST) as $name => $value) {
就正常了。

参考:

http://cn.php.net/manual/en/ini.core.php#ini.request-order

http://cn.php.net/manual/en/reserved.variables.request.php