php原生序列化用serialize()和unserialize(),不依赖扩展,适合存配置或缓存;但仅限php环境,不可信数据反序列化有安全风险,需限制allowed_classes并校验返回值。

PHP里用serialize()和unserialize()最直接
PHP原生序列化就是靠这两个函数,不依赖扩展、不挑环境,适合存配置、缓存、临时状态。但要注意:它们只认PHP自己的格式,跨语言或长期存储不推荐。
典型用法是把数组或对象转成字符串存进数据库或文件:
$data = ['user_id' => 123, 'role' => 'admin', 'expires' => time() + 3600];
$serialized = serialize($data);
// 结果类似:a:3:{i:0;s:7:"user_id";i:1;s:4:"role";i:2;s:7:"expires";}
关键点:
-
serialize()能处理数组、对象、基本类型,但不能序列化资源(如fopen()返回的句柄)和闭包 - 对象序列化时,如果类定义了
__sleep()方法,会先调它来决定保留哪些属性 -
unserialize()有安全风险——若反序列化不可信数据,可能触发恶意代码(比如通过__wakeup()),生产环境务必避免反序列化用户输入
存数据库时别直接用serialize()字段
MySQL里用TEXT或MEDIUMTEXT字段存serialize()结果没问题,但没法按内容查——比如“找出所有role为admin的记录”,SQL写不出来。
更实际的做法是:
- 只对非查询字段用
serialize(),比如用户偏好设置settings这种整块结构 - 把要检索的字段单独拆成列,比如
user_role、status,保持可索引性 - 如果必须查序列化内容,改用
json_encode()+JSON字段类型(MySQL 5.7+),支持JSON_CONTAINS()等函数
替代方案:json_encode()更通用但有局限
JSON比PHP原生序列化格式更轻、跨语言友好、人眼可读,但不是万能替代:
- 不支持资源、资源句柄、
DOMDocument等复杂对象,会报错或静默丢弃 - 数组键名强制转字符串,数字索引没问题,但
array('foo' => 'bar')可以,array(1.5 => 'bar')会被截成"1" - 中文默认是Unicode转义(
\u4f60),加JSON_UNESCAPED_UNICODE参数可避免:json_encode($data, JSON_UNESCAPED_UNICODE) -
json_decode()默认返回stdClass对象,加第二个参数true才得数组:json_decode($str, true)
注意unserialize()失败时的错误处理
损坏的序列化字符串、版本不兼容(比如PHP 7序列化后在PHP 8反序列化)、或被篡改,都会让unserialize()返回false且触发E_NOTICE警告,但不会抛异常。
稳妥做法是显式检查:
$data = unserialize($raw);
if ($data === false && $raw !== 'b:0;') {
// 'b:0;' 是布尔false的合法序列化结果,需排除
error_log("Unserialize failed on: " . substr($raw, 0, 50));
$data = []; // 或抛异常、返回默认值
}
真正容易被忽略的是:PHP 7.4+ 加了unserialize()的allowed_classes选项,可限制只允许反序列化指定类,防止RCE漏洞。哪怕只是简单后台,只要涉及用户可控输入,就该加上:
unserialize($input, ['allowed_classes' => ['MyConfig', 'MyUser']]);
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











