本文目录导读:

实现一个图书馆管理系统是一个经典的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表,允许读者预约已被借出的图书。
希望这个方案能给你一个清晰的实施路径,你可以根据自己的需求(如是否要条形码扫描、是否要在线续借等)进一步调整和扩展。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播