とりあえず解決?CodeIgniterのセッション有効期限
CodeIgniterでセッション有効期限をうまく扱えない問題、ひとまず解決。
実は解決したかに見えて大きな問題が残ってるのだが、とりあえず書いておく。
Sessionクラスを拡張してsess_runとsess_writeを改造した。
とりあえず、設定ファイルでsess_expirationが0のときに無期限(実際には2年)となっていた部分を、本当の0に変更(sess_run())。
さらに、実際にクッキーを書き込むsess_writeにて、セッションクラスのメンバー$sess_length(ここに設定値が保持される)が0の場合はクッキーのライフタイムをtime+2年から0に変更。
こうすることで、設定ファイルで期限を0としたときはブラウザを閉じるまで有効、となった。ひとまずOK。
残る問題は、個別のセッションごとにタイムアウトを保持できていないこと。設定ファイルを毎回読んでしまうので、いったん「このセッションの期限は2週間」などと個別に設定しても、次のページ遷移でグローバルな設定ファイルの「0」が適用されてしまう。
つまりタイムアウトをセッション固有の値としてそれぞれ保存する必要がある。これはSessionクラスの更なる改造が必要だし、下手すればセッション情報を保存しているテーブルの構造にも影響するので、また後で手をつけることにする。
CodeIgniterのセッション有効期限でつまづく
CodeIgniterのセッションが気に入らないという話を先日書いたばかりだが、しばらく放置して戻ってきたらまたつまづいてしまった。
ユーザーをログインさせるときに「次回以降パスワードを省略」できるよう、セッションの有効期限を設定しようとしたのだが…。
これまで扱ってきたPHPでの開発では、PHPネイティブのセッション関連設定項目にて有効期限を0にしておけば、ブラウザを閉じたときにセッションが切れてくれていた。有効期限を延ばしてクッキーを設定しなおせば長いライフタイムのセッションができて、それがパスワード保存、つまりログイン状態の維持ということになっていた。
CIではネイティブの関数を使用せずオリジナルのセッション管理クラスを利用している。これにももちろん有効期限の設定項目はあるのだが、0にした場合、閉じるまでではなく無期限ということになってしまう。つまりブラウザを閉じてもいつまでもログイン状態が保持されることになる。
有効期限のデフォルトは2時間になっており、2時間の間であればいったんブラウザを閉じて開きなおしても以前のセッションに復帰する。ためしに有効期限を1秒などの短い値にしてみたが、そうするとブラウザを閉じなくても有効期限切れとして扱われ、次々と新しいセッションが生成されてしまった。
デフォルトの2時間など、一回の利用の時間として想定できるほどほどの値にしておくという手もあるが、よくないだろう。なぜなら一回の利用の間でも2時間を越えればセッションが初期化されてしまうからだ。さらに、2時間を越えなかったとしてもブラウザを閉じただけでは消えず、共有のコンピュータであれば危険。要するに、一回ブラウザを開いて閉じるまでというセッション期限をどうしても使いたいわけだ。
さぁどうやって解決しようか。
できるかぎりCIのコードを残したまま、言い換えれば、自分でコードを書かずに解決したいものだが。
CodeIgniterのProfilerが便利
CodeIgniterの便利な機能を発見した。
実行時のクエリや処理時間をページに出力してくれるProfiler。
コントローラークラスの中で次の一行を書くだけで、初期化と実行にかかった時間、POSTデータ、発行されたSQLクエリをページの最後に出力してくれる。
$this->output->enable_profiler(true);
これを含めたコントローラーはたとえばこんな感じ。
class BingoBongo extends Controller{
function BingoBongo(){
parent::Controller();
}
function index(){
$this->output->enable_profiler(true);
//..残りの処理
}
}こういう機能がストレスなく使えるとテストとデバッグが大変楽になるのでありがたい。
CodeIgniterが急激にいやになってきた
新しいアプリをCodeIgniter(略してCI)で作ろうとしている。
構成が分かりやすく拡張もしやすかったのですばらしい第一印象を受けて、これならスラスラ作れそうだと思っていたが、しばらく作業をしてみると徐々に気に入らない部分が見えてきた。
ParserがSmartyじゃない
テンプレートの中で変数を使うためにいちいち< ?php ~ ?>を書いていると可読性が著しく下がるため、パフォーマンスが犠牲になるとはいえ僕としてはSmartyのようなテンプレートエンジンを使いたい。(これに関しては初めから分かっていたし独自ライブラリを作ったので今は問題ない。)
セッションをクッキーに直書きする
見たときは目を疑った。PHPのセッションデータはふつうセッションID(鍵)だけをクッキーに保存し、データ自体はサーバー側に保存するのだが、CIではシリアライズしたデータそのものをクッキーに保存していた。データベースを使うオプションもあるがそれでもデータはクッキー。従って保存できるデータ量が限られる。(これも独自ライブラリで修正したが、かなり大掛かりな作業になった。)
セッションを読み書きするメソッド名が長い
get()とset()にすればいいものを、userdata()とset_userdata()などという面倒臭いメソッド名がついているから、わざわざ自分でエイリアスを書いた。
バリデーションがダサい
ここは特に問題が多い。
まずライブラリのメソッドの中身に「$_POST」がハードコーディングされているため、任意の変数をバリデートできない。なぜこんな仕様になっているのか理解に苦しむ。柔軟性を考えると(というか何も考えなくても)普通に引数で取るしかないと思うのだが。
そして、任意のエラーをあとから手動で追加するメソッドが用意されていないから、わざわざ自分でメソッドを書くはめになる。
そして、エラーメッセージを変数で取得するとデフォルトで<p>~</p>に囲まれて来るという驚きのダサさを発揮してくれる。
そして、ルールを設定するためのコードが可読性の低いものになる。
正直、これは使い物にならない。こうしてみるとEthnaのバリデーションはよくできていたと思う。
i18nクラスを呼び出すときの名前がバラバラ
状況によってLangだったりLanguageだったりする。非常に分かりにくい。
何かを取得するメソッド名がバラバラ
クラスによって。たとえば$config->item(’key’)、$lang->line(’key’)、$session->userdata(’key’)。同じネイティブライブラリなんだから全部get()とかにしてくれ。
同じライブラリを二度呼び出すと死ぬ
たとえばバリデーションライブラリを呼び出すときは
$this->load->library('validation');となる。これ自体は大変分かりやすくていいのだが、何らかの都合でこれと同じ行が二度目に出てくると、単純にクラスの再宣言ということでエラーが出て倒れる。ものすごく簡単に防げるはずだが、それがないために場合によってはものすごく不便だ。
今のところはこんなものだがまだ増える予感がする。
さてどうしよう、ここまで手を加えたからには粘って使うべきか、それとも見切りをつけて別のフレームワークへ行くべきか…。
