PHP urlencode 不得不说的秘密

PHP urlencode 方法可以算是使用率比较高的一个方法了。特别是在 API 接口设计的领域或使用其他第三方 API 的时候,经常会碰到使用 urlencode 的场景。

在几年前设计过一套 API 接口提供给 App 客户端调用。Android 客户端使用 Java 开发,他们会把参与按照文档定义的规则把参数名与值进行拼接之后再 urlencode 编码,然后再拼接上一个密钥 KEY 再 MD5 再转换为大写得到一个签名。服务器端收到这个请求之后,也会按照这个规则进行签名生成与客户端提交的签名进行判断。

结果问题就出来了。

// Android 客户端提交的信息如下:
$params = [
    'method'   => 'user.register',  // 注册接口。
    'v'           => '1.0.0',        // APP 版本号。
    'mobile'   => '14812345678',    // 注册手机号。
    'code'     => '123456',        // 短信验证码。
    'password' => 'abcde fg'        // 账号密码。注意这里带了一个空格。
];

// 按照键名自然排序(升序)。
ksort($params);

// 把键名与值拼接。
$str = '';
foreach ($params as $key => $value) {
    $str .= "{$key}{$value}";
}

$key  = 'abckey';         // 密钥 KEY。
$str  = urlencode($str);     // URL encode 转码。
$sign = md5($str . $key);    // 生成签名。
$sign = strtoupper($sign);    // 签名转成大写。

echo $sign; // 输出结果:80ADC8A5878776D971E4ED444FB8386B

上面这一套规则其实非常简单。可问题出就出在上面的 password 参数存在一个空格。而我们使用 urlencode 转码之后,这个空格会被转码成 + 号。

$str = 'xxx xxx';
echo urlencode($str); // 输出:xxx+xxx

而 Java 或者其他的语言,它们的 urlencode 会把空格转码为 %20。很显然 + 与 %20 是完全不相同的字符串。在进行 MD5 签名生成的时候,很显然签名是不对等。

我们查阅 PHP urlencode 的文档获知,它存在历史的原因,并未遵循 RFC3986 标准导致。所以,PHP 提供了另一个遵守 RFC3986 标准的 urlencode 方法:rawurlencode。

该方法与其他语言的 urlencode 方法保持一致的转码规则。

结论:接口设计的时候不要使用 urlencode,而要使用 rawurlencode 方法。

以上是最近对接多家 API 接口之后,重新唤醒了我几年前接口设计时的一些踩坑回忆。于是,今天特意整理并分享给大家。

博主 2011 年创建了一个《PHP 初学者官方群》,目前群成员 500 人左右。群号:168159147。为了防止广告,设置为付费入群。欢迎大家加入讨论技术!

标签: 无

发表评论: