PHP 的 session 通过使用唯一的会话 ID 将用户的数据保存在服务器端。每次用户发出请求时,PHP 会查找该会话 ID,并加载对应的会话数据。数据通常是通过 $_SESSION 超全局变量进行存取的。
PHP 在内部自动使用 serialize 函数将对象或数组等数据转化为字符串存储,并且用 unserialize 函数将其还原为原始数据类型。
不过,有时我们希望直接访问这些序列化后的数据,或者手动处理它们,这时 unserialize 函数就显得尤为重要。
unserialize 函数用于将序列化的字符串转化为 PHP 变量。
<span><span><span class="hljs-keyword">mixed</span></span><span> </span><span><span class="hljs-title function_ invoke__">unserialize</span></span><span> ( </span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-variable">$data</span></span><span> [, </span><span><span class="hljs-keyword">array</span></span><span> </span><span><span class="hljs-variable">$options</span></span><span> = [] ] )
</span></span>
$data:要反序列化的字符串。
$options:可选的参数,提供额外的反序列化控制(PHP 7+ 支持)。例如,可以指定允许反序列化的类。
成功时返回反序列化后的变量,失败时返回 false。
假设我们有一个用户对象,里面包含了一些用户的基本信息。我们将会手动将该对象序列化,并存储在 session 中。
<span><span><span class="hljs-title function_ invoke__">session_start</span></span><span>();
</span><span><span class="hljs-comment">// 创建一个用户对象</span></span><span>
</span><span><span class="hljs-class"><span class="hljs-keyword">class</span></span></span><span> </span><span><span class="hljs-title">User</span></span><span> {
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-variable">$name</span></span><span>;
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-variable">$email</span></span><span>;
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">__construct</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$name</span></span></span><span>, </span><span><span class="hljs-variable">$email</span></span><span>) {
</span><span><span class="hljs-variable language_">$this</span></span><span>->name = </span><span><span class="hljs-variable">$name</span></span><span>;
</span><span><span class="hljs-variable language_">$this</span></span><span>->email = </span><span><span class="hljs-variable">$email</span></span><span>;
}
}
</span><span><span class="hljs-comment">// 实例化用户对象</span></span><span>
</span><span><span class="hljs-variable">$user</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title class_">User</span></span><span>(</span><span><span class="hljs-string">'John Doe'</span></span><span>, </span><span><span class="hljs-string">'[email protected]'</span></span><span>);
</span><span><span class="hljs-comment">// 将用户对象序列化后存入 session</span></span><span>
</span><span><span class="hljs-variable">$_SESSION</span></span><span>[</span><span><span class="hljs-string">'user_data'</span></span><span>] = </span><span><span class="hljs-title function_ invoke__">serialize</span></span><span>(</span><span><span class="hljs-variable">$user</span></span><span>);
</span></span>
在上面的代码中,我们创建了一个 User 类,并将一个用户对象 John Doe 序列化后存储到 $_SESSION['user_data'] 中。
一旦数据存入 session,我们可以在随后的请求中恢复它。通过 unserialize 函数,我们能够将存储在 session 中的序列化数据还原为原始的对象形式。
<span><span><span class="hljs-title function_ invoke__">session_start</span></span><span>();
</span><span><span class="hljs-comment">// 检查 session 中是否有 'user_data' 数据</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$_SESSION</span></span><span>[</span><span><span class="hljs-string">'user_data'</span></span><span>])) {
</span><span><span class="hljs-comment">// 反序列化 session 数据</span></span><span>
</span><span><span class="hljs-variable">$user</span></span><span> = </span><span><span class="hljs-title function_ invoke__">unserialize</span></span><span>(</span><span><span class="hljs-variable">$_SESSION</span></span><span>[</span><span><span class="hljs-string">'user_data'</span></span><span>]);
</span><span><span class="hljs-comment">// 输出用户信息</span></span><span>
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">'Name: '</span></span><span> . </span><span><span class="hljs-variable">$user</span></span><span>->name . </span><span><span class="hljs-string">'<br>'</span></span><span>;
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">'Email: '</span></span><span> . </span><span><span class="hljs-variable">$user</span></span><span>->email . </span><span><span class="hljs-string">'<br>'</span></span><span>;
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">'No user data found in session.'</span></span><span>;
}
</span></span>
在这段代码中,我们首先检查 $_SESSION['user_data'] 是否存在。如果存在,我们使用 unserialize 函数将其还原为 User 对象,然后输出该对象的属性。
使用 unserialize 函数时,必须特别注意安全性问题。尤其是反序列化来自不可信源的数据时,可能导致对象注入攻击。这可能会让攻击者通过构造恶意的序列化数据来执行危险的操作。因此,推荐在使用 unserialize 时,添加安全措施来避免此类问题。
在 PHP 7+ 中,可以通过设置 allowed_classes 选项来限制反序列化的类。例如,限制只能反序列化 User 类:
<span><span><span class="hljs-variable">$options</span></span><span> = [</span><span><span class="hljs-string">'allowed_classes'</span></span><span> => [</span><span><span class="hljs-string">'User'</span></span><span>]];
</span><span><span class="hljs-variable">$user</span></span><span> = </span><span><span class="hljs-title function_ invoke__">unserialize</span></span><span>(</span><span><span class="hljs-variable">$_SESSION</span></span><span>[</span><span><span class="hljs-string">'user_data'</span></span><span>], </span><span><span class="hljs-variable">$options</span></span><span>);
</span></span>
这样,只有 User 类的对象才能被反序列化,其他类则会被阻止。
在跨版本或跨服务器的 PHP 环境中,unserialize 可能会遇到兼容性问题。例如,如果某个类在不同版本中发生了变化,反序列化时可能会失败。为避免这种问题,开发者可以使用 json_encode 和 json_decode 作为替代方法,尤其是在涉及简单数据结构时。