ADOdb for PHPを使う場合session_regenerate_idをしちゃダメ

ADOdb for PHPを使う場合session_regenerate_idをしちゃダメ

ADOdb is a database abstraction library for PHPを使って$_SESSIONをコントロールする場合、session_regenerate_id()を使っちゃいけません

必ずライブラリに付属しているadodb_session_regenerate_id()を使いましょう

session_regenerate_id()をすると特定の時だけ、$_SESSIONが破棄されるという問題がおきました

ログを埋め込みまくって原因を追及したところ原因はココ

~~~
// crc32 optimization since adodb 2.1
// now we only update expiry date, thx to sebastian thom in adodb 2.32
if ($crc !== false && $crc == (strlen($oval) . crc32($oval))) {
if ($debug) {
echo ‘

Session: Only updating date – crc32 not changed

‘;
}

$expirevar = ”;
if ($expire_notify) {
$var = reset($expire_notify);
global $$var;
if (isset($$var)) {
$expirevar = $$var;
}
}

$sql = “UPDATE $table SET expiry = $expiry ,expireref=”.$conn->Param(‘0’).”, modified = $sysTimeStamp WHERE $binary sesskey = “.$conn->Param(‘1’).” AND expiry >= $sysTimeStamp”;
$rs = $conn->Execute($sql,array($expirevar,$key));
return true;
}
~~~
1プロセス中に、writeが複数呼ばれた際にsession dataに差分がなければ日付のみ更新するという内容の処理(らしい)

session_regenerate_idをした場合の動き

read(session_id_OLD) select * from session where sess_key = session_id_OLD
destroy(session_id_OLD) delete from session where sess_key = session_id_OLD
write(session_id_NEW) update session set expiry = now() where sess_key = session_id_NEW

この時、1プロセス中でsessionの中身は同じなのでwriteでは日付だけ更新する
deleteしちゃってるデータをupdateしてるしSQLのエラーが多分出ているんじゃないかな・・

と、いうわけでDB上からsessionが破棄されてしまいます、ただし$_SESSIONにはこの時点では残っているのでsessionは切れません。。
F5を押すなり、違うページを開くなりすると読み込むべきデータが消えちゃってるのでここで$_SESSIONは空になります

対処法1

adodb_session_regenerate_idを使いましょう
ちゃんと新しいsession_idでupdateをしているので大丈夫
~~~
function adodb_session_regenerate_id()
{
$conn = ADODB_Session::_conn();
if (!$conn) return false;

$old_id = session_id();
if (function_exists(‘session_regenerate_id’)) {
session_regenerate_id();
} else {
session_id(md5(uniqid(rand(), true)));
$ck = session_get_cookie_params();
setcookie(session_name(), session_id(), false, $ck[‘path’], $ck[‘domain’], $ck[‘secure’]);
//@session_start();
}
$new_id = session_id();
$ok = $conn->Execute(‘UPDATE ‘. ADODB_Session::table(). ‘ SET sesskey=’. $conn->qstr($new_id). ‘ WHERE sesskey=’.$conn->qstr($old_id));

/* it is possible that the update statement fails due to a collision */
if (!$ok) {
session_id($old_id);
if (empty($ck)) $ck = session_get_cookie_params();
setcookie(session_name(), session_id(), false, $ck[‘path’], $ck[‘domain’], $ck[‘secure’]);
return false;
}

return true;
}
~~~

対処法2

もうあちこちにsession_regenerate_id書かれちゃってて上に置き換えるのは大変…
なので丸ごとコメントアウト ○| ̄|_
~~~
// crc32 optimization since adodb 2.1
// now we only update expiry date, thx to sebastian thom in adodb 2.32
/*
if ($crc !== false && $crc == (strlen($oval) . crc32($oval))) {
if ($debug) {
echo ‘

Session: Only updating date – crc32 not changed

‘;
}

$expirevar = ”;
if ($expire_notify) {
$var = reset($expire_notify);
global $$var;
if (isset($$var)) {
$expirevar = $$var;
}
}

$sql = “UPDATE $table SET expiry = $expiry ,expireref=”.$conn->Param(‘0’).”, modified = $sysTimeStamp WHERE $binary sesskey = “.$conn->Param(‘1’).” AND expiry >= $sysTimeStamp”;
$rs = $conn->Execute($sql,array($expirevar,$key));
return true;
}
*/
~~~

多少処理は増えるけど、それほどの負荷軽減でもないので…

というわけで3日間はまった結果はこんなんでした
多分、仕様だろうからコミットも出来ないしご注意くださいませ!としかいいようがないですね