phpurl传递加号,坑爹的URL编码-PHP正确处理URL中的加号
(+)
问题背景
接收客户端传⼊参数,base64解码失败,经过排查发现原因是参数上传前字符串中有+,但是PHP接收后,发现+变成了空格,导致
base64解码失败。
测试验证
访问⼀个测试的接⼝ /internal/test
curl '127.0.0.1/internal/test?a=abc+def'
验证1:
简单输出$_GET
public function test() {
var_dump($_GET);
}
结果:
array(1) {
["a"]=>
string(7) "abc def"
}
结论:可以看到直接接收GET参数,+变成了空格
+变成空格的原因
经过⼀顿查资料,⾸先我们要知道URL编码是什么
URL编码
⼀个例⼦
这就是URL被编码了,这⾥编码是将中⽂转换成了%开头的两个⼗六进制数。
为什么URL会被编码呢?
url编码处理URL中的参数部分是由⼀个个key=value的参数对组成,⽽如果&=/?等在URL具有⼀定功能的特殊字符出现在key或者value中时,就会导致语义出现不⼀致的情况,例如参数q的值是a&b,那么当出现q=a&b&f=s这样⼀个参数对时,是表⽰q的值是a&b,还是q的值是a,⽽b 的值为空呢?
因此需要对URL进⾏编码,这样被编码过的字符就不再会有歧义,上⾯例⼦中的q=a&b&f=s会被编码成q=a%26b&f=s,你看这样是不是就不会混乱了。
如何对URL进⾏编码呢?
URL如何进⾏编码由RFC标准进⾏规定,
在RFC-1738对URL进⾏说明的各项标准中,提出了要对URL中不安全的字符进⾏编码,编码⽅式即使⽤%和紧跟的两个⼗六进制数字表⽰,注意在该标准中空格被编码成+
在升级版RFC-2396对URI进⾏说明的各项标准中,再次提到了对参数进⾏编码,注意在在该标准中空格被编码成%20
在再次升级版的RFC-3986标准中,对Url的编解码问题做出了更加详细的建议,指出了哪些字符需要被编码才不会引起Url语义的转变,以及对为什么这些字符需要编码做出了相应的解释。
回头来研究下⼀开始的问题
通过以上的资料,我们可以看出来+被变成了空格的原因,正是按照RFC-1738标准进⾏的反编码,也就是.PHP接收$_GET参数遵循的是的是RFC-1738标准。
所以直接读取$_GET时,+就反过来被解码成了空格
怎么解决这个问题
那我们怎么让PHP不按照RFC-1738标准进⾏解码,⽽是按照升级版的RFC-3986标准进⾏解码呢?
最简单的办法当然是让+以正确的⽅式进⾏编码,也就是在客户端请求接⼝时,按照RFC-3986标准进⾏对URL进⾏编码。此时+被编码成%2b,当PHP接收参数时,将%2b解码成+,⼤功告成。
验证结果
对URL进⾏正确的编码
curl '127.0.0.1/internal/test?a=abc%2bdef'
此时可以看到接⼝输出
array(1) {
["a"]=>
string(7) "abc+def"
}
PHP语⾔⾥还有别的坑吗?
除了接收$_GET参数外,PHP中还有对URL参数处理的两个常⽤的函数urlencode和urldecode。
注意这两个函数也是遵循RFC-1738进⾏编码和解码,从官⽹的说明可以看到
This differs from the » RFC 3986 encoding (see rawurlencode()) in that for historical reasons, spaces are encoded as plus (+) signs.
做个试验
先对字符串abc def进⾏编码
$str = 'abc def';
echo urlencode($str);
输出结果
abc+def
然后对字符串a=abc+def进⾏解码
$str = 'a=abc+def';
echo urldecode($str);
输出结果
a=abc def
可以看出确实空格被编码成了+,⽽+则被解码成空格
怎么解决呢?
那PHP⾥⾯有没有使⽤RFC-3986标准进⾏编码的呢,有的,是rawurlencode和rawurldecode,PHP官⽅是这么写的rawurlencode — URL-encode according to RFC 3986
再来做个试验
先对字符串abc def进⾏编码
$str = 'abc def';
echo rawurlencode($str);
输出结果
abc%20def
可以看到空格被编码成%20,然后对字符串a=abc+def进⾏解码
$str = 'a=abc+def';
echo rawurldecode($str);
输出结果
a=abc+def
可以看到+解码后还是+,没有变成空格
结论
所以最符合标准,并且⽐较容易实现的⽅案就是让客户端or前端在请求服务端接⼝时遵循RFC-3986标准进⾏正确的URL编码

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。