16

PHP urlencode 不得不说的秘密 - PHP 解说

 4 years ago
source link: https://phpjieshuo.com/archives/154/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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。为了防止广告,设置为付费入群。欢迎大家加入讨论技术!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK