PHP unserialize() 函数(超详细)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

什么是 PHP unserialize() 函数?

PHP 的 unserialize() 函数是与 serialize() 函数相对应的核心功能之一。它用于将序列化后的字符串还原为原始的 PHP 变量,例如数组、对象等。简单来说,unserialize() 的作用就像“拆开包裹”——它将经过序列化处理的紧凑字符串重新解析为可操作的数据结构。

举个形象的比喻:假设你有一个快递包裹,里面装着各种物品(如衣服、书籍、电子产品)。序列化(serialize())就像是将这些物品拆解、压缩并打包成一个密封的盒子,而 unserialize() 则是打开盒子,按原样还原所有物品的位置和状态。

如何正确使用 unserialize() 函数?

基本语法与示例

unserialize() 函数的语法非常简单:

mixed unserialize( string $str )  

其中 $str 是序列化后的字符串。如果序列化失败,函数将返回 false

示例 1:数组的序列化与反序列化

// 定义一个数组  
$data = array(  
    'name' => 'Alice',  
    'age' => 25,  
    'hobbies' => array('reading', 'coding')  
);  

// 序列化数组  
$serialized_data = serialize($data);  
echo "Serialized String:\n";  
echo $serialized_data;  
// 输出类似:a:3:{s:4:"name";s:5:"Alice";s:3:"age";i:25;s:7:"hobbies";a:2:{i:0;s:6:"reading";i:1;s:6:"coding";}}  

// 反序列化  
$restored_data = unserialize($serialized_data);  
echo "\n\nRestored Array:\n";  
print_r($restored_data);  
// 输出原始数组结构  

示例 2:对象的反序列化

当处理对象时,unserialize() 需要确保对象的类定义已加载:

class User {  
    public $id;  
    public $username;  
}  

$user = new User();  
$user->id = 123;  
$user->username = 'Bob';  

// 序列化对象  
$serialized_user = serialize($user);  

// 反序列化时,必须先定义 User 类  
$restored_user = unserialize($serialized_user);  
echo "User ID: " . $restored_user->id; // 输出 123  

支持的数据类型

unserialize() 可以还原以下 PHP 数据类型:
| 数据类型 | 序列化前缀 | 示例 |
|----------------|------------|----------------------|
| 字符串 | s | s:5:"Hello"; |
| 整数 | i | i:42; |
| 布尔值 | b | b:1; (代表 true) |
| 数组 | a | a:2:{...} |
| 对象 | O | O:4:"User":2:{...} |

注意事项

  1. 类定义必须存在:反序列化对象时,若类未定义,会触发 E_NOTICE 错误,并返回 false
  2. 嵌套结构支持:可以处理多维数组、嵌套对象等复杂结构。
  3. 二进制安全:序列化后的字符串是二进制安全的,可以安全地存储或传输。

unserialize() 的实际应用场景

场景 1:会话数据存储

PHP 的 $_SESSION 数据默认通过序列化存储。例如,将用户购物车信息保存到 session 中:

// 将购物车数据序列化后存入 session  
$_SESSION['cart'] = serialize($cart_data);  

// 取回数据时反序列化  
$cart = unserialize($_SESSION['cart']);  

场景 2:缓存优化

通过序列化将大型对象或数组保存到缓存(如 Redis)中,减少重复计算:

// 序列化后存储到 Redis  
$redis->set('cache_key', serialize($large_data));  

// 取回并反序列化  
$restored_data = unserialize($redis->get('cache_key'));  

场景 3:API 数据传输

在前后端交互中,可通过序列化将复杂数据结构编码为字符串传输:

// 后端生成响应数据  
$response = array(  
    'status' => 'success',  
    'data' => array('id' => 101, 'content' => 'Hello World')  
);  

// 序列化后返回  
echo serialize($response);  

unserialize() 的潜在风险与安全防护

风险 1:PHP Object Injection(对象注入)

当反序列化不可信的数据时,攻击者可能构造恶意对象,触发代码执行。例如:

// 假设存在一个危险类  
class DangerousClass {  
    public function __destruct() {  
        // 这里可能执行任意代码  
        system('rm -rf /');  
    }  
}  

// 攻击者构造的恶意序列化字符串  
$malicious_data = 'O:15:"DangerousClass":0:{}';  

// 未经验证直接反序列化  
unserialize($malicious_data); // 触发危险操作  

风险 2:数据结构不匹配

如果序列化后的字符串与当前类结构不一致(例如类新增了属性),反序列化可能导致数据丢失或逻辑错误。

安全防护措施

  1. 避免反序列化不可信数据

    • 仅对内部生成的、可验证的序列化字符串使用 unserialize()
    • 对用户输入或第三方数据,优先采用 JSON 或 XML 等更安全的格式。
  2. 自定义反序列化逻辑
    通过 __wakeup() 魔术方法验证数据合法性:

    class SecureUser {  
        public $id;  
        public $username;  
    
        public function __wakeup() {  
            if (!is_int($this->id) || !is_string($this->username)) {  
                throw new Exception('Invalid data format');  
            }  
        }  
    }  
    
  3. 使用安全替代方案

    • 对于对象存储,考虑使用 json_encode()/json_decode()(但需注意对象的兼容性)。
    • 对于复杂场景,可采用数据库结构化存储替代序列化。

常见问题解答

Q1: 如何判断序列化后的字符串是否有效?

可以通过 is_serialized() 函数(PHP 5.6+)验证:

if (is_serialized($str)) {  
    // 安全地执行反序列化  
}  

Q2: 反序列化失败时如何调试?

在开发环境中开启 display_errors = On,并检查错误日志。对于复杂结构,可以先手动解析序列化字符串,确认格式是否正确。

Q3: 是否支持跨版本反序列化?

PHP 的序列化格式在不同版本间兼容性较好,但需注意:

  • 类结构修改可能导致数据丢失。
  • 对象反序列化时,类的 __wakeup() 方法在 PHP 5.3+ 版本中会被自动调用。

结论

unserialize() 函数是 PHP 开发中一个强大但需谨慎使用的工具。通过理解其工作机制、掌握安全防护策略,并结合实际案例实践,开发者可以高效利用它处理复杂数据结构,同时避免潜在的安全风险。在使用时,始终遵循“不信任任何外部输入”的原则,确保应用的稳定性和安全性。

掌握 unserialize() 的核心逻辑,不仅能提升代码效率,更能为构建健壮的 PHP 应用奠定基础。

最新发布