PHP学生选课系统提交动态复选框值时如何与数据库比对防重复
学生选课系统重复选课校验逻辑修复方案
现有代码核心问题
- 逐课程边校验边插入:校验到重复课程前,无重复的课程已经被写入数据库,无法拦截整次提交
- 跳转后未终止执行:调用
header()跳转后没有追加exit/die语句,后续代码仍会继续执行 - 单课程重复查询性能损耗:每次遍历都单独查询已选课程和课程基础信息,选课数量大时数据库压力高
- 单课程插入即跳转:第一门课插入成功就直接跳转,剩余选中的课程不会被写入
修复后提交处理代码
<?php // 表单提交处理逻辑 if (isset($_POST['submit'])) { // 校验是否选中课程 if (!isset($_POST['inChk']) || empty($_POST['inChk'])) { header('location: cos_reg.php?data=empty'); exit; } $selectedCourses = $_POST['inChk']; $userRegNo = $_SESSION['regno']; // 1. 一次性查询当前用户所有已选课程存入数组 $existCourses = []; $checkSql = "SELECT CourseCode FROM cregtbl WHERE RegNo = ?"; if ($stmt = $con->prepare($checkSql)) { $stmt->bind_param("s", $userRegNo); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { $existCourses[] = $row['CourseCode']; } $stmt->close(); } // 2. 全量校验所有选中课程是否重复 $duplicateList = []; foreach ($selectedCourses as $courseCode) { if (in_array($courseCode, $existCourses)) { $duplicateList[] = $courseCode; } } // 存在重复直接拦截整次提交,跳转提示 if (!empty($duplicateList)) { // 如需展示具体重复课程,可将$duplicateList拼接至URL参数 header('location: cos_reg.php?msg=duplicate'); exit; } // 3. 批量查询所有选中课程的基础信息 $courseBaseInfo = []; $placeholder = rtrim(str_repeat('?,', count($selectedCourses)), ','); $paramType = str_repeat('s', count($selectedCourses)); $courseSql = "SELECT CourseCode, CourseTitle, CreditUnit, Status FROM admintbl WHERE CourseCode IN ($placeholder)"; if ($stmt = $con->prepare($courseSql)) { $stmt->bind_param($paramType, ...$selectedCourses); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { $courseBaseInfo[$row['CourseCode']] = $row; } $stmt->close(); } // 4. 所有校验通过后统一插入选课数据 $insertStatus = true; $insertSql = "INSERT INTO cregtbl(StudentName, Email, RegNo, Level, Department, Semester, Reg_Date, CourseCode, CourseTitle, CreditUnit, Status) VALUES (?,?,?,?,?,?,?,?,?,?,?)"; $stmt = $con->prepare($insertSql); foreach ($selectedCourses as $code) { // 过滤非法课程编码 if (!isset($courseBaseInfo[$code])) continue; $info = $courseBaseInfo[$code]; $stmt->bind_param( "sssssssssss", $_SESSION['name'], $_SESSION['email'], $userRegNo, $_SESSION['level'], $_SESSION['dept'], $_SESSION['semester'], $rdate, $info['CourseCode'], $info['CourseTitle'], $info['CreditUnit'], $info['Status'] ); if (!$stmt->execute()) { $insertStatus = false; break; } } $stmt->close(); // 最终结果跳转 if ($insertStatus) { header('location: cos_reg.php?msg3=registered'); } else { header('location: cos_reg.php?msg=insert_fail&err=' . urlencode($con->error)); } exit; } ?>
逻辑优化说明
- 全量前置校验:所有选课校验通过后才执行写入,只要存在重复就直接拦截整次提交,不会出现部分写入的问题
- 降低数据库压力:将逐次查询改为批量查询,数据库交互次数从2*N次降低为3次,性能提升明显
- 强制终止执行:所有
header跳转后追加exit语句,避免后续代码意外执行 - 兼容原有逻辑:保留原有的跳转参数标识,无需修改前端提示相关代码
内容的提问来源于stack exchange,提问作者Ndongesit Edet
相关产品推荐
相关产品推荐

