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

PHP serialize 與 unserialize 序列化完整指南

     編輯:PHP 綜合知識

核心概念

  • serialize():將任意 PHP 變數(陣列、物件、標量)轉為可儲存、可傳輸的字串表示,保留型別與結構。
  • unserialize():將序列化字串還原為原始 PHP 變數。
  • 資源型別:不可序列化(如資料庫連線、檔案控制代碼),嘗試會發出 E_NOTICE 並回傳 false。

基本語法與輸出格式

<?php
$arr = ['id' => 1, 'name' => '測試', 'tags' => ['php', 'serialize']];
$str = serialize($arr);
echo $str;
// 輸出:a:3:{s:2:"id";i:1;s:4:"name";s:6:"測試";s:4:"tags";a:2:{i:0;s:3:"php";i:1;s:9:"serialize";}}

// 格式說明:
// a:3 => 陣列 3 元素
// s:2:"id" => 長度 2 字串 "id"
// i:1 => 整數 1
// s:6:"測試" => 長度 6 位元組字串(UTF-8 中文佔 3 位元組)
// 物件格式:O:類別名長度:"類別名":屬性數:{...}
?>

物件序列化:魔術方法 __sleep / __wakeup

<?php
class User {
    public $id;
    public $name;
    private $password; // 敏感欄位不想序列化
    private $db;       // 資源型別不可序列化

    public function __construct($id, $name, $password) {
        $this->id = $id;
        $this->name = $name;
        $this->password = $password;
        $this->db = new PDO('sqlite::memory:');
    }

    // 序列化前調用:指定要保存的屬性名稱陣列
    public function __sleep(): array {
        return ['id', 'name']; // 排除 password、db
    }

    // 反序列化後調用:重新建立資源連線
    public function __wakeup(): void {
        $this->db = new PDO('sqlite::memory:');
        $this->password = '***'; // 重置敏感欄位
    }
}

$user = new User(1, 'Alice', 'secret123');
$serialized = serialize($user);
echo $serialized . "\n";
// O:4:"User":2:{s:2:"id";i:1;s:4:"name";s:5:"Alice";}  // 只有 id、name

$restored = unserialize($serialized);
var_dump($restored); // password 為 '***', db 為新 PDO 實例
?>

實戰應用場景

場景說明注意事項
Session 儲存複雜資料預設 Session 處理器內部即使用 serialize資料量大時考慮 igbinary 或資料庫儲存
快取物件/陣列Redis/Memcached 存入序列化字串注意反序列化效能,熱資料用原生格式
跨程序傳遞資料CLI 腳本間透過檔案/管道傳遞結構化資料版本一致性:類別定義必須存在且相容
資料庫欄位存儲陣列不想建關聯表時,將陣列序列化存 TEXT 欄位無法直接 SQL 查詢內部值,僅適合整體讀寫
API 回應快取將回應物件序列化存檔,下次直接輸出需處理快取失效與結構變更遷移

安全性警示 ⚠️

絕對不要 對不可信輸入(如 $_GET, $_COOKIE, $_POST)直接呼叫 unserialize()。

<?php
// 危險範例:攻擊者可構造惡意序列化字串觸發 __wakeup/__destruct 鏈(POP Chain)
$data = $_COOKIE['data'];
$obj = unserialize($data); // 嚴重安全漏洞!

// 安全做法:
// 1. 使用 JSON (json_encode/json_decode) 替代,不支援物件但無代碼執行風險
// 2. 若必須用 serialize,啟用 PHP 7.0+ 的 allowed_classes 選項
$obj = unserialize($data, ['allowed_classes' => ['MySafeClass']]); // 只允許白名單類別
// 3. 簽名驗證:儲存時簽名,讀取時驗證完整性
$payload = serialize($data);
$signed = $payload . '.' . hash_hmac('sha256', $payload, SECRET_KEY);
// 讀取時驗證簽名再 unserialize
?>

效能優化建議

  • igbinary 擴展:二進位序列化格式,體積縮減 30~50%,速度提升 2~3 倍。session.serialize_handler = igbinary。
  • 避免深層巢狀:扁平化資料結構減少序列化開銷。
  • 大物件分塊:將大陣列拆分多個鍵儲存,按需載入。

版本相容性

  • PHP 4/5 序列化字串在 PHP 7/8 通常可正常還原(類別定義需存在)。
  • PHP 7.4+ 棄用 __sleep 回傳不存在屬性、Serializable 介面(改用 __serialize/__unserialize)。
  • 跨版本部署時,建議以 JSON 或 Protocol Buffers 等與語言無關格式儲存長期資料。

掌握序列化機制與安全邊界,讓資料持久化與傳輸既方便又可靠。

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