PHP在线考试系统使用order by rand()时出现题目重复问题求助
解决PHP在线考试系统中
ORDER BY RAND()导致题目重复的问题 首先,咱们先拆解下你代码里的问题根源:
- 你的第二个查询是
SELECT * FROM question WHERE testid=? AND qnid=? ORDER BY RAND(),但qnid是题目的唯一标识啊!指定qnid后结果只会有一条数据,ORDER BY RAND()在这里完全没用,相当于白加。 - 题目重复的核心原因是你没有正确生成不重复的随机题ID,或者
$_SESSION['qn']没有随着答题流程更新,导致每次都加载同一道题。 - 另外,
mysql_*系列函数早就被PHP废弃了(PHP 7.0起直接移除),不仅有安全风险(比如SQL注入),还会导致兼容性问题,必须换掉。
下面给你两种靠谱的解决方案,任选其一即可:
方案一:预先生成随机题序(推荐)
考试开始时,一次性把当前试卷的所有题ID打乱顺序存入Session,之后按顺序取题,完全不会重复:
// 假设你已经用mysqli建立了数据库连接$conn session_start(); // 进入考试页面时初始化题序(只执行一次) if (!isset($_SESSION['question_order'])) { // 随机获取当前试卷的所有题ID $query = "SELECT qnid FROM question WHERE testid = ? ORDER BY RAND()"; $stmt = $conn->prepare($query); $stmt->bind_param("i", $_SESSION['testid']); $stmt->execute(); $result = $stmt->get_result(); // 把题ID存入Session数组 $_SESSION['question_order'] = []; while ($row = $result->fetch_assoc()) { $_SESSION['question_order'][] = $row['qnid']; } // 记录当前题的索引 $_SESSION['current_qn_idx'] = 0; } // 加载当前题目 if (isset($_SESSION['stdname']) && isset($_SESSION['question_order'])) { $total_qns = count($_SESSION['question_order']); if ($_SESSION['current_qn_idx'] >= $total_qns) { echo "所有题目已完成!"; exit; } // 获取当前题ID $_SESSION['qn'] = $_SESSION['question_order'][$_SESSION['current_qn_idx']]; // 查询题目详情 $query_qn = "SELECT * FROM question WHERE testid = ? AND qnid = ?"; $stmt_qn = $conn->prepare($query_qn); $stmt_qn->bind_param("ii", $_SESSION['testid'], $_SESSION['qn']); $stmt_qn->execute(); $question = $stmt_qn->get_result()->fetch_assoc(); // 查询学生已有的回答 $query_ans = "SELECT stdanswer, answered FROM studentquestion WHERE stdid = ? AND testid = ? AND qnid = ?"; $stmt_ans = $conn->prepare($query_ans); $stmt_ans->bind_param("iii", $_SESSION['stdid'], $_SESSION['testid'], $_SESSION['qn']); $stmt_ans->execute(); $student_answer = $stmt_ans->get_result()->fetch_assoc(); // 点击「下一题」时执行这句,切换到下一道题 // $_SESSION['current_qn_idx']++; }
方案二:每次随机选未答的题目
如果不想预加载所有题,每次查询时直接从学生还没答过的题里随机选一道:
// 假设你已经用mysqli建立了数据库连接$conn session_start(); if (isset($_SESSION['stdname'])) { // 随机获取一道未答的题ID $query = "SELECT q.qnid FROM question q LEFT JOIN studentquestion sq ON q.qnid = sq.qnid AND sq.stdid = ? AND sq.testid = ? WHERE q.testid = ? AND sq.qnid IS NULL // 筛选未答的题 ORDER BY RAND() LIMIT 1"; $stmt = $conn->prepare($query); $stmt->bind_param("iii", $_SESSION['stdid'], $_SESSION['testid'], $_SESSION['testid']); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); if ($row) { $_SESSION['qn'] = $row['qnid']; // 查询题目详情 $query_qn = "SELECT * FROM question WHERE testid = ? AND qnid = ?"; $stmt_qn = $conn->prepare($query_qn); $stmt_qn->bind_param("ii", $_SESSION['testid'], $_SESSION['qn']); $stmt_qn->execute(); $question = $stmt_qn->get_result()->fetch_assoc(); // 查询学生已有的回答(如果中途返回可能存在) $query_ans = "SELECT stdanswer, answered FROM studentquestion WHERE stdid = ? AND testid = ? AND qnid = ?"; $stmt_ans = $conn->prepare($query_ans); $stmt_ans->bind_param("iii", $_SESSION['stdid'], $_SESSION['testid'], $_SESSION['qn']); $stmt_ans->execute(); $student_answer = $stmt_ans->get_result()->fetch_assoc(); } else { echo "所有题目已完成!"; } }
关键注意事项
- 必须替换
mysql_*函数:上面的示例用了mysqli预处理语句,能有效防止SQL注入,同时兼容最新PHP版本。 - Session的维护:要确保Session正常开启(代码开头加
session_start()),并且考试结束后可以清空相关Session变量。 - 避免重复提交:如果是AJAX加载题目,要做好防重复提交的处理,防止同一题被多次选中。
内容的提问来源于stack exchange,提问作者Javed Ansari
相关产品推荐
相关产品推荐

