首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP unserialize 返回 false 解決方案:序列化字串長度不匹配修復

     編輯:PHP 相關知識

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:長度:"值";。檢查上例兩處錯誤:

欄位序列化標示長度實際字元長度原因
names:6UTF-8 下「新晨」為 6 位元組(各 3 字節)若儲存時為 Latin1,實際為 4 位元組
rpages:29URL 實際 30 字元可能含 `\r` 或編碼差異導致計數偏差

常見觸發場景:

  • 資料庫欄位編碼為 latin1,連線編碼為 utf8,讀寫時長度計算不一致。
  • 跨系統傳輸經過 addslashes/stripslashes、json_encode/decode 導致引號轉換。
  • Windows 換行符 `\r\n` 殘留在字串中。

修復函數

UTF-8 環境修復

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);
}

ASCII/單位元組編碼修復

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"
}

預防最佳實務

  1. 統一編碼:資料庫、連線、PHP 檔案、HTML 頁面全端統一 UTF-8(SET NAMES utf8mb4、default_charset = "UTF-8")。
  2. 避免手工拼裝序列化字串:永遠使用 serialize() 產生,unserialize() 解析。
  3. 儲存前清理:$data = str_replace(["\r", "\0"], '', $data); 移除控制字元。
  4. 改用 JSON:跨語言、跨系統傳輸優先選 JSON(json_encode/decode),無長度標識問題,除非必須保留 PHP 物件型別。
  5. 資料庫欄位型別:儲存序列化資料用 TEXT 或 BLOB,避免 VARCHAR 截斷。

進階:自定義序列化處理器

PHP 7+ 可實現 Serializable 介面或使用 __serialize/__unserialize 魔術方法,完全掌控序列化格式,避免內建格式的編碼敏感問題。

掌握序列化長度不匹配的修復原理,能快速解決跨系統、跨編碼環境下的資料遷移與相容性問題,建議專案統一遷移至 JSON 格式從根本上消除此類風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved