解析php中的escape函数


Posted in PHP onJune 29, 2013

采用js对URL中的汉字进行escape编码。
<a href="" onclick="window.open('product_list.php?p_sort='+escape('三水点靠木'));">这样点击链接后的效时:
引用:http://127.0.0.1/shop/product_list.php?p_sort=PHP%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<$sublen;$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}|&#x.{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) == "&#x")
                           $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 (日文)
ps: 韩文是大于[\u9fa5]的字符
正则例子:
preg_replace("/([\x80-\xff])/","",$str);
preg_replace("/([u4e00-u9fa5])/","",$str);
PHP 相关文章推荐
PHP+AJAX实现无刷新注册(带用户名实时检测)
Dec 02 PHP
PHP STRING 陷阱原理说明
Jul 24 PHP
PHP中的MYSQL常用函数(php下操作数据库必备)
Sep 12 PHP
PHP 时间日期操作实战
Aug 26 PHP
PHP中通过语义URL防止网站被攻击的方法分享
Sep 08 PHP
curl实现站外采集的方法和技巧
Jan 31 PHP
如何让搜索引擎抓取AJAX内容解决方案
Aug 25 PHP
php广告加载类用法实例
Sep 23 PHP
php数组键名技巧小结
Feb 17 PHP
PHP获得数组交集与差集的方法
Jun 10 PHP
PHP文件上传小程序 适合初学者学习!
May 23 PHP
PHP进阶学习之依赖注入与Ioc容器详解
Jun 19 PHP
使用PHP会话(Session)实现用户登陆功能
Jun 29 #PHP
php获取数组中重复数据的两种方法
Jun 28 #PHP
php setcookie(name, value, expires, path, domain, secure) 参数详解
Jun 28 #PHP
关于url地址传参数时字符串有回车造成页面脚本赋值失败的解决方法
Jun 28 #PHP
使用PHP实现Mysql读写分离
Jun 28 #PHP
win7下memCache的安装过程(具体操作步骤)
Jun 28 #PHP
浅析memcache启动以及telnet命令详解
Jun 28 #PHP
You might like
如何分别全角和半角以避免乱码
2006/10/09 PHP
模仿OSO的论坛(一)
2006/10/09 PHP
ThinkPHP基本的增删查改操作实例教程
2014/08/22 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
5款适合PHP使用的HTML编辑器推荐
2015/07/03 PHP
Yii2下session跨域名共存的解决方案
2017/02/04 PHP
php+ajax实现异步上传文件或图片功能
2017/07/18 PHP
Laravel 加载第三方类库的方法
2018/04/20 PHP
php转换上传word文件为PDF的方法【基于COM组件】
2019/06/10 PHP
符合W3C网页标准的iframe标签的使用方法
2007/07/19 Javascript
清除网页历史记录,屏蔽后退按钮!
2008/12/22 Javascript
Jquery ajaxsubmit上传图片实现代码
2010/11/04 Javascript
jquery插件jTimer(jquery定时器)使用方法
2013/12/23 Javascript
使用jsonp完美解决跨域问题
2014/11/27 Javascript
JavaScript获取页面上被选中文字的方法技巧
2015/03/13 Javascript
jQuery仿天猫实现超炫的加入购物车
2015/05/04 Javascript
关于js函数解释(包括内嵌,对象等)
2016/11/20 Javascript
node.js中debug模块的简单介绍与使用
2017/04/25 Javascript
BootStrap表单验证 FormValidation 调整反馈图标位置的实例代码
2017/05/17 Javascript
VUEJS 2.0 子组件访问/调用父组件的实例
2018/02/10 Javascript
vue之父子组件间通信实例讲解(props、$ref、$emit)
2018/05/22 Javascript
vue实现简单loading进度条
2018/06/06 Javascript
C#程序员入门学习微信小程序的笔记
2019/03/05 Javascript
node.js处理前端提交的GET请求
2019/08/30 Javascript
JavaScript实现滑块验证解锁
2021/01/07 Javascript
Python编程深度学习绘图库之matplotlib
2018/12/28 Python
Python常用的json标准库
2019/02/19 Python
Python3.5以上版本lxml导入etree报错的解决方案
2019/06/26 Python
Django项目中使用JWT的实现代码
2019/11/04 Python
社区版pycharm创建django项目的方法(pycharm的newproject左侧没有项目选项)
2020/09/23 Python
解决pycharm不能自动保存在远程linux中的问题
2021/02/06 Python
最耐用行李箱,一箱永流传:Briggs & Riley(全球终身保修)
2017/12/07 全球购物
重新定义牛仔布,100美元以下:Warp + Weft
2018/07/25 全球购物
2014大学校园光棍节活动策划书
2014/09/29 职场文书
C#连接ORACLE出现乱码问题的解决方法
2021/10/05 Oracle
centos8安装MongoDB的详细过程
2021/10/24 MongoDB