本文目录导读:

我来为你详细介绍如何实现一个PHP选课系统,我会从基础架构开始,逐步实现核心功能。
系统架构设计
数据库表结构
-- 学生表
CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
student_no VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
major VARCHAR(100),
grade VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 课程表
CREATE TABLE courses (
id INT PRIMARY KEY AUTO_INCREMENT,
course_no VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
teacher VARCHAR(50),
credit DECIMAL(2,1),
max_students INT DEFAULT 50,
enrolled INT DEFAULT 0,
schedule VARCHAR(200), -- 上课时间
classroom VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 选课记录表
CREATE TABLE enrollments (
id INT PRIMARY KEY AUTO_INCREMENT,
student_id INT,
course_id INT,
enroll_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status ENUM('active', 'dropped') DEFAULT 'active',
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id),
UNIQUE KEY unique_enrollment (student_id, course_id, status)
);
-- 管理员表
CREATE TABLE admins (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL
);
目录结构
course-selection-system/
├── config/
│ └── database.php
├── includes/
│ ├── auth.php
│ ├── functions.php
│ └── session.php
├── css/
│ └── style.css
├── student/
│ ├── login.php
│ ├── dashboard.php
│ ├── course-list.php
│ ├── select-course.php
│ └── my-courses.php
├── admin/
│ ├── login.php
│ ├── dashboard.php
│ ├── manage-courses.php
│ ├── add-course.php
│ └── manage-students.php
└── index.php
核心代码实现
数据库配置文件
<?php
// config/database.php
class Database {
private $host = 'localhost';
private $db_name = 'course_selection';
private $username = 'root';
private $password = '';
private $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host={$this->host};dbname={$this->db_name}",
$this->username,
$this->password
);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->exec("set names utf8");
} catch(PDOException $e) {
echo "数据库连接错误: " . $e->getMessage();
}
return $this->conn;
}
}
?>
会话管理类
<?php
// includes/session.php
class Session {
public static function start() {
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
}
public static function set($key, $value) {
$_SESSION[$key] = $value;
}
public static function get($key) {
return $_SESSION[$key] ?? null;
}
public static function destroy() {
session_destroy();
}
public static function isLoggedIn() {
return isset($_SESSION['user_id']);
}
public static function getUserType() {
return $_SESSION['user_type'] ?? null;
}
}
?>
认证功能
<?php
// includes/auth.php
require_once 'session.php';
require_once '../config/database.php';
class Auth {
private $db;
public function __construct() {
$database = new Database();
$this->db = $database->getConnection();
Session::start();
}
// 学生登录
public function studentLogin($student_no, $password) {
$sql = "SELECT * FROM students WHERE student_no = :student_no";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':student_no', $student_no);
$stmt->execute();
$student = $stmt->fetch(PDO::FETCH_ASSOC);
if ($student && password_verify($password, $student['password'])) {
Session::set('user_id', $student['id']);
Session::set('user_type', 'student');
Session::set('user_name', $student['name']);
Session::set('student_no', $student['student_no']);
return true;
}
return false;
}
// 管理员登录
public function adminLogin($username, $password) {
$sql = "SELECT * FROM admins WHERE username = :username";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':username', $username);
$stmt->execute();
$admin = $stmt->fetch(PDO::FETCH_ASSOC);
if ($admin && password_verify($password, $admin['password'])) {
Session::set('user_id', $admin['id']);
Session::set('user_type', 'admin');
Session::set('user_name', $admin['username']);
return true;
}
return false;
}
// 登出
public function logout() {
Session::destroy();
header('Location: ../index.php');
exit();
}
// 验证登录状态
public static function requireLogin() {
Session::start();
if (!Session::isLoggedIn()) {
header('Location: ../index.php');
exit();
}
}
}
?>
学生端功能
课程列表页面
<?php
// student/course-list.php
require_once '../includes/auth.php';
Auth::requireLogin();
$database = new Database();
$db = $database->getConnection();
// 获取当前学生信息
$student_id = Session::get('user_id');
// 获取学生已选课程ID
$sql_enrolled = "SELECT course_id FROM enrollments WHERE student_id = :student_id AND status = 'active'";
$stmt_enrolled = $db->prepare($sql_enrolled);
$stmt_enrolled->bindParam(':student_id', $student_id);
$stmt_enrolled->execute();
$enrolled_courses = $stmt_enrolled->fetchAll(PDO::FETCH_COLUMN);
// 课程筛选
$where = [];
$params = [];
if (isset($_GET['keyword']) && !empty($_GET['keyword'])) {
$where[] = "(c.name LIKE :keyword OR c.teacher LIKE :keyword OR c.course_no LIKE :keyword)";
$params[':keyword'] = '%' . $_GET['keyword'] . '%';
}
$where_clause = $where ? 'WHERE ' . implode(' AND ', $where) : '';
// 获取课程列表
$sql = "SELECT c.*,
(c.max_students - c.enrolled) as available_seats
FROM courses c
{$where_clause}
ORDER BY c.course_no";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$courses = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head>课程列表</title>
<link rel="stylesheet" href="../css/style.css">
</head>
<body>
<div class="header">
<h1>选课系统 - 课程列表</h1>
<div class="user-info">
欢迎, <?php echo Session::get('user_name'); ?> |
<a href="my-courses.php">我的课程</a> |
<a href="logout.php">退出</a>
</div>
</div>
<div class="search-form">
<form method="GET" action="">
<input type="text" name="keyword" placeholder="搜索课程名称/教师/课程编号"
value="<?php echo $_GET['keyword'] ?? ''; ?>">
<button type="submit">搜索</button>
</form>
</div>
<div class="course-grid">
<?php foreach ($courses as $course): ?>
<div class="course-card">
<h3><?php echo htmlspecialchars($course['name']); ?></h3>
<p class="course-no">编号:<?php echo $course['course_no']; ?></p>
<p class="teacher">教师:<?php echo htmlspecialchars($course['teacher']); ?></p>
<p class="credit">学分:<?php echo $course['credit']; ?></p>
<p class="schedule">时间:<?php echo $course['schedule']; ?></p>
<p class="capacity">
已选:<?php echo $course['enrolled']; ?>/<?php echo $course['max_students']; ?>
<span class="available">(可退:<?php echo $course['available_seats']; ?>)</span>
</p>
<?php if (in_array($course['id'], $enrolled_courses)): ?>
<button class="btn btn-warning" disabled>已选</button>
<a href="drop-course.php?id=<?php echo $course['id']; ?>"
class="btn btn-danger"
onclick="return confirm('确定退选该课程?')">退选</a>
<?php elseif ($course['available_seats'] > 0): ?>
<a href="select-course.php?id=<?php echo $course['id']; ?>"
class="btn btn-primary"
onclick="return confirm('确定选择该课程?')">选课</a>
<?php else: ?>
<button class="btn btn-secondary" disabled>已满</button>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</body>
</html>
选课功能
<?php
// student/select-course.php
require_once '../includes/auth.php';
Auth::requireLogin();
$database = new Database();
$db = $database->getConnection();
$student_id = Session::get('user_id');
$course_id = $_GET['id'] ?? 0;
try {
// 开始事务
$db->beginTransaction();
// 检查课程是否存在且有剩余名额
$sql = "SELECT * FROM courses WHERE id = :course_id FOR UPDATE";
$stmt = $db->prepare($sql);
$stmt->bindParam(':course_id', $course_id);
$stmt->execute();
$course = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$course) {
throw new Exception("课程不存在");
}
if ($course['enrolled'] >= $course['max_students']) {
throw new Exception("课程已满");
}
// 检查是否已经选过该课程
$sql = "SELECT id FROM enrollments
WHERE student_id = :student_id
AND course_id = :course_id
AND status = 'active'";
$stmt = $db->prepare($sql);
$stmt->bindParam(':student_id', $student_id);
$stmt->bindParam(':course_id', $course_id);
$stmt->execute();
if ($stmt->rowCount() > 0) {
throw new Exception("您已选择该课程");
}
// 添加选课记录
$sql = "INSERT INTO enrollments (student_id, course_id, status)
VALUES (:student_id, :course_id, 'active')";
$stmt = $db->prepare($sql);
$stmt->bindParam(':student_id', $student_id);
$stmt->bindParam(':course_id', $course_id);
$stmt->execute();
// 更新课程已选人数
$sql = "UPDATE courses SET enrolled = enrolled + 1 WHERE id = :course_id";
$stmt = $db->prepare($sql);
$stmt->bindParam(':course_id', $course_id);
$stmt->execute();
// 提交事务
$db->commit();
$_SESSION['success'] = "选课成功!";
header("Location: course-list.php");
} catch (Exception $e) {
// 回滚事务
$db->rollBack();
$_SESSION['error'] = $e->getMessage();
header("Location: course-list.php");
}
?>
我的课程页面
<?php
// student/my-courses.php
require_once '../includes/auth.php';
Auth::requireLogin();
$database = new Database();
$db = $database->getConnection();
$student_id = Session::get('user_id');
// 获取学生已选课程
$sql = "SELECT c.*, e.enroll_time, e.id as enrollment_id
FROM enrollments e
JOIN courses c ON e.course_id = c.id
WHERE e.student_id = :student_id
AND e.status = 'active'
ORDER BY e.enroll_time DESC";
$stmt = $db->prepare($sql);
$stmt->bindParam(':student_id', $student_id);
$stmt->execute();
$my_courses = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 计算总学分
$total_credits = array_sum(array_column($my_courses, 'credit'));
?>
<!DOCTYPE html>
<html>
<head>我的课程</title>
<link rel="stylesheet" href="../css/style.css">
</head>
<body>
<div class="header">
<h1>我的课程</h1>
<div class="user-info">
欢迎, <?php echo Session::get('user_name'); ?> |
<a href="course-list.php">课程列表</a> |
<a href="logout.php">退出</a>
</div>
</div>
<div class="summary">
<p>已选课程:<?php echo count($my_courses); ?> 门</p>
<p>总学分:<?php echo $total_credits; ?></p>
</div>
<?php if (count($my_courses) > 0): ?>
<table class="course-table">
<thead>
<tr>
<th>课程编号</th>
<th>课程名称</th>
<th>教师</th>
<th>学分</th>
<th>上课时间</th>
<th>选课时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($my_courses as $course): ?>
<tr>
<td><?php echo $course['course_no']; ?></td>
<td><?php echo htmlspecialchars($course['name']); ?></td>
<td><?php echo htmlspecialchars($course['teacher']); ?></td>
<td><?php echo $course['credit']; ?></td>
<td><?php echo $course['schedule']; ?></td>
<td><?php echo $course['enroll_time']; ?></td>
<td>
<a href="drop-course.php?id=<?php echo $course['id']; ?>"
class="btn btn-danger btn-sm"
onclick="return confirm('确定退选该课程?')">退选</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<div class="empty-message">
<p>您还没有选择任何课程</p>
<a href="course-list.php" class="btn btn-primary">浏览课程</a>
</div>
<?php endif; ?>
</body>
</html>
管理端功能
课程管理
<?php
// admin/manage-courses.php
require_once '../includes/auth.php';
Auth::requireLogin();
if (Session::getUserType() !== 'admin') {
header('Location: ../index.php');
exit();
}
$database = new Database();
$db = $database->getConnection();
// 处理添加课程
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'add') {
try {
$sql = "INSERT INTO courses (course_no, name, teacher, credit, max_students, schedule, classroom)
VALUES (:course_no, :name, :teacher, :credit, :max_students, :schedule, :classroom)";
$stmt = $db->prepare($sql);
$stmt->execute([
':course_no' => $_POST['course_no'],
':name' => $_POST['name'],
':teacher' => $_POST['teacher'],
':credit' => $_POST['credit'],
':max_students' => $_POST['max_students'],
':schedule' => $_POST['schedule'],
':classroom' => $_POST['classroom']
]);
$_SESSION['success'] = "课程添加成功!";
} catch (Exception $e) {
$_SESSION['error'] = "添加失败:" . $e->getMessage();
}
}
}
// 获取所有课程
$sql = "SELECT * FROM courses ORDER BY course_no";
$stmt = $db->query($sql);
$courses = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head>课程管理</title>
<link rel="stylesheet" href="../css/style.css">
</head>
<body>
<div class="header">
<h1>课程管理</h1>
<div class="user-info">
管理员: <?php echo Session::get('user_name'); ?> |
<a href="dashboard.php">管理首页</a> |
<a href="logout.php">退出</a>
</div>
</div>
<!-- 添加课程表单 -->
<div class="add-course-form">
<h2>添加新课程</h2>
<form method="POST" action="">
<input type="hidden" name="action" value="add">
<div class="form-group">
<label>课程编号:</label>
<input type="text" name="course_no" required>
</div>
<div class="form-group">
<label>课程名称:</label>
<input type="text" name="name" required>
</div>
<div class="form-group">
<label>授课教师:</label>
<input type="text" name="teacher" required>
</div>
<div class="form-group">
<label>学分:</label>
<input type="number" name="credit" step="0.5" required>
</div>
<div class="form-group">
<label>容量:</label>
<input type="number" name="max_students" value="50" required>
</div>
<div class="form-group">
<label>上课时间:</label>
<input type="text" name="schedule" placeholder="如:周一 1-2节" required>
</div>
<div class="form-group">
<label>教室:</label>
<input type="text" name="classroom" required>
</div>
<button type="submit" class="btn btn-primary">添加课程</button>
</form>
</div>
<!-- 课程列表 -->
<div class="course-list">
<h2>已开设课程</h2>
<table class="data-table">
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>教师</th>
<th>学分</th>
<th>容量</th>
<th>已选</th>
<th>时间</th>
<th>教室</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($courses as $course): ?>
<tr>
<td><?php echo $course['course_no']; ?></td>
<td><?php echo htmlspecialchars($course['name']); ?></td>
<td><?php echo htmlspecialchars($course['teacher']); ?></td>
<td><?php echo $course['credit']; ?></td>
<td><?php echo $course['max_students']; ?></td>
<td><?php echo $course['enrolled']; ?></td>
<td><?php echo $course['schedule']; ?></td>
<td><?php echo $course['classroom']; ?></td>
<td>
<a href="edit-course.php?id=<?php echo $course['id']; ?>"
class="btn btn-sm btn-info">编辑</a>
<a href="delete-course.php?id=<?php echo $course['id']; ?>"
class="btn btn-sm btn-danger"
onclick="return confirm('确定删除该课程?')">删除</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</body>
</html>
安全考虑和优化建议
安全措施
// 防止SQL注入 - 使用预处理语句
// 防止XSS攻击 - 使用htmlspecialchars()
// 防止CSRF攻击 - 添加Token验证
// 密码加密 - 使用password_hash()和password_verify()
// CSRF Token生成和验证
function generateCSRFToken() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verifyCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
性能优化
// 数据库索引优化 ALTER TABLE enrollments ADD INDEX idx_student_course (student_id, course_id, status); ALTER TABLE courses ADD INDEX idx_course_no (course_no); // 使用缓存 // 可以缓存热门课程列表,减少数据库查询
验证规则
// 选课时间限制
function isWithinSelectionPeriod() {
$start_time = strtotime('2024-09-01 08:00:00');
$end_time = strtotime('2024-09-15 18:00:00');
$now = time();
return $now >= $start_time && $now <= $end_time;
}
// 最大选课数量限制
function canSelectMoreCourses($student_id, $max_courses = 6) {
// 查询学生当前选课数量
// 比较是否超过最大限制
}
部署建议
-
环境要求
- PHP 7.4+
- MySQL 5.7+
- Apache/Nginx
-
配置文件
- 将数据库配置信息放在单独的配置文件中
- 设置错误报告级别
- 配置时区
-
初始数据
- 创建管理员账号
- 导入测试数据
这个选课系统包含了基本的选课功能,你可以根据实际需求进行扩展,比如添加课程冲突检测、选课优先级、退课审核等功能。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播