PHP项目怎么实现图书馆管理?

wen java案例 9

本文目录导读:

PHP项目怎么实现图书馆管理?

  1. 系统功能模块规划
  2. 数据库设计(MySQL)
  3. 项目目录结构(推荐)
  4. 核心功能代码实现(关键片段)
  5. 安全与注意事项
  6. 进阶扩展方向

实现一个图书馆管理系统是一个经典的PHP项目,涵盖了数据库设计、CRUD操作、用户认证和权限管理等核心技能。

下面为你提供一个从零到一的完整实现方案,包括系统架构、功能模块、数据库设计和核心代码示例。

系统功能模块规划

一个基础但完整的图书馆管理系统通常包含以下模块:

  1. 用户管理
    • 管理员(图书管理员):负责图书上架、借出、归还、用户管理。
    • 读者(普通用户):可以查询图书、查看个人借阅历史、预约书籍。
  2. 图书管理
    • 添加、编辑、删除图书信息(ISBN、书名、作者、出版社、分类、库存)。
    • 图书分类管理。
  3. 借阅管理
    • 借书(扫描读者证和图书条码)。
    • 还书(计算是否超期,生成罚款)。
    • 借阅记录查询。
  4. 系统辅助功能
    • 登录与注销(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 = "记录不存在或已归还";
    }
}
?>

安全与注意事项

  1. SQL注入防护:全程使用 PDO 预处理语句(如上面代码中的 占位符),不要直接拼接SQL。
  2. 密码安全:使用 password_hash()password_verify(),不要用 MD5。
  3. 权限控制:在每个管理后台页面顶部检查 isAdmin(),防止普通用户越权访问。
  4. XSS防护:所有输出到HTML的数据使用 htmlspecialchars() 转义。
  5. 事务处理:借书/还书操作涉及多个表更新,务必使用事务(beginTransaction / commit / rollBack)保证数据一致性。

进阶扩展方向

  • 使用框架:将上述原生代码迁移到 LaravelThinkPHP,提高开发效率和安全性。
  • 引入前端框架:使用 BootstrapTailwind CSS 美化界面;使用 Vue/React 实现单页应用。
  • API化:将业务逻辑封装成 RESTful API,用于小程序或移动端。
  • 邮件提醒:在还书日临近时,用 PHP 的 mail() 函数或 PHPMailer 发送提醒邮件。
  • 图书预约:增加 reservations 表,允许读者预约已被借出的图书。

希望这个方案能给你一个清晰的实施路径,你可以根据自己的需求(如是否要条形码扫描、是否要在线续借等)进一步调整和扩展。

抱歉,评论功能暂时关闭!