しかしこのセッション管理、複数の画面遷移やサーバーとクライアントで色々とやることがあるので、
行き当たりばったりやってみたらとんでもないスパゲッティができ上がってしまった。
これはもはや人様に見せていいプログラムではないと判断し、いったん作ったプログラムを捨てて基盤から作ることにする。
まずはディレクトリ構成から。
今回作ったのは"←"で説明があるもの
├cgi-bin
│ testLOGIN5.cgi
│ testOK2.cgi
│
├─CMN
│ │ CMN.pm
│ │ CMN_config.xml
│ │
│ ├─ACMN ←アプリケーション共通という意味のディレクトリを作成
│ │ ACMN.pm ←これ
│ │
│ └─DCMN
│ DCMN.pm
│
└─tmp ←ワーク的なやつ
└─session ←セッションファイル置き場
では作成したACMN.pmを示そうか
・・・と言ってもいきなり全部貼り付けても「うわぁぁぁ」てなるのでまずはセッション作成部分だけを示す。
#!"C:\Perl64\bin\perl.exe"
package CMN::ACMN::ACMN;
use CGI;
use CGI::Session '-ip_match';
use lib './CMN';
use CMN::CMN;
our $XmlPath = './CMN/CMN_config.xml';
sub new {
return bless {} ;
}
#セッションの作成
#in1 :データセット名 (未設定を想定)
#in2 :セッションID (未設定を想定)
#in3 :セッション情報の作成DIR (未設定を想定)
#in4 :セッション有効期限 (未設定を想定)
#out1:作成したセッションID
sub ACMN_createSession{
$Xml = CMN::CMN->new();
my $class = shift;
my %args = (Dsn => undef,
Sid => undef,
Dir => $Xml->CMN_getXmlElement(Xml => $XmlPath, Node => 'ACMN/Session/Dir'),
Exp => $Xml->CMN_getXmlElement(Xml => $XmlPath, Node => 'ACMN/Session/Expire'),
@_);
my $args = \%args;
#セッションの作成
$session = CGI::Session->new($args{Dsn},
$args{Sid},
{Directory=>$args{Dir}}
);
#セッション有効期限の設定
$session->expire($args{Exp});
#サーバーへの書き込み
$session->flush();
#セッションIDを返す
return $session->id;
}
1;
柄にもなくコメントを書いたりしているが、これはアレである。
もうそろそろ見ただけでわかるソース書くのが限界に来てしまったのだ。
スクリプト言語でコメントを入れることは実行速度に響きそうなので嫌だったのだが、仕方がないのだ。許してくれ
まず冒頭の
use CGI::Session '-ip_match';
でCGI::Sessionをインポート。
後ろについているのはip_matchスイッチと呼ばれるもので、
これをつけると、セッションファイルを検索する際に、”今処理を要求してきたIPの”セッションファイルを探すようになり、セキュリティがほんのりアップする。ほんのりね
セッションファイルについては後述するのでちょっと待って。
次にセッション作成するACMN_createSessionを見よう。
なんかいろいろ引数があるが、基本的には引数なしで呼ばれることを想定。
デフォルト値は全部undefにしたいところだが、Dir (セッションファイル置き場)とExp(有効期限)はそういうわけにもいかなかったので初期値を設定。
ああ言い忘れたけど初期値を書いておいたCMN_config.xmlは↓こんなふうに追記
<?xml version="1.0" encoding="UTF-8"?>
<CMN>
<DCMN>
<DataBase>
<DataSource>DBI:mysql:sato:127.0.0.1:3306</DataSource>
<DataBase>sato</DataBase>
<Pass>sato</Pass>
</DataBase>
</DCMN>
<ACMN>
<Session>
<Dir>./tmp/session</Dir>
<Expire>+10m</Expire>
</Session>
</ACMN>
</CMN>
下のほうに<ACMN>を追記。
読み込みに際して、
Dir => $Xml->CMN_getXmlElement(Xml => $XmlPath, Node => 'ACMN/Session/Dir')
のように、XMLのノードがCMNから始まってないが、これはどうやら、DOMにしたとき、ルートノードは飛ばしていることが発覚したから。
話をもどそう。
セッション作成はCGI::Session->new(データソース名,セッションID,セッションファイル置き場)
で作成する。
データソース名はundefを設定するとデフォルトでファイルになる。もちろんDBも可。
セッションIDは、何か値を与えるとそのセッションIDを探してくる。
そのIDでセッションファイル置き場を探して、有効なIDが存在したらそのセッションを返す。
見つからなかったか、undefが設定されていたら新たに作る。
セッションファイル置き場はその名の通りである。もしここがundefの場合、デフォルトがどこになっているのか知らないが、そこらへんにセッションファイルを撒き散らす結果になるので必ず設定しよう。
次の行のプログラムを見よう。
$session->expire($args{Exp});
でセッションの有効期限を設定しているが・・・この書き方はどっちかっつうとCookieの有効期限じゃないのか・・・?
まあそんなことは置いておいて、ここには’+10m’という値を設定する。意味は10分間
そこまでいったら忘れずに
$session->flush();
でサーバーにファイルを作成する。
意味は現在ストリームとかバッファにためておいたデータを実際に書き出しますよという意味。
BASICで懐かしいflushである。VisualBasicにも同名のメソッドがあるが、closeするときに勝手にやるのであんまりなじみがない。
重要なことだが、ことPerlにおいてはcloseメソッドが存在するものの、PerlDoc曰くcloseは遅いから使っちゃダメらしい。じゃあなんで作った。
最後に作成したセッションIDを返す。
この部品を作るとき、何を戻すべきか相当悩んだが、「IDがわかればじゅうぶんじゃね?」という結論に達したのでIDのみ返す。セッションのオブジェクトは返さない。
こいつを起動すると↓こんな名前のファイルが出来上がる。
cgisess_a92a3d24da3e704f5732ac6edaf67cfb
中はcsvっぽい形式になっており、
セッションIDやら最終アクセス時刻やら作成日やらIPやら何やらが平文で書いてある。
わかりやすくていいんだけど・・・
いやあセキュリティ上まずいですねえ・・・
というわけでセッションの有効判定につづく