本文目录导读:

实现一个图书馆管理系统是一个经典的PHP项目,涵盖了数据库设计、CRUD操作、用户认证和权限管理等核心技能。
下面为你提供一个从零到一的完整实现方案,包括系统架构、功能模块、数据库设计和核心代码示例。
系统功能模块规划
一个基础但完整的图书馆管理系统通常包含以下模块:
- 用户管理:
- 管理员(图书管理员):负责图书上架、借出、归还、用户管理。
- 读者(普通用户):可以查询图书、查看个人借阅历史、预约书籍。
- 图书管理:
- 添加、编辑、删除图书信息(ISBN、书名、作者、出版社、分类、库存)。
- 图书分类管理。
- 借阅管理:
- 借书(扫描读者证和图书条码)。
- 还书(计算是否超期,生成罚款)。
- 借阅记录查询。
- 系统辅助功能:
- 登录与注销(Session/Cookie)。
- 分页搜索。
- 图书封面图片上传。
数据库设计(MySQL)
数据库是系统的核心,建议使用 MySQL(或 MariaDB)。
假设数据库名称为 library_db,主要表结构如下:
用户表 users
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL, -- 使用 password_hash() 存储
`email` VARCHAR(100),
`role` ENUM('admin', 'reader') NOT NULL DEFAULT 'reader', -- 角色
`status` TINYINT(1) NOT NULL DEFAULT 1, -- 1:激活, 0:禁用
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
图书分类表 categories
CREATE TABLE `categories` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL UNIQUE, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
图书信息表 books
CREATE TABLE `books` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `isbn` VARCHAR(20) NOT NULL UNIQUE, VARCHAR(255) NOT NULL, `author` VARCHAR(255), `publisher` VARCHAR(255), `category_id` INT(11), `total_quantity` INT(11) NOT NULL DEFAULT 1, -- 总库存 `available_quantity` INT(11) NOT NULL DEFAULT 1, -- 可借数量 `cover_image` VARCHAR(255), -- 封面图片路径 `description` TEXT, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), FOREIGN KEY (`category_id`) REFERENCES `categories`(`id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
借阅记录表 borrow_records
CREATE TABLE `borrow_records` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`book_id` INT(11) NOT NULL,
`borrow_date` DATE NOT NULL,
`due_date` DATE NOT NULL, -- 应还日期(通常借书日起 30 天)
`return_date` DATE DEFAULT NULL, -- 实际归还日期
`status` ENUM('borrowed', 'returned', 'overdue') DEFAULT 'borrowed',
`fine` DECIMAL(10,2) DEFAULT 0.00, -- 罚款金额
PRIMARY KEY (`id`),
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
FOREIGN KEY (`book_id`) REFERENCES `books`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
项目目录结构(推荐)
library-management/
├── config/
│ └── database.php # 数据库连接配置
├── includes/
│ ├── auth.php # 登录验证 / Session 管理
│ ├── functions.php # 公共函数库
│ └── header.php # 公共头部
├── assets/
│ ├── css/
│ ├── js/
│ └── uploads/ # 图书封面存放目录
├── public/ # 入口文件(也可将 .php 直接放根目录)
│ ├── index.php # 首页/图书列表
│ ├── login.php
│ ├── register.php
│ ├── logout.php
│ └── admin/
│ ├── dashboard.php # 管理员后台
│ ├── book_add.php
│ ├── book_edit.php
│ ├── borrow.php # 借书页面
│ └── return.php # 还书页面
└── .htaccess # URL重写(可选)
核心功能代码实现(关键片段)
数据库连接 config/database.php
<?php
$host = 'localhost';
$dbname = 'library_db';
$username = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
?>
用户登录验证 includes/auth.php
<?php
session_start();
require_once 'config/database.php';
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
function isAdmin() {
return isset($_SESSION['role']) && $_SESSION['role'] === 'admin';
}
// 登录处理逻辑(在 login.php 中使用)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = $user['role'];
header("Location: index.php");
exit;
} else {
$error = "用户名或密码错误";
}
}
?>
图书列表展示 public/index.php
<?php
require_once '../includes/auth.php';
require_once '../config/database.php';
if (!isLoggedIn()) {
header("Location: login.php");
exit;
}
// 分页和搜索
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$search = isset($_GET['search']) ? $_GET['search'] : '';
$searchCondition = '';
$params = [];
if (!empty($search)) {
$searchCondition = "WHERE b.title LIKE :search OR b.author LIKE :search2";
$params = ['search' => "%$search%", 'search2' => "%$search%"];
}
// 查询总数
$countStmt = $pdo->prepare("SELECT COUNT(*) FROM books b $searchCondition");
$countStmt->execute($params);
$totalBooks = $countStmt->fetchColumn();
$totalPages = ceil($totalBooks / $limit);
// 查询具体数据
$sql = "SELECT b.*, c.name as category_name
FROM books b
LEFT JOIN categories c ON b.category_id = c.id
$searchCondition
ORDER BY b.created_at DESC
LIMIT $limit OFFSET $offset";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$books = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head>图书列表 - 图书馆系统</title>
<link rel="stylesheet" href="../assets/css/style.css">
</head>
<body>
<?php include '../includes/header.php'; ?>
<h1>图书目录</h1>
<!-- 搜索框 -->
<form method="GET" action="">
<input type="text" name="search" placeholder="搜索书名或作者" value="<?= htmlspecialchars($search) ?>">
<button type="submit">搜索</button>
</form>
<table border="1" cellpadding="10">
<tr>
<th>ISBN</th>
<th>书名</th>
<th>作者</th>
<th>分类</th>
<th>可借数量</th>
<th>操作</th>
</tr>
<?php foreach ($books as $book): ?>
<tr>
<td><?= htmlspecialchars($book['isbn']) ?></td>
<td><?= htmlspecialchars($book['title']) ?></td>
<td><?= htmlspecialchars($book['author']) ?></td>
<td><?= htmlspecialchars($book['category_name']) ?></td>
<td><?= $book['available_quantity'] ?></td>
<td>
<?php if ($book['available_quantity'] > 0): ?>
<a href="borrow.php?book_id=<?= $book['id'] ?>">借书</a>
<?php else: ?>
<span style="color:red;">已借完</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<!-- 分页 -->
<div>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<a href="?page=<?= $i ?>&search=<?= urlencode($search) ?>"><?= $i ?></a>
<?php endfor; ?>
</div>
</body>
</html>
借书功能 admin/borrow.php
这是最关键的逻辑。
<?php
require_once '../includes/auth.php';
require_once '../config/database.php';
if (!isAdmin()) {
header("Location: ../login.php");
exit;
}
// 处理借书请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$bookId = $_POST['book_id'];
$userId = $_POST['user_id']; // 通常通过扫描读者证或选择用户
// 1. 检查图书是否存在且有库存
$stmt = $pdo->prepare("SELECT * FROM books WHERE id = ? AND available_quantity > 0");
$stmt->execute([$bookId]);
$book = $stmt->fetch();
if (!$book) {
$error = "图书不存在或已借完";
} else {
// 2. 开始事务,保证数据一致性
$pdo->beginTransaction();
try {
// 减少库存
$updateStmt = $pdo->prepare("UPDATE books SET available_quantity = available_quantity - 1 WHERE id = ?");
$updateStmt->execute([$bookId]);
// 添加借阅记录
$borrowDate = date('Y-m-d');
$dueDate = date('Y-m-d', strtotime('+30 days')); // 默认借30天
$insertStmt = $pdo->prepare("INSERT INTO borrow_records (user_id, book_id, borrow_date, due_date, status) VALUES (?, ?, ?, ?, 'borrowed')");
$insertStmt->execute([$userId, $bookId, $borrowDate, $dueDate]);
$pdo->commit();
$success = "借书成功!";
} catch (Exception $e) {
$pdo->rollBack();
$error = "借书失败: " . $e->getMessage();
}
}
}
// 获取读者列表(用于选择)
$readers = $pdo->query("SELECT id, username FROM users WHERE role = 'reader'")->fetchAll();
// 获取所有图书
$books = $pdo->query("SELECT id, title, isbn FROM books WHERE available_quantity > 0")->fetchAll();
?>
<!-- 借书表单 HTML 代码(略,包含选择用户、选择图书、提交按钮) -->
还书功能 admin/return.php
<?php
// ... 权限验证同上 ...
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['return'])) {
$recordId = $_POST['record_id'];
// 查找借阅记录
$stmt = $pdo->prepare("SELECT * FROM borrow_records WHERE id = ? AND status = 'borrowed'");
$stmt->execute([$recordId]);
$record = $stmt->fetch();
if ($record) {
$pdo->beginTransaction();
try {
// 计算是否超期
$today = date('Y-m-d');
$fine = 0;
if ($today > $record['due_date']) {
$daysOverdue = (strtotime($today) - strtotime($record['due_date'])) / (60 * 60 * 24);
$fine = $daysOverdue * 0.5; // 每天罚款0.5元
}
// 更新借阅记录
$updateRecord = $pdo->prepare("UPDATE borrow_records SET return_date = ?, status = 'returned', fine = ? WHERE id = ?");
$updateRecord->execute([$today, $fine, $recordId]);
// 增加图书库存
$updateBook = $pdo->prepare("UPDATE books SET available_quantity = available_quantity + 1 WHERE id = ?");
$updateBook->execute([$record['book_id']]);
$pdo->commit();
$success = "还书成功!" . ($fine > 0 ? " 罚款:{$fine}元" : "");
} catch (Exception $e) {
$pdo->rollBack();
$error = "还书失败: " . $e->getMessage();
}
} else {
$error = "记录不存在或已归还";
}
}
?>
安全与注意事项
- SQL注入防护:全程使用 PDO 预处理语句(如上面代码中的 占位符),不要直接拼接SQL。
- 密码安全:使用
password_hash()和password_verify(),不要用 MD5。 - 权限控制:在每个管理后台页面顶部检查
isAdmin(),防止普通用户越权访问。 - XSS防护:所有输出到HTML的数据使用
htmlspecialchars()转义。 - 事务处理:借书/还书操作涉及多个表更新,务必使用事务(
beginTransaction/commit/rollBack)保证数据一致性。
进阶扩展方向
- 使用框架:将上述原生代码迁移到 Laravel 或 ThinkPHP,提高开发效率和安全性。
- 引入前端框架:使用 Bootstrap 或 Tailwind CSS 美化界面;使用 Vue/React 实现单页应用。
- API化:将业务逻辑封装成 RESTful API,用于小程序或移动端。
- 邮件提醒:在还书日临近时,用 PHP 的
mail()函数或 PHPMailer 发送提醒邮件。 - 图书预约:增加
reservations表,允许读者预约已被借出的图书。
希望这个方案能给你一个清晰的实施路径,你可以根据自己的需求(如是否要条形码扫描、是否要在线续借等)进一步调整和扩展。