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日間はまった結果はこんなんでした
多分、仕様だろうからコミットも出来ないしご注意くださいませ!としかいいようがないですね