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

大型 PHP 專案架構四:物件序列化機制深度解析與限制

     編輯:PHP 相關知識

PHP serialize/unserialize 運作原理、資料持久化陷阱與現代替代方案

PHP 4 引入物件序列化,允許將物件狀態轉為字串儲存。但僅序列化屬性而非方法,導致反序列化後需重新載入類別定義。本文深度剖析機制、安全風險與最佳實踐。

序列化核心運作示範

<?php
class User {
    public $name;
    public $email;
    private $passwordHash; // 私有屬性也會序列化

    public function __construct($name, $email, $password) {
        $this->name = $name;
        $this->email = $email;
        $this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
    }

    public function greet() {
        return "Hello, {$this->name}!";
    }
}

$user = new User('Alice', 'alice@example.com', 'secret123');
$serialized = serialize($user);
echo "序列化字串:\n$serialized\n\n";

// 輸出範例:
// O:4:"User":3:{s:4:"name";s:5:"Alice";s:5:"email";s:19:"alice@example.com";s:16:"UserpasswordHash";s:60:"$2y$10$...";}

// 儲存至檔案/資料庫
file_put_contents('user.dat', $serialized);

// --- 跨請求/腳本恢復 ---
$loaded = file_get_contents('user.dat');
$user2 = unserialize($loaded);

// 關鍵:類別定義必須已載入 (require 'User.php')
echo $user2->greet(); // 正常運作:方法來自類別定義,非序列化資料
?>

序列化格式解析 (PHP 內部表示)

前綴類型範例
iIntegeri:42;
dFloatd:3.14;
bBooleanb:1;
sStrings:5:"hello";
aArraya:2:{i:0;s:3:"foo";i:1;s:3:"bar";}
OObjectO:8:"stdClass":1:{s:3:"foo";s:3:"bar";}
rReferencer:1;
NNULLN;

關鍵限制與陷阱

⚠️ 方法不被序列化

序列化字串僅包含屬性值。反序列化時,PHP 依據類別名稱尋找已載入的類別定義,並將屬性值注入新實例。若類別定義不存在、簽名不符、或方法邏輯已變更,行為將異常。

🚫 Resource 類型不可序列化

資料庫連線、檔案控制代碼、GD 圖片資源等內部指標無法序列化。嘗試序列化會拋出 Exception (PHP 7.4+) 或產生不完整字串。

🔧 魔術方法精確控制

class User {
    // 序列化前調用:決定哪些屬性被序列化
    public function __sleep() {
        return ['name', 'email']; // 排除 passwordHash、暫時屬性
    }

    // 反序列化後調用:重建資源連線、初始化狀態
    public function __wakeup() {
        $this->db = new PDO(...); // 重新建立 DB 連線
    }

    // PHP 7.4+ 新介面 (推薦替代 __sleep/__wakeup)
    public function __serialize(): array {
        return ['name' => $this->name, 'email' => $this->email];
    }
    public function __unserialize(array $data): void {
        $this->name = $data['name'];
        $this->email = $data['email'];
        $this->db = new PDO(...);
    }
}
?>

安全風險:反序列化漏洞 (Object Injection)

**不可信資料絕對禁止 unserialize()**。攻擊者構造惡意序列化字串,利用 __wakeup/__destruct/__toString 魔術方法鏈 (Gadget Chain) 達成 RCE、檔案寫入、SQL 注入。

  • 已知漏洞框架:Laravel (歷史版本)、Yii、Symfony、WordPress 外掛
  • 防護:unserialize($data, ['allowed_classes' => ['MyClass']]) 白名單 (PHP 7.0+)
  • 替代:JSON (json_encode/decode)、MessagePack、Protocol Buffers — 僅資料、無程式碼執行風險

現代持久化策略選型指南

場景推薦方案理由
Session 儲存PHP 內建 session handler (files/redis/memcached)自動序列化、GC、鎖機制
快取物件Redis + JSON/MessagePack高效能、跨語言、無反序列化風險
排程任務傳遞資料庫 JSON 欄位 / 訊息佇列 (RabbitMQ/Kafka)持久、可查詢、解耦
API 回應JSON (標準)通用、可快取、前端直食
複雜領域物件Event Sourcing + CQRS完整審計軌跡、時間旅行、重放
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved