最近更新: 2006-08-02

PHP~~serialize and unserialize with Form

使用 PHP 的 serialize, compress 及 encode 函數,將 serialized object 儲存在網頁表單中。有 ASP.Net 使用經驗者,這即是 ViewState 的原理。

概論

PHP5 內建了一對 serialize 函數,即 serialize()/unserialize() ,可以將 object (a simple variable, an array, or an object which implement __sleep() method) 以特定字串形式儲存 (serialization)。此外,也可以用 JSON 形式,但需要安裝 php-json extension 才可支援。安裝 php-json 後,可用 json_encode()/json_decode() 進行 serialization 。

接下來,考慮到資料文字儲存在網頁時的傳送安全性以及儲存空間,再對 serialized object 進行資料壓縮及傳送編碼。

PHP 有兩組簡便的資料壓縮函數,即採用 ZLIB 壓縮格式的 gzcompress()/gzuncompress 和採用 DEFLATE 壓縮格式的 gzdeflate()/gzinflate() 。而 gzencode() 是前兩種壓縮格式的資料字串再加上 GZip file header 。我們並不需要 GZip file header ,在此不使用。由於 serialized object 係由一般文字組成,而 DEFLATE 壓縮格式對一般文字的壓縮率較佳,故採用 gzdeflate()/gzinflate() 。

壓縮後的字串,包含 binary 資料,直接儲存在網頁時,會破壞頁面結構,所以必須再加以編碼。 PHP 提供 MIME 的 base64 函數 base64_encode()/base64_decode() , base64 編碼格式只包含 A-Z,0-9, +, / 字元,不會破壞網頁的 HTML 語法,可安全地將資料儲存於網頁中。通常,我們利用網頁表單的隱藏欄位 (hidden input element in form) 儲存 serialized object ,以便隨著表單的提交送回 server 。

範例一

綜合以上說明,一個簡單的範例如下:

<?php
if( !isset($_POST['serialized_obj']) ) {
    $o = array();
    for($i = 0; $i < 100; $i++) {
        $o[$i] = $i*100;
    }
}
else {
    $o = unserialize( gzinflate( base64_decode($_POST['serialized_obj']) ) );
}

echo '<pre>';
var_dump($o);
echo '</pre>';
echo 'Length of serialized object: ', strlen(serialize($o), '<br/>';
echo 'Length of serialized object compressed by deflate: ',
    gzdeflate(strlen(serialize($o)), '<br/>';
echo 'Length of serialized object compressed by zlib: ',
    gzcompress(strlen(serialize($o)), '<br/>';
echo 'In most case, the length of data compressed by deflate will shorter than compressed by zlib.<br/>';

$serialized_obj = base64_encode( gzdeflate( serialize($o) ) );

?>
<form>
    <input name="serialized_obj" type="hidden" value="<?=$serialized_obj?>"/>
    <button name="postback" type="submit">submit</button>
</form>

應用 JSON

如果有需要利用 JavaScript 強化表單使用介面時,則可改用 json_encode()/json_decode() ,兼顧 server-side 的 PHP 及 client-side 的 JavaScript 。使用時須注意,根據 JSON 的規範,必須使用 UTF-8 字元編碼,故在非 UTF-8 環境下時,需先用 iconv() 將非 UTF-8 字元轉換成 UTF-8 字元。

最後要留意的事項是 magic_quotes_gpc 的影嚮。儲存在網頁表單中的 serialized object ,在提交回 server 時,若 magic_quotes_gpc 設定為 On ,則 PHP 會主動在 serialized object 的資料內容中加上必要的斜線字元 (slash, \) 。必須以 stripslashes() 將之去除,才可以 unserialization 。細心的人會注意到,在範例一,並沒有加上 stripslashes() 的動作。這並非失誤。因為範例一最後儲存的是 base64_encode() 的編碼字串,而這種格式的字串中,並未包含任何會被加上斜線字元的字元。亦即回傳的資料內容並不會受到 magic_quotes_gpc 的影嚮,所以並不需要 stripslashes() 。

範例二

<?php
if( !isset($_POST['serialized_obj']) ) {
    $o = array();
    for($i = 0; $i < 100; $i++) {
        $o[$i] = $i*100;
    }
}
else {
    if( get_magic_quotes_gpc() ) {
        $serialized_obj = stripslashes($_POST['serialized_obj']);
    }
    else {
        $serialized_obj = $_POST['serialized_obj'];
    }
    $o = json_decode( preg_replace('/\"/', "'", $serialized_obj) );
}

echo '<pre>';
var_dump($o);
echo '</pre>';
$serialized_obj = json_encode( $o );
?>
<form id="form1">
    <select id="DropDownList1">
    </select>
    <input id="serialized_obj" name="serialized_obj" type="hidden"
        value="<?=preg_replace("/'/", '"', $serialized_obj)?>"/>
    <button name="postback" type="submit">submit</button>
</form>
<script type="text/javascript">
YAHOO.util.Event.addListener(
    window,
    "load",
    function() {
        var o = <?=$serialized_obj?>;
        //var o = eval( '('+document.getElementById('serialized_obj').value()+')' );
        var list1 = document.getElementById('DropDownList1');
        for(var i = 0; i < 100; i++) {
            list1.options[i] = new Option(o[i], i);
        }
    }
);
</script>
相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/1964361.html