unserialize() 返回 false 通常是因為序列化字串中的長度標識與實際字串長度不一致。常見原因包括:編碼不一致(UTF-8 vs Latin1 導致中文字元長度計算差異)、單雙引號轉換、控制字元(如 `\r`)干擾。本文分析根因並提供修復函數。
<?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:"https://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:長度:"值";。檢查上例兩處錯誤:
| 欄位 | 序列化標示長度 | 實際字元長度 | 原因 |
|---|---|---|---|
name | s:6 | UTF-8 下「新晨」為 6 位元組(各 3 字節) | 若儲存時為 Latin1,實際為 4 位元組 |
rpage | s:29 | URL 實際 30 字元 | 可能含 `\r` 或編碼差異導致計數偏差 |
常見觸發場景:
latin1,連線編碼為 utf8,讀寫時長度計算不一致。addslashes/stripslashes、json_encode/decode 導致引號轉換。\r\n` 殘留在字串中。function mb_unserialize($serial_str) {
// 重新計算所有 s:長度:"值" 的實際位元組長度
$serial_str = preg_replace_callback(
'!s:(\d+):"(.*?)";!s',
function ($m) {
return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
},
$serial_str
);
// 移除殘留的 \r
$serial_str = str_replace("\r", '', $serial_str);
return @unserialize($serial_str);
}
function asc_unserialize($serial_str) {
$serial_str = preg_replace_callback(
'!s:(\d+):"(.*?)";!s',
function ($m) {
return 's:' . strlen($m[2]) . ':"' . $m[2] . '";';
},
$serial_str
);
$serial_str = str_replace("\r", '', $serial_str);
return @unserialize($serial_str);
}
<?php
header('Content-Type: text/html; charset=utf-8');
$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:"https://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)
var_dump(mb_unserialize($str)); // 正確陣列輸出
array(9) {
["time"]=> int(1405306402)
["name"]=> string(6) "新晨"
["url"]=> string(1) "-"
["word"]=> string(1) "-"
["rpage"]=> string(30) "https://www.baidu.com/test.html"
["cpage"]=> string(1) "-"
["ip"]=> string(15) "117.151.180.150"
["ip_city"]=> string(31) "中國北京市 北京市移動"
["miao"]=> string(1) "5"
}
SET NAMES utf8mb4、default_charset = "UTF-8")。serialize() 產生,unserialize() 解析。$data = str_replace(["\r", "\0"], '', $data); 移除控制字元。json_encode/decode),無長度標識問題,除非必須保留 PHP 物件型別。TEXT 或 BLOB,避免 VARCHAR 截斷。PHP 7+ 可實現 Serializable 介面或使用 __serialize/__unserialize 魔術方法,完全掌控序列化格式,避免內建格式的編碼敏感問題。
掌握序列化長度不匹配的修復原理,能快速解決跨系統、跨編碼環境下的資料遷移與相容性問題,建議專案統一遷移至 JSON 格式從根本上消除此類風險。