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作為替代方法,尤其是在涉及簡單數據結構時。