理顺 HTTP URL 参数传递编码问题

1、中文乱码

中文乱码一般出现在 Window 服务器上,系统采用了 GBK 编码,所以要事先进行 UTF-8 解码

2、浏览器编码

先看下面的两条普通 URL

https://abc.com/t/s?q=【家务清洁】https://c.zh.cn/h.eJQuV1C?sm=c0df48%20
Request URL: https://abc.com/t/s?q=%E3%80%90%E5%AE%B6%E5%8A%A1%E6%B8%85%E6%B4%81%E3%80%91https://c.zh.cn/h.eJQuV1C?sm=c0df48%20

https://abc.com/t/s?q=【家务清洁】https%3A%2F%2Fc.zh.cn%2Fh.eJQuV1C%3Fsm%3Dc0df48%2520
Request URL: https://abc.com/t/s?q=%E3%80%90%E5%AE%B6%E5%8A%A1%E6%B8%85%E6%B4%81%E3%80%91https%3A%2F%2Fc.zh.cn%2Fh.eJQuV1C%3Fsm%3Dc0df48%2520

第一条是通过浏览器输入,打印结果数据有丢失

array(1) { ["q"]=> string(54) "【家务清洁】https://c.zh.cn/h.eJQuV1C?sm=c0df48 " }

第二条是通过 FORM 表单提交自动加了 urlencode 编码,打印结果正常

array(1) { ["q"]=> string(56) "【家务清洁】https://c.zh.cn/h.eJQuV1C?sm=c0df48%20" }

小结:非 ASCII 码会自动编码,服务器自动解码

再看两条 PATHINFO 模式 URL

https://abc.com/t/s/q/【家务清洁】https://c.zh.cn/h.eJQuV1C?sm=c0df48%20
Request URL: https://abc.com/t/s/q/%E3%80%90%E5%AE%B6%E5%8A%A1%E6%B8%85%E6%B4%81%E3%80%91https://c.zh.cn/h.eJQuV1C?sm=c0df48%20

https://abc.com/t/s/q/【家务清洁】https%3A%2F%2Fc.zh.cn%2Fh.eJQuV1C%3Fsm%3Dc0df48%2520
Request URL: https://abc.com/t/s/q/%E3%80%90%E5%AE%B6%E5%8A%A1%E6%B8%85%E6%B4%81%E3%80%91https%3A%2F%2Fc.zh.cn%2Fh.eJQuV1C%3Fsm%3Dc0df48%2520

打印结果一样

array(3) { ["q"]=> string(24) "【家务清洁】https:" ["cn"]=> string(1) "h" ["sm"]=> string(7) "c0df48 " }

在使用 PATHINFO 模式时,”/” 会被解释为参数,所以最好先进行安全编码,尤其有带 “/” 参数时

// 对URL和文件名有特殊意义的字符来作为加密字符,具体就是以-和_取代+和/
function urlsafe($string, $operation = 'ENCODE') {
	if($operation == 'ENCODE') { 
		$string = str_replace('=','-',str_replace('/', '!', str_replace('+', '_', $string))); 
	}else {
		$string = str_replace('_','+',str_replace('!', '/', str_replace('-', '=', $string))); 
	}
	return $string;
}

为什么第二个 %20 丢了 ?

在 PATHINFO 模式时,服务器第一次转义后,会有 “c0df48%20” 字符,它认为 %20 还需转义,如果服务器设置了 双重转义,会继续转义,否则会出现 404 错误提示

IIS 服务器设置允许双重转义配置 web.config 代码

<system.webServer>
    <security>
        <requestFiltering allowDoubleEscaping="true"/>
    </security>
<system.webServer>

注意:在使用复杂的参数时,最好不要使用 PATHINFO 模式,urlsafe 安全并非安全,向上面的 “%20” 双重转义,最安全的做法是进行 BASE64 编码再传递

评论

还没有任何评论,你来说两句吧!