處理 cookie

用純 PHP 處理 HTTP cookie 並不困難。不過 Yii 框架讓這件事情更簡單一些。

下面我們說明如何處理一般的 cookie 行為。

要設置 cookie,或者說,要建立一個 cookie 檔案並傳給瀏覽器的話,在 Yii 我們可以建立一個\yii\web\Cookie物件,並加入回應cookies 集合:

$cookie = new Cookie([
    'name' => 'cookie_monster',
    'value' => 'Me want cookie!',
    'expire' => time() + 86400 * 365,
]);
\Yii::$app->getResponse()->getCookies()->add($cookie);

上面的程式碼裡面,傳了一些參數給 Yii 的cookie 物件建構子。這些參數基本上與 PHP 原本的setcookie 函式參數相同:

  • name
    • cookie的名稱
  • value
    • cookie的值。必須確定是一個字串。如果不是字串的話,可能會讓大多瀏覽器不太開心。
  • domain
    • cookie 的網域
  • expire
    • unix 時間戳記,標記 cookie 該被刪掉的時間
  • path
    • cookie 的伺服器路徑。
  • secure
    • 設置為true的話, cookie 只有在使用 HTTPS 的狀況下才會建立。
  • httpOnly
    • 設置為true的話,cookie 無法透過 JavaScript存取。

取得cookie的程式碼如下:

$value = \Yii::$app->getRequest()->getCookies()->getValue('my_cookie');

3. 在哪邊設置與取得cookie?

cookie 是 HTTP 請求的一部分,而網頁請求與回應都屬於控制器(controller)的責任,所以建議把cookie相關的程式碼放在控制器裡面。

因為安全性問題,一般cookie只能在同一個網域裡面做存取。舉例來說,如果你把cookie的網域是example.com,那麼www.example.com就不能取得這個 cookie。所以如果我們需要使用子網域(像是admin.example.com、profile.example.com……) cookie的domain要特別設置:

$cookie = new Cookie([
    'name' => 'cookie_monster',
    'value' => 'Me want cookie everywhere!',
    'expire' => time() + 86400 * 365,
    'domain' => '.example.com' // <<<=== 這裡!
]);
\Yii::$app->getResponse()->getCookies()->add($cookie);

現在這個 cookie 在所有example.com的子網域都會生效了。

5. 跨子網域身份驗證和身份cookie

在自動登入或者「記住我」的這種 cookie,與子網域的cookie技巧相同。不過這次必須在 user 元件裡面,在identityCookie陣列寫入我們想要的 cookie 設定。

在 config 檔案裡面的 user 元件裡面,加入 identityCookie參數:

$config = [
    // ...
    'components' => [
        // ...
        'user' => [
            'class' => 'yii\web\User',
            'identityClass' => 'app\models\User',
            'enableAutoLogin' => true,
            'loginUrl' => '/user/login',
            'identityCookie' => [ // <<<=== 這裡!

                'name' => '_identity',
                'httpOnly' => true,
                'domain' => '.example.com',// <<<=== 注意這裡!
            ],
        ],
        'request' => [
            'cookieValidationKey' => 'your_validation_key'
        ],
        'session' => [
            'cookieParams' => [
                'domain' => '.example.com',// <<<=== 注意這裡!
                'httpOnly' => true,
            ],
        ],

    ],
];

注意每個子網域底的 cookieValidationKey都應該要相同。

另外,session::cookieParams參數和user::identityCookie必須在所有的子網域都一樣,以確定所有子網域的loginlogout運作正常。這部份在之後的章節,會解釋的更加詳細。

如果你想在子網域切換時還能維持session,或者你希望後台/admin網址裡面的 session 要與其他地方分開處理,這兩種情況下 session cookies 參數都是很重要的。

$config = [
    // ...
    'components' => [
        // ...
        'session' => [
            'name' => 'admin_session',
            'cookieParams' => [
                'httpOnly' => true,
                'path' => '/admin',
            ],
        ],
    ],
];

7. 其他資料

results matching ""

    No results matching ""