PHP登录模块异常:封禁用户登录显示登录失败而非封禁提示
问题排查
你的登录系统之所以在账号被封禁时输出登录失败提示,而非你期望的封禁提示,主要是这几个逻辑问题导致的:
- 冗余且无效的判断:外层已经通过
$countLogin == 1确认了账号密码匹配,内部又重复做了一次同样的判断,导致你写在内部else里的封禁提示永远不会被执行。 - 错误的提示输出方式:当检测到封禁状态(
$status ==1)时,你用die()输出了纯文本提示,而不是你预设的带样式的alert,而且如果你的status字段值不是1(比如封禁时设置了其他值),这个逻辑直接跳过,反而走到登录成功或失败分支。 - 重复SQL查询:多次执行查询获取用户信息,不仅低效,还容易出现逻辑漏洞。
修复方案
我重构了你的登录逻辑,调整了判断顺序,优化了SQL查询,确保封禁提示能正确触发,修复后的代码如下:
<?php if (!$user->LoggedIn()) { if (isset($_POST['logINBoss'])) { $captcha = htmlspecialchars($_POST["g-recaptcha-response"]); $secret = $odb->query("SELECT `google_secret` FROM `admin` LIMIT 1")->fetchColumn(0); $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secret."&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']); $response = json_decode($response); if (!$captcha || $response->success == false) { echo '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>Invalid Captcha Code Entered!</div></center>'; } else { $username = htmlspecialchars($_POST['username']); $password = htmlspecialchars($_POST['password']); $Errors = array(); // 修正用户名长度判断,和提示文本的4-15字符保持一致 if (!ctype_alnum($username) || strlen($username) < 4 || strlen($username) > 15) { $Errors[] = '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>Username Must Be Alphanumeric And 4-15 characters in length</div></center>'; } if (empty($username) || empty($password)) { $Errors[] = '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>Fill in all fields</div></center>'; } if (empty($Errors)) { // 一次查询获取用户所有必要信息,避免重复查询 $SQLGetUser = $odb->prepare("SELECT `ID`, `username`, `password`, `status` FROM `users` WHERE `username` = :username"); $SQLGetUser->execute(array(':username' => $username)); $userInfo = $SQLGetUser->fetch(PDO::FETCH_ASSOC); if ($userInfo) { // 先验证密码正确性 if (SHA1($password) === $userInfo['password']) { // 再检查账号是否被封禁 if ($userInfo['status'] == 1) { // 获取封禁原因,处理空原因的情况 $SQLGetBanReason = $odb->prepare("SELECT `reason` FROM `bans` WHERE `username` = :username"); $SQLGetBanReason->execute(array(':username' => $username)); $banReason = $SQLGetBanReason->fetchColumn(0) ?: 'No reason specified'; // 输出你期望的带样式的封禁提示 echo '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>You are banned for Reason: ' . htmlspecialchars($banReason) . '</div></center>'; } else { // 账号正常,执行登录流程 $logAddr = $odb->prepare("INSERT INTO `loginip` (`username`,`ip`,`date`,`http_agent`) VALUES (:user, :ip, UNIX_TIMESTAMP(NOW()), :agent);"); $logAddr->execute(array( ":user" => $username, ":ip" => $_SERVER['REMOTE_ADDR'], ":agent" => $_SERVER['HTTP_USER_AGENT'] )); $_SESSION['username'] = $userInfo['username']; $_SESSION['ID'] = $userInfo['ID']; echo '<center><div class="alert alert-icon alert-success alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>You have been logged in successfully..</div></center><meta http-equiv="refresh" content="3;url=index.php">'; } } else { // 密码错误,输出登录失败 echo '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>Login Failed!!</div></center>'; } } else { // 用户名不存在,输出登录失败 echo '<center><div class="alert alert-icon alert-danger alert-dismissible fade in" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><i class="mdi mdi-check-all"></i>Login Failed!!</div></center>'; } } else { foreach($Errors as $Error) { echo $Error; } } } } } ?>
修复的核心要点
- 简化SQL查询:只执行一次查询获取用户的ID、用户名、密码和状态,减少数据库交互次数,提升效率。
- 调整判断顺序:先确认用户名存在,再验证密码,最后检查封禁状态,逻辑更清晰,避免漏洞。
- 统一提示样式:移除
die(),改用你预设的alert样式输出封禁提示,确保页面样式一致性。 - 修复细节错误:修正了用户名长度判断的逻辑(原来的
<1改为<4),和提示文本的4-15字符要求保持一致。 - 兼容空封禁原因:如果封禁时未填写原因,默认显示"No reason specified",避免页面出现空白内容。
内容的提问来源于stack exchange,提问作者Immense
相关产品推荐
相关产品推荐

