[ トップ | 一覧 | 更新履歴 ]

Apache::Session.pm

GzuGzuBug | PerlPackageModules | CGI::Session.pm

セッションの永続化

Apache::Session

CGI::Session.pmというのもある。

俺的説明だと「プログラムが終了してもObjectを保持し続ける仕組み」です。再度、プログラムを起動したときに、保存しておいたObjectを取得することができます。 これまたセッションごとのデータを保持してもらう以外にも使い道がありそうですが。

特にCGIプログラムは、1ページ(HTML)を出力するごとに起動、終了してしまうので、各ページ間で、もっと広げると、ユーザが画面遷移する機能全体でObjectをサーバが持っていることができれ ば、余計なパラメータの受け渡しを減らすことができます。

大きな機能を上げると、

使ってみる

sessionを保存、復元するのにDB(あるいはエミュレーション)を使ってます。(複数の方法があります) web上でユーザが画面遷移していきますが、CGIは1画面ごと(1キックごと)にprogramが 起動され処理後に終了してしまうために、前後のCGIへ情報を渡すには、(1)URLパラメータ をずーーーーと渡し続けるか、 (2)cookieに入れてしまうか、(3)session管理を使うかという選択があります。

強引に分類すると、

簡単なCGIで画面遷移が10程度なら(1)でもいいか。 cookieに保存してもらうやり方が(2)。 画面遷移が多く、URLで渡すパラメータを一定量に抑えたいのと一元管理したいなら(3)かな。 sessionのIDだけをcookieに入れることにすれば、 URLのパラメータがすっきりするので(2)を併用して(3)で すべて保存するやり方をとるサイトが多いと思います。 自分の場合、ブラウザはcookie offにしてるのと、 1ブラウザ 1セッションになってしまって、複数画面開くと問題ありになる可能性あり。 セッションはサーバで管理し、session IDをcookieに入れるのが一番多い選択だとは 思いますが、 自分の趣味で、session idはURパラメータで画面間で引き渡し、 他は sessionをサーバで管理する方法をとります。 じゃあ、Apache::Sessionをどう使うのでしょうか。 セッションの保存の仕方が何種類かあります。ファイルに保存する方法や、DBに保存する方法があります。 DBはpostgreSQLを使ってるので、これに保存する方法を選びました。 なので、DBI.pm, DBD::Pg.pmが必須。Digest::MD5.pmも使う。

DBに"sessions"というテーブルを作ります。

    CREATE TABLE sessions(
        id          varchar(32) NOT NULL PRIMARY KEY,
        a_session   text        NOT NULL
    );

しかしながら、Session.pmを使うとセッションがcreateされるたびに、データがどんどん増えていきます。 なので、古いセッションを削除する仕組みは自前で用意しなければなりません。 セッションが参照されたときにそ の時刻を入れるカラムを追加します。 必ずマニュアルどおりに作らなければならないわけでなく、上の2カラムに対して アクセスするから2カラムは必 須である、ってだけなので...

    CREATE TABLE sessions(
        id          varchar(32) NOT NULL PRIMARY KEY,
        a_session   text        NOT NULL,
        -- 追加したよ
        date_ref    timestamp   DEFAULT now()
    );

Apache::Session.pmにより、新規に行が追加されたときはnow() ファンクションが 呼ばれ現在時刻が入りま す。 そして、セッションを参照したときは、自前のコードでこのdate_refを現在時刻に 行をupdateします。 そして、一定時刻を過ぎたセッション情報をdelete削除するバッチを作り、 cron -eに登録して、一定周期で実 行してもらいます。 trigger使ってfunctionを呼び出そうかと思ったけど、参照だけ(Selectだけ)の ときも時刻をUpdateしたいの で、このやり方にしました。 これで、なんとか古いsession情報でDBがいっぱいになることを防ぎます。 同じようにpostgreSQLを使ってるならvacuumもcronに登録したいところです。 (Apache::Sessionのコードを読んで、継承できるなら継承して、updateしてるところ にコードを追加するのも いいですが。やりません)

開発システム側では、 session idに対応する情報がなかったら、タイムアウトしたか、不正な画面遷移をしたこと をユーザに伝え、ログイン画面に戻る、なんて処理が必要になります。

準備が出来たところでセッションを新たに作るのとセッションを復元する方法を書きます。

セッションを作る

