php中unserialize返回false的解决方法

前端技术 2023/09/01 PHP

本文实例讲述了php中unserialize返回false的解决方法,分享给大家供大家参考。具体方法如下:

php 提供serialize(序列化) 与unserialize(反序列化)方法。
使用serialize序列化后,再使用unserialize反序列化就可以获取原来的数据。

先来看看如下程序实例:

<?php 
$arr = array( 
  \'name\' => \'fdipzone\', 
  \'gender\' => \'male\' 
); 
 
$str = serialize($arr); //序列化 
echo \'serialize str:\'.$str.\"\\r\\n\\r\\n\"; 
 
$content = unserialize($str); // 反序列化 
echo \"unserialize str:\\r\\n\"; 
var_dump($content); 
?> 

输出:

serialize str:a:2:{s:4:\"name\";s:8:\"fdipzone\";s:6:\"gender\";s:4:\"male\";} 
 
unserialize str: 
array(2) { 
 [\"name\"]=> 
 string(8) \"fdipzone\" 
 [\"gender\"]=> 
 string(4) \"male\" 
} 

但下面这个例子反序列化会返回false

<?php 
$str = \'a:9:{s:4:\"time\";i:1405306402;s:4:\"name\";s:6:\"新晨\";s:5:\"url\";s:1:\"-\";s:4:\"word\";s:1:\"-\";s:5:\"rpage\";s:29:\"http://www.baidu.com/test.html\";s:5:\"cpage\";s:1:\"-\";s:2:\"ip\";s:15:\"117.151.180.150\";s:7:\"ip_city\";s:31:\"中国北京市 北京市移动\";s:4:\"miao\";s:1:\"5\";}\'; 
var_dump(unserialize($str)); // bool(false) 
?> 

检查序列化后的字符串,发现出问题是在两处地方:

s:5:\"url\"
s:29:\"http://www.baidu.com/test.html\"
这两处应为
s:3:\"url\"
s:30:\"http://www.baidu.com/test.html\"

出现这种问题的原因是序列化数据时的编码与反序列化时的编码不一致导致,例如数据库是latin1和UTF-8字符长度不一样。
另外有可能出问题的还有单双引号,ascii字符\"\\0\"被解析为 \'\\0\',\\0在C中是字符串的结束符等于chr(0),错误解析后算了2个字符。
\\r在计算长度时也会出问题。

解决方法如下:

// utf8 
function mb_unserialize($serial_str) { 
  $serial_str= preg_replace(\'!s:(\\d+):\"(.*?)\";!se\', \"\'s:\'.strlen(\'$2\').\':\\\"$2\\\";\'\", $serial_str ); 
  $serial_str= str_replace(\"\\r\", \"\", $serial_str); 
  return unserialize($serial_str); 
} 
 
// ascii 
function asc_unserialize($serial_str) { 
  $serial_str = preg_replace(\'!s:(\\d+):\"(.*?)\";!se\', \'\"s:\".strlen(\"$2\").\":\\\"$2\\\";\"\', $serial_str ); 
  $serial_str= str_replace(\"\\r\", \"\", $serial_str); 
  return unserialize($serial_str); 
} 

例子:

echo \'<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\'; 
 
// utf8 
function mb_unserialize($serial_str) { 
  $serial_str= preg_replace(\'!s:(\\d+):\"(.*?)\";!se\', \"\'s:\'.strlen(\'$2\').\':\\\"$2\\\";\'\", $serial_str ); 
  $serial_str= str_replace(\"\\r\", \"\", $serial_str); 
  return unserialize($serial_str); 
} 
 
$str = \'a:9:{s:4:\"time\";i:1405306402;s:4:\"name\";s:6:\"新晨\";s:5:\"url\";s:1:\"-\";s:4:\"word\";s:1:\"-\";s:5:\"rpage\";s:29:\"http://www.baidu.com/test.html\";s:5:\"cpage\";s:1:\"-\";s:2:\"ip\";s:15:\"117.151.180.150\";s:7:\"ip_city\";s:31:\"中国北京市 北京市移动\";s:4:\"miao\";s:1:\"5\";}\'; 
 
var_dump(unserialize($str));  // false 
 
var_dump(mb_unserialize($str)); // 正确 

使用处理过单双引号,过滤\\r的mb_unserialize方法就能成功反序列化了。

使用unserialize:

bool(false) 
 
使用mb_unserialize

array(9) { 
 [\"time\"]=> 
 int(1405306402) 
 [\"name\"]=> 
 string(6) \"新晨\" 
 [\"url\"]=> 
 string(1) \"-\" 
 [\"word\"]=> 
 string(1) \"-\" 
 [\"rpage\"]=> 
 string(30) \"http://www.baidu.com/test.html\" 
 [\"cpage\"]=> 
 string(1) \"-\" 
 [\"ip\"]=> 
 string(15) \"117.151.180.150\" 
 [\"ip_city\"]=> 
 string(31) \"中国北京市 北京市移动\" 
 [\"miao\"]=> 
 string(1) \"5\" 
}

希望本文所述对大家PHP程序设计的学习有所帮助。

本文地址:https://www.stayed.cn/item/2227

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。