2015年10月23日 星期五

Laravel的Session不等於PHP Native Session

在Laravel內我們可能寫了以下的程式碼

get('/session', function () {
    session_start();
    session()->put('foo', 'bar');
    $_SESSION['foo'] = 'bar';

    header('location: '.url('/session/display'));
    exit;
});

get('/session/display', function () {
    session_start();
    ob_start();
    dump(session()->get('foo'));
    dump($_SESSION['foo']);
    $content = ob_get_clean();

    // output null, 'bar'

    return $content;
});

會發現輸出結果完全不如我們所預期,為什麼會這樣呢?我們就好好的來做個探討吧...

原因出在Laravel的Session根本不是用PHP Native Session

在遇到這個狀況後,於是就去查了一下Laravel Session倒底是怎麼一回事,發現Laravel的程式碼內根本沒有執行session_start()啊

Laravel Session倒底是怎麼運作的

追了一下Laravel的原始碼,發現它是利用Illuminate\Session\Middleware\StartSession來進行php session模擬的, 在Laravel執行的最後階段在將存在記憶體內的資料進行實體寫入, 所以只要在我們只要在程式內任意一個地方執行了php的exit, die, header('location: xxx'); 那Session就不會被存入檔案內,自然在下一次連線也就取不到值了

有沒有解決方案

有,當然有,只要輸入

get('/session', function () {
    session_start();
    session()->put('foo', 'bar');
    $_SESSION['foo'] = 'bar';
    session()->save(); // 手動寫入
    dump($_SESSION['foo']);
    $content = ob_get_clean();

    // output 'bar', 'bar'

    return $content;
});

後記

為什麼會有這一篇的出現,因為我們可能會用很多其它已經寫好的library,但它們就是有用到session_start();外加header, die, exit等等指令啊,所以記錄一下來提醒自己囉