ユーザがログインしたときなどに、セッションを作ります。ユーザIDとか、 セッションに入れておきたい情報 を登録します。 Apache::Sessionのmanualのsampleどおりですが、DBに接続済みのとき、

    eval{
        tie %session, 'Apache::Session::Postgres',
        undef, { Handle => $dbh, Commit => 0 }
    };
    return -1 if $@;

tieがエラー時にprogramが止まってしまわないようにevalで囲んで、後の $@に何か入っていたらエラーハンド リングします。 $dbhは、DBI接続したときのハンドラです。 tieした変数%sessionをuntieするまで%sessionに操作、設定した値が、 セッションに(DBに)保存されます。 tie時に$session{_session_id}にKeyが設定されます。後にセッションを復元する ときに、この値をKeyとし て呼び出します。

    $sid = $session{_session_id};
    $session{user_id}   = $user_id;
    $session{user_name} = $user_name;
    untie %session;

Commitは、untieしたとき、あるいはdeleteメソッドを呼び出したときに、$dbhに対し、 commitメソッド を呼び出すかどうかのフラグです。 新しく作ったセッションをDBに登録しなければならないので、 DBエラーなどの致命的エラーがない限り、DB 切断前にはcommitしなければなりません。 新しく作ったとき(tieの3番目に何も指定しない=undefのとき)は Commit=>1が無難ですが、 このtieを行う前にDBに対してどんな操作を行ったか、その後どのような操作を行 うのか、不正時にどこまでrollbackするのか、 これらのことを考え、処理順番を考えて、このcommitにどのよ うな値を入れるか考え なさい、とmanualには載ってますので、よーーーく考えましょう。

セッションを復元する

セッションを作った画面から、次の画面へ遷移していくとき、session id(Key)だけを 引き継げば、設定した パラメータが引き継げます。 そのsession idからパラメータを復元する方法です。 session idが$sidに入っているとすると、

    eval{
        tie %session, 'Apache::Session::Postgres',
        $sid, { Handle => $dbh, Commit => 0 }
    };
    return -1 if $@;

新しく作ったときにundefを渡していたところにKeyとなる文字列を渡します。 ここでは$sidです。

    $user_id   = $session{user_id};
    $user_name = $session{user_name};
    untie %session;

参照だけならCommit=>0で充分です。 ただし、

    $session{user_name} = $modify_name;
    $session{user_pass} = $new_pass;
    untie %session;

同じセッションのデータを書き換えたり、新しいパラメータを追加した場合、 ここでCommit=>1にするか、後 から$dbh->commit();を呼び出すかは、 新しいセッションを作るところで説明したように、設計者の判断によ ります。

セッションを削除する

すでにtieされた%sessionに対し、

    tied(%session)->delete();

新しくセッションを作って(新しいsession idが欲しいとき)データをそのまま移し替 えたいときなどに、古いセッ ション を明示的に(というか明示的に削除しないと削除されないが)削除します。

セッションの参照時の参照時刻Update

date_refカラムを追加したときは、参照が起こるたびにこのカラムをUpdateしなければ なりません。

実際の実装では、tieしたり、パラメータが多いので、自分で使いやすいように class(package)でラッピングして 使ってます。Apache::Session.pmに限らないが) cleate,restore,destoryとかのmethodを作ってしまってます。

セッションがありがたいとき

自分がセッションがあってよかったと思うときは、 典型的な入力から設定完了までの画面遷移を扱うときです。

    入力画面 -- CGI.1 --> 確認画面 -- CGI.2 --> 完了画面

CGI.1で入力したデータの値チェックをして、データを表示します。

CGI.2で入力したデータをDBに登録し、完了画面表示します。 セッションを使わないと、入力画面で入力項目が多いとき、 CGI.1からCGI.2にURL経由でパラメータを渡さ なければなりません。 あるいは、temp用のテーブルを作ってCGI.1で一時保管し、CGI.2でそのテーブルから 読み込んで一時テーブ ルから本番のテーブルに移すということになります。 (同じテーブルでフラグのカラムを付けてもいいが) セッションを使うことにより、画面遷移上のデータはセッションに持たせ、一時保管してもらって、経過のデータ の流れと実際にDBに保存する流れを分離できます。


GzuGzu (WikiWikiWeb descendant) ver 1.00 pre2
このページはGzuGzuで作成されました.
yaino.com