PHPで一種のWebアプリを構築しています。基本的にユーザーがオンラインであることをサーバーに伝えるセッション変数にトークンを保存する方法でログインフォームがあります(これはデータベースにも保存されます)。このトークンは、ログイン フォームが表示されるとクリアされます (新しいログイン... またはログアウト時 - ここのコードには示されていません)。また、ログインの成功時に session_id() をデータベースに保存します。
2 つのセッションが (同じブラウザーまたは異なるブラウザーで) 開かれるのを防ぐために、2 種類のチェックを行います。
ユーザーがログイン後に 2 番目のタブのみを開く場合、このトークンと http リファラーを確認します。トークンが空ではなく (誰かがログインしていることを意味します)、http リファラーが空である場合 (新しいタブ/ウィンドウが開かれていることを意味します)、エラー メッセージをエコーします (「既にセッションが開いています...」)。
ログインする前にユーザーが 2 つのタブを開いている場合、このトークンと、DB および現在の DB の session_id() をチェックします。トークンがそこにあり (誰かがログインしていることを意味します)、DB と現在の session_id() が同じであれば (つまり、まだ同じブラウザーを使用していることを意味します)、エラー メッセージをエコーします (「既に開いているセッションがあります.. .")。ここで session_id() が異なる場合は、別のブラウザーを使用していることを意味し、これについてもチェックしています。
同時に、ユーザーがログインフォームを再投稿できないようにしようとしています。つまり、ログイン直後にリロードをクリックしないようにしたいのです。
問題:
上記のセットアップでは、リロードをクリックすると、トークンがそこにあり、session_id() も同じであるため、サーバーは 2 番目のブラウザー タブ ログイン (上記のケース #2) であると見なします。エラーメッセージが表示されます (「既に開いているセッションがあります...」)。
あまりにも組み合わせて、ログインフォームのリロード時に何も起こらないことを確認する方法はありますか?
コードは次のようになります (不要なコードを削除しようとしましたが、100% 正しくない場合は申し訳ありません)。
<?php function LoginForm() {
$_SESSION['token'] = ''; ?>
<form action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI'].$_SERVER['QUERY_STRING']); ?>" method="post">
Please enter your login details</div><br />
Login ID<br />
<input type="text" name="userid" /><br /><br />
Password<br />
<input type="password" name="password" /><br /><br />
<input type="submit" name="login" value="Login" />
</form>
<?php }
if (!empty($token_in_DB) AND !isset($_SERVER['HTTP_REFERER'])) {
echo "You are already logged in on another tab / window";
exit();
} elseif (isset($_POST['login'])) {
if (!empty($token_in_DB)) {
if ($session_in_DB == session_id()) {
echo "You are already logged in on another tab / window";
exit();
} else {
echo "You are already logged in on another browser / computer";
exit();
}
} elseif (/* password is ok */) {
// login
// set token session variable
// add token to db
}
} elseif (empty($_SESSION['token'])) {
LoginForm();
} ?>