php serialize()和unserialize()的一个坑

有个业务需求需要把格式化的数据(有中文)存入到数据表中,起初想起里用的json_encode(),随手拈来的函数。可是想起来中文被它格式化存入数据表中,mysql会自动去掉\u的反斜线。等数据取出在decode的时候 又得重新添加,而且会出现误添加,导致错误。后来想起来serialize()和unserialize(),然后还有他们的一个坑。


数据封装在utf-8编码下进行,因此示例数据如下:

a:3:{i:76969;s:12:"山东省的";i:79255;s:6:"试试";i:79256;s:0:"";}


可以看到utf-8下面单个中文字符占用3个字节,所以s对应的值分别是12,6,0;

然后从库里面拿出这段数据放在本地测试,页面编码默认ANSI,然后就会发现unserialize 报如下错误:

Notice: unserialize(): Error at offset 27 of 66 bytes


然后
就是false。然后搜了很多资料才发现,unserialize去反序列化时,会先判断里面字符的长度,然后跟s进行对比,如果对比成功就会解析成功,否则就会报错。

所以如果解析页面的编码跟序列化页面编码不一致的话,就会导致unserialize时strlen的判断和s值不一致,导致错误。


解决办法:  

        1.统一页面编码;

2.找到一个通用的函数:

       原理是重新计算字符的长度,然后替换掉s的值

function common_unserialize($str) {
	if(empty($str)){
		return '';
	}
    $str= preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $str );
    $str= str_replace("\r", "", $str);      
    return unserialize($str);
}


你可能感兴趣的:(php)