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

PHP 序列化與反序列化完整指南:原理、陷阱與最佳實踐

     編輯:PHP 綜合知識

序列化是將資料結構轉為可儲存/傳輸字串的過程,反序列化則是還原。PHP 內建 serialize() / unserialize() 是核心函式,本文深入解析其運作細節、常見陷阱與解決方案。

基本用法

<?php
$user = ['Moe', 'Larry', 'Curly'];

// 序列化
$serialized = serialize($user);
// a:3:{i:0;s:3:"Moe";i:1;s:5:"Larry";i:2;s:5:"Curly";}

// 反序列化
$restored = unserialize($serialized);
// ['Moe', 'Larry', 'Curly']
?>

序列化格式解析

格式意義範例
a:size:{...}陣列a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}
O:len:"class":size:{...}物件O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}
s:len:"value"字串s:5:"hello"
i:value整數i:42
d:value浮點數d:3.14
b:value布林b:1
NNULLN
r:id參考r:1

常見陷阱與解決方案

1. 字元編碼問題(中文、特殊字元導致長度計算錯誤)

<?php
$data = ['name' => '張三', 'desc' => '說明: "引號"'];
$serialized = serialize($data);
// 反序列化可能失敗或資料損壞
?>

解決方案:Base64 編碼包裝

function safe_serialize($data) {
    return base64_encode(serialize($data));
}

function safe_unserialize($str) {
    return unserialize(base64_decode($str));
}

// 進階:加上壓縮節省空間
function my_serialize($data) {
    return base64_encode(gzcompress(serialize($data), 9));
}

function my_unserialize($str) {
    return unserialize(gzuncompress(base64_decode($str)));
}

2. 類別定義不存在導致 __PHP_Incomplete_Class

<?php
// 檔案 A:序列化物件
class User { public $name = 'John'; }
$obj = new User();
file_put_contents('user.dat', serialize($obj));

// 檔案 B:反序列化(未引入 User 類別)
$data = file_get_contents('user.dat');
$obj = unserialize($data);
// $obj 變成 __PHP_Incomplete_Class,無法呼叫方法
?>

解決:

  • 反序列化前 require_once 類別定義
  • 實作 __sleep() / __wakeup() 控制序列化行為
  • 使用 spl_autoload_register() 自動載入
  • 設定 unserialize() 第二參數 ['allowed_classes' => ['User', 'Order']](PHP 7.0+)

3. 物件注入安全風險

絕不可 對不可信輸入(如 $_GET、$_COOKIE、Redis 快取)直接呼叫 unserialize(),攻擊者可構造惡意物件觸發 __wakeup()、__destruct() 等魔術方法導致 RCE。

// 危險範例
$data = unserialize($_COOKIE['data']);  // 絕對禁止!

// 安全做法:改用 JSON
$data = json_decode($_COOKIE['data'], true);

// 若必須用 serialize,嚴格限制允許類別
$data = unserialize($trusted_data, ['allowed_classes' => ['MyApp\\DTO\\User']]);

效能比較

方法速度體積可讀性支援類型
serialize/unserialize快中低所有 PHP 型別(含物件、資源)
json_encode/decode中小高陣列、物件、純量(無資源、循環引用)
var_export + include慢大高陣列、物件(無資源、閉包)
igbinary (擴充)最快最小低所有型別,二進位格式
msgpack (擴充)極快極小低跨語言相容

最佳實踐建議

  1. 快取/Session 儲存:預設 PHP Session 使用 serialize,大量物件考慮 session.serialize_handler = igbinary
  2. API 資料交換:統一使用 JSON,跨語言相容、除錯容易
  3. 設定檔/靜態資料:var_export 產出 PHP 陣列檔,include 直接載入,OPcache 可加速
  4. 高效能隊列/訊息:引入 igbinary 或 msgpack 擴充
  5. 安全第一:不可信資料永遠不要 unserialize,改用 JSON 或簽名驗證

自訂序列化介面

<?php
class User implements Serializable {
    public $id;
    public $name;
    private $password;  // 不序列化敏感欄位

    public function serialize() {
        return serialize(['id' => $this->id, 'name' => $this->name]);
    }

    public function unserialize($data) {
        $arr = unserialize($data);
        $this->id = $arr['id'];
        $this->name = $arr['name'];
        $this->password = null;  // 重新登入時設定
    }
}
?>

掌握序列化細節,能避免許多難以除錯的問題,也能在效能與安全之間取得最佳平衡。

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