d.hetima RSSフィード

2007-02-01

CakePHP に use_trans_sid 風の処理を組み込む

CakePHP のセッションまわりをカスタマイズする の続編。携帯向けのページに、クッキーを使わないセッション処理を組み込む方法です。

手順は、

  • CakeSession クラスの初期化をカスタマイズして、クッキー使用を切り替える
  • フォームやリンクに session_id を仕込む
  • リクエストから session_id を取得してセッションと結びつける

となります。use_trans_sid を使えばもっとシンプルにはなると思いますが、セッションを保持させたくない遷移もあるわけで、その都度指定した方が便利だろうというわけで。

リクエストから session_id を取得してセッションと結びつける

これは Controller の __construct() に書きます。beforeFilter() では既にセッション初期化済みなので間に合わないのです。Controller ごとに処理を書くのは面倒だし DRY じゃないので、抽象的な MobileAppController を作り、携帯向けページの Controller はこのクラスを派生させるようにします。これは app_controller.php に書いています。

<?php
//携帯向け AppController
class MobileAppController extends AppController {
    var $_needs_session_renew=false; //for Session Fixation

    function __construct()
    {
        if(isset($_POST[MY_SESSION_POST_NAME])) $sid=$_POST[MY_SESSION_POST_NAME];
        else if(isset($_GET[MY_SESSION_POST_NAME])) $sid=$_GET[MY_SESSION_POST_NAME];
        else $sid=null;
        if( preg_match('/^[0-9a-f]{32}$/', $sid) ){
            session_id($sid);
            $this->_needs_session_renew=true; //for Session Fixation
        }
        define('MY_CAKE_NO_COOKIE', 1);
        parent::__construct();
    }

    function beforeFilter() {
        //for Session Fixation
        if($this->_needs_session_renew){
            $this->Session->renew();
        }
        parent::beforeFilter();
    }
}
?>

定数 MY_SESSION_POST_NAME は あらかじめ bootstrap.php あたりで define しておきます。POST か GET に MY_SESSION_POST_NAME が含まれていたら、値が妥当かチェックして session_id() を設定します。POST だけで良いなら $_GET の if 文は削除してください。MY_CAKE_NO_COOKIE を define します(セッション初期化時に使います)。

また、Session Fixation 対策として、リクエストの値で session_id を生成したら session_regenerate_id() します。具体的には beforeFilter() の最初に $this->Session->renew() を実行します。

CakeSession クラスの初期化をカスタマイズして、クッキー使用を切り替える

CakePHP のセッションまわりをカスタマイズする の方法でセッションをカスタマイズします。MY_CAKE_NO_COOKIE が定義されていたら use_cookies を 0 にします。

<?php
if (!isset($_SESSION)) {
    if (function_exists('ini_set')) {
        ini_set('session.use_trans_sid', 0);
        ini_set('url_rewriter.tags', '');
        ini_set('session.serialize_handler', 'php');
        //クッキーの設定
        if(defined('MY_CAKE_NO_COOKIE')){
            ini_set('session.use_cookies', 0);
        }else{
            ini_set('session.use_cookies', 1);
        }
        //おまけ:クッキー名を切り替えたい場合こんな感じ
        if(defined('MY_CAKE_SESSION_COOKIE')){
            ini_set('session.name', MY_CAKE_SESSION_COOKIE);
        }else{
            ini_set('session.name', CAKE_SESSION_COOKIE);
        }
        ini_set('session.cookie_lifetime', $this->cookieLifeTime);
        ini_set('session.cookie_path', $this->path);
        ini_set('session.gc_probability', 1);
        ini_set('session.auto_start', 0);
        ini_set('session.save_path', TMP . 'sessions'); //cake
    }
}
?>

フォームやリンクに session_id を仕込む

最後に view に組み込みます。form には hidden でこんな感じに。面倒ならば HtmlHelper の formTag() を拡張した Helper を作ってみるのも良いかもしれません。

<input type="hidden" name="<?php echo MY_SESSION_POST_NAME; ?>" value="<?php echo session_id(); ?>">

#07#07 2007/02/01 22:57 神速レス感謝です!
これで、携帯対応の調査ができます m( __ __ )m
ただ、携帯対応になるとコントローラを携帯用にしないとダメなのかなぁ、思ったり。
実装の最終目標は、IPアドレス見てViewとセッション管理を変更して文字コードをSJISで変換するってことを1コントローラでまとめられたら最高なんですけど、、、なかなか、手強そうですね。無難にやるにはコントローラ部分をうまく分割することでしょうか。
携帯対応の続報がありましたら、また宜しくお願い致します。
今回は、本当にありがとうございましたw

hetimahetima 2007/02/02 00:40 今回必要だったのは携帯専用のページだったので、振り分け等は考慮してませんでした。beforeFilter() で IP アドレスを調べて携帯以外なら403ページを吐いてexitという仕様です。
両対応の案件が来たらまた考えますw

#07#07 2007/02/02 09:01 おお、ご回答ありがとうございます。
両対応するってのは欲張りなんしょうねぇ、、、
実質、Web+3キャリア分ですからね。
GREEさんの勉強会資料で携帯キャリアの対応方法とか見ても厳しいのですね。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト

コメントを書くには、なぞなぞ認証に回答する必要があります。