Bootstrap

php中{$msg|escape},php中escape函数的实现方法详解

采用js对URL中的汉字进行escape编码。

,点击链接后的效果类似这样:http://127.0.0.1/shop/product_list.php?p_sort=%u5F00%u53D1%u8D44%u6E90%u7F51

可见PHP的urldecode()或者base64_decode()是无法反解的。

可以考虑用php实现一个反解函数,如下:

复制代码 代码示例:

function js_unescape($str){

$ret = '';

$len = strlen($str);

for ($i = 0; $i < $len; $i++)

{

if ($str[$i] == '%' && $str[$i+1] == 'u')

{

$val = hexdec(substr($str, $i+2, 4));

if ($val < 0x7f) $ret .= chr($val);

else if($val < 0x800) $ret .= chr(0xc0|($val>>6)).chr(0x80|($val&0x3f)); else $ret .= chr(0xe0|($val>>12)).chr(0x80|(($val>>6)&0x3f)).chr(0x80|($val&0x3f));

$i += 5;

}

else if ($str[$i] == '%')

{

$ret .= urldecode(substr($str, $i, 3));

$i += 2;

}

else $ret .= $str[$i];

}

return $ret;}

?>

注意JS编码会自动转换成为UTF-8, 所以必须进行编码转换才能得到正确的结果,否则会中文乱码。但如果使用UTF-8编码就不用这一步了。

代码如下:print iconv('utf-8', 'gb2312', js_unescape($_REQUEST['p_sort']));

到此我们就成功地反解了js的escape编码了。

如下:

用PHP实现js的escape编码的函数:

复制代码 代码示例:

function phpescape($str)

{

$sublen=strlen($str);

$retrunString="";

for ($i=0;$i

{

if(ord($str[$i])>=127)

{

$tmpString=bin2hex(iconv("gb2312","ucs-2",substr($str,$i,2)));

//$tmpString=substr($tmpString,2,2).substr($tmpString,0,2);window下可能要打开此项

$retrunString.="%u".$tmpString;

$i++;

} else

{

$retrunString.="%".dechex(ord($str[$i]));

}

}

return $retrunString;

}

?>

在json中不支持中文,用它传送中文数据就会出现数据丢失或者乱码,必须在传 送前对要发送的字符串进行编码,由于传送过去需要用js进行数据解析,考虑到js中有unescape函数,故若在php中有个escape函数,对数据 进行编码,在客户端用unescape进行 解码,这样就会方便很多。

很多用php实现的escape函数,基本类似,这里举个例子:

复制代码 代码示例:

function phpEscape($str) {

preg_match_all("/[\x80-\xff].|[\x01-\x7f]+/",$str,$r);

$ar = $r[0];

foreach($ar as $k=>$v) {

if(ord($v[0]) < 128)

$ar[$k] = rawurlencode($v);

else

$ar[$k] = "%u".bin2hex(iconv("GB2312","UCS-2",$v));

}

return join("",$ar);

}

?>

解释一下这个函数的原理。

第一句:preg_match_all("/[\x80-\xff].|[\x01-\x7f]+/",$str,$r);这个是用正则表达式匹配 字符串中所有的字符,[\x80-\xff]. 匹配的是汉字,\x表示匹配字符的16进制编码,[ ] 是类选择符,“.” 表示任意一个字符,这样[\x80-\xff].匹配的是两个字符,其中第一个就是16进制从80到ff的字符,而这恰好就是汉字编码的第一个字符。这样 就能完整的匹配一个汉字。关于unicode中汉字的编码,大家可以到网上搜索一下。

同理,[\x01-\x7f]+英文字符串,因为最早的英文是 ASCII编码,编码值小于128,也就是16进制的从01到7f,"+"表示一个或者多个字符,这样[\x01-\x7f]+就能匹配连续多个英文字符 串。

示例:

复制代码 代码示例:

$ar = $r[0]; //$r[0]里存放是匹配到的数组

foreach($ar as $k=>$v) {

if(ord($v[0]) < 128) //假如字符编码值小于128,说明是个英文字符

$ar[$k] = rawurlencode($v); //直接用rawurlencode编码

else

$ar[$k] = "%u".bin2hex(iconv("GB2312","UCS-2",$v)); //否则的话用iconv函数把汉字转变成ucs-2编码,也就是unicode编码

}

?>

在javascript中就可以用unescape来解码了。

\u0391-\uFFE5 和\u4e00-\u9fa5来匹配中文。

但好像前者包含汉字下的A-¥等 后者可能是纯汉字。

其中解码函数为:

复制代码 代码示例:

function unescape($str) {

$str = rawurldecode($str);

preg_match_all("/%u.{4}|.{4};|\d+;|.+/U",$str,$r);

$ar = $r[0];

foreach($ar as $k=>$v) {

if(substr($v,0,2) == "%u")

$ar[$k] = iconv("UCS-2","GBK",pack("H4",substr($v,-4)));

elseif(substr($v,0,3) == "")

$ar[$k] = iconv("UCS-2","GBK",pack("H4",substr($v,3,-1)));

elseif(substr($v,0,2) == "") {

$ar[$k] = iconv("UCS-2","GBK",pack("n",substr($v,2,-1)));

}

}

return join("",$ar);

}

?>

一、编码范围

1,GBK (GB2312/GB18030)

\x00-\xff GBK双字节编码范围

\x20-\x7f ASCII

\xa1-\xff 中文

\x80-\xff 中文

2,UTF-8 (Unicode)

\u4e00-\u9fa5 (中文)

\x3130-\x318F (韩文

\xAC00-\xD7A3 (韩文)

\u0800-\u4e00 (日文)

备注:韩文是大于[\u9fa5]的字符

正则例子:

复制代码 代码示例:

preg_replace("/([\x80-\xff])/","",$str);

preg_replace("/([u4e00-u9fa5])/","",$str);

;