CodeIgniter上でデータベース利用方式でのSession使用時に、2度も3度も余計なsetcookie()を走らせないようにする。
皆様こんにちは。お久しぶりです。
今日は表題の小ネタ。(CodeIgniterの学習とは呼べないのでタイトルから外します。)
症状
以下のバグレポートの内容がCodeIgniter2.0の system/libraries/Session.phpでも直ってなさそうなので、俺俺修正コードを貼り付けておきます。参照:http://codeigniter.com/bug_tracker/bug/7358/
Description
When using session using a database every call to un/set_userdata results in a cookie being set. When using a DB the session cookie shouldn’t change when the userdata is changed. no need for another cookie being sent.
un/set_userdata calls sess_write which is where it sets the new cookie. simple fix would be to drop the $this->_set_cookie($cookie_userdata);
超俺訳:
データベース利用方式でセッションを使っているとき、
unset_userdataやset_userdataを毎回呼ぶ度に、クッキーへの書き込みが走ってるんだけど
そもそも保持したいデータはDBに入れてるのだから、unset_userdataやset_userdataしたタイミングでは
クッキー内容は何にも変わんねーよ。毎回クッキーに同じ値を書かなくてもいいじゃん。つかSet-Cookie:何回走らせてんだ。これバグだろ常考。
現状の動きを確認してみる
$config['sess_encrypt_cookie']= FALSE; で
クッキーの暗号化をしてなければ一発でわかる。
(ここでは3回setcookie()している。動かしたソースでset_userdataとかflash_dataが動いているため)
(写真赤丸内はSet-Cookie: csn=…ってなってるけど、$config['sess_cookie_name']のデフォルトだとSet-Cookie: ci_session=…)
$config['sess_encrypt_cookie']= TRUE; で
暗号化すると一見違うSet-Cookie:が走っているように見えるんだけど、
実はCI_Encryptのencodeを呼び出した時に呼ばれる_xor_encode()の中でmt_randが走っているからで復号した中身は一緒なのだ。
(確認は、$hoge=$this->CI->encrypt->decode($cookie_data); してmd5取ってvar_dump($hoge);してみれば良い。 )
修正ソース抜粋
いつもながら無保証です。
直前の$cookie_dataのmd5を保持しておいて、今回も同じだったら何もせず_set_cookie()を抜け出すって処理を入れてるだけ。
変更部分は、 //add start here 〜 //add end の間、他はオリジナルソースのSession.phpからコピーした。
あと、証拠の写真2記述のデバグ用に #$hoge=$this->CI->encrypt->decode($cookie_data); ってのをコメントアウトして入れている。
/application/libraries/MY_Session.php 内で_set_cookie()をオーバーライドする。
(MY_Session.phpが無ければ作るべし、MY_うんたらの説明はもう省略)
<?php if ( ! defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' ); class MY_Session extends CI_Session { function __construct () { parent :: __construct(); } //途中略(function _serialize()とかfunction _unserialize()とかのbugfix等々が間にある) // -------------------------------------------------------------------- /** * Write the session cookie * * @access public * @return void */ function _set_cookie($cookie_data = NULL) { if (is_null($cookie_data)) { $cookie_data = $this->userdata; } // Serialize the userdata for the cookie $cookie_data = $this->_serialize($cookie_data); //add start here //see:http://codeigniter.com/bug_tracker/bug/7358/ $cookie_md5 = md5($cookie_data); static $last_cookie_md5=''; if($last_cookie_md5 !== $cookie_md5){ $last_cookie_md5 = $cookie_md5; }else{ return; } //add end if ($this->sess_encrypt_cookie == TRUE) { $cookie_data = $this->CI->encrypt->encode($cookie_data); #debug #$hoge=$this->CI->encrypt->decode($cookie_data); #var_dump(md5($hoge)) ; } else { // if encryption is not used, we provide an md5 hash to prevent userside tampering $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); } // Set the cookie setcookie( $this->sess_cookie_name, $cookie_data, $this->sess_expiration + time(), $this->cookie_path, $this->cookie_domain, 0 ); } //下略 }//endofclass /** * End of file MY_Session.php */ /** * Location: ./application/libraries/MY_Session.php */ ?>
修正後の動きを確認してみる
$config['sess_encrypt_cookie']= FALSE;のとき
$config['sess_encrypt_cookie']= TRUE;のとき
ってなかんじで、全く同一のSet-Cookie:重複が回避された。
ではでは!