本文目录导读:

我来给你一个完整的PHP实战项目方案,从基础到进阶,包含真实项目案例和代码示例。
🚀 实战项目:在线图书管理系统
这是一个完整的CRUD项目,涵盖用户认证、数据管理、文件上传等核心功能。
项目结构
book-manager/
├── config/
│ └── database.php
├── includes/
│ ├── auth.php
│ ├── functions.php
│ └── header.php
├── admin/
│ ├── login.php
│ ├── dashboard.php
│ ├── books/
│ │ ├── index.php
│ │ ├── create.php
│ │ ├── edit.php
│ │ └── delete.php
│ └── uploads/
├── assets/
│ ├── css/
│ └── js/
└── index.php
数据库设计
CREATE DATABASE book_manage;
USE book_manage;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE books (
id INT PRIMARY KEY AUTO_INCREMENT,VARCHAR(200) NOT NULL,
author VARCHAR(100) NOT NULL,
isbn VARCHAR(13) UNIQUE,
price DECIMAL(10,2),
cover_image VARCHAR(255),
description TEXT,
published_date DATE,
created_by INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (created_by) REFERENCES users(id)
);
配置文件
<?php
// config/database.php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'book_manage');
function getConnection() {
try {
$conn = new PDO(
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
DB_USER,
DB_PASS
);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $conn;
} catch(PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
}
?>
用户认证系统
<?php
// includes/auth.php
session_start();
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
function requireLogin() {
if (!isLoggedIn()) {
header('Location: /book-manager/admin/login.php');
exit();
}
}
function login($username, $password) {
$conn = getConnection();
$stmt = $conn->prepare("SELECT id, username, password 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'];
return true;
}
return false;
}
function logout() {
session_destroy();
header('Location: login.php');
exit();
}
?>
登录页面
<?php
// admin/login.php
require_once '../config/database.php';
require_once '../includes/auth.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (login($username, $password)) {
header('Location: dashboard.php');
exit();
} else {
$error = "用户名或密码错误";
}
}
?>
<!DOCTYPE html>
<html>
<head>登录 - 图书管理系统</title>
<link rel="stylesheet" href="../assets/css/style.css">
</head>
<body class="login-page">
<div class="login-container">
<h2>图书管理系统登录</h2>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" required>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
</div>
</body>
</html>
图书列表(含分页和搜索)
<?php
// admin/books/index.php
require_once '../../config/database.php';
require_once '../../includes/auth.php';
requireLogin();
$conn = getConnection();
$search = $_GET['search'] ?? '';
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
// 构建查询
$where = '';
if ($search) {
$where = "WHERE title LIKE :search OR author LIKE :search";
}
// 获取总数
$countQuery = "SELECT COUNT(*) as total FROM books $where";
$stmt = $conn->prepare($countQuery);
if ($search) {
$stmt->bindValue(':search', "%$search%");
}
$stmt->execute();
$total = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
$totalPages = ceil($total / $limit);
// 获取图书列表
$query = "SELECT * FROM books $where ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
$stmt = $conn->prepare($query);
if ($search) {
$stmt->bindValue(':search', "%$search%");
}
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$books = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<?php include '../includes/header.php'; ?>
<div class="container">
<div class="page-header">
<h1>图书管理</h1>
<a href="create.php" class="btn btn-success">新增图书</a>
</div>
<!-- 搜索表单 -->
<form method="GET" class="search-form">
<input type="text" name="search" value="<?php echo htmlspecialchars($search); ?>"
placeholder="搜索标题或作者...">
<button type="submit" class="btn btn-primary">搜索</button>
</form>
<!-- 图书列表 -->
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>封面</th>
<th>标题</th>
<th>作者</th>
<th>价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($books as $book): ?>
<tr>
<td><?php echo $book['id']; ?></td>
<td>
<?php if ($book['cover_image']): ?>
<img src="../uploads/<?php echo $book['cover_image']; ?>"
width="50" height="70" alt="封面">
<?php endif; ?>
</td>
<td><?php echo htmlspecialchars($book['title']); ?></td>
<td><?php echo htmlspecialchars($book['author']); ?></td>
<td>¥<?php echo number_format($book['price'], 2); ?></td>
<td>
<a href="edit.php?id=<?php echo $book['id']; ?>" class="btn btn-sm">编辑</a>
<a href="delete.php?id=<?php echo $book['id']; ?>"
class="btn btn-sm btn-danger"
onclick="return confirm('确定删除吗?')">删除</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- 分页 -->
<?php if ($totalPages > 1): ?>
<nav>
<ul class="pagination">
<?php if ($page > 1): ?>
<li><a href="?page=<?php echo $page - 1; ?>&search=<?php echo urlencode($search); ?>">« 上一页</a></li>
<?php endif; ?>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<li class="<?php echo $i === $page ? 'active' : ''; ?>">
<a href="?page=<?php echo $i; ?>&search=<?php echo urlencode($search); ?>"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
<?php if ($page < $totalPages): ?>
<li><a href="?page=<?php echo $page + 1; ?>&search=<?php echo urlencode($search); ?>">下一页 »</a></li>
<?php endif; ?>
</ul>
</nav>
<?php endif; ?>
</div>
添加图书(含文件上传)
<?php
// admin/books/create.php
require_once '../../config/database.php';
require_once '../../includes/auth.php';
requireLogin();
$conn = getConnection();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = $_POST['title'];
$author = $_POST['author'];
$isbn = $_POST['isbn'];
$price = $_POST['price'];
$description = $_POST['description'];
$published_date = $_POST['published_date'];
// 验证
$errors = [];
if (empty($title)) $errors[] = "标题不能为空";
if (empty($author)) $errors[] = "作者不能为空";
// 处理文件上传
$coverImage = null;
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === 0) {
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$fileType = $_FILES['cover_image']['type'];
if (in_array($fileType, $allowedTypes)) {
$fileExt = pathinfo($_FILES['cover_image']['name'], PATHINFO_EXTENSION);
$fileName = time() . '_' . uniqid() . '.' . $fileExt;
$uploadPath = '../../uploads/' . $fileName;
if (move_uploaded_file($_FILES['cover_image']['tmp_name'], $uploadPath)) {
$coverImage = $fileName;
} else {
$errors[] = "文件上传失败";
}
} else {
$errors[] = "只允许上传JPEG、PNG、GIF格式的图片";
}
}
if (empty($errors)) {
$stmt = $conn->prepare("INSERT INTO books (title, author, isbn, price, description, published_date, cover_image, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([
$title, $author, $isbn, $price, $description,
$published_date, $coverImage, $_SESSION['user_id']
]);
header('Location: index.php?message=success');
exit();
}
}
?>
<?php include '../includes/header.php'; ?>
<div class="container">
<h2>新增图书</h2>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<label>书名 *</label>
<input type="text" name="title" value="<?php echo $_POST['title'] ?? ''; ?>" required>
</div>
<div class="form-group">
<label>作者 *</label>
<input type="text" name="author" value="<?php echo $_POST['author'] ?? ''; ?>" required>
</div>
<div class="form-group">
<label>ISBN</label>
<input type="text" name="isbn" value="<?php echo $_POST['isbn'] ?? ''; ?>">
</div>
<div class="form-group">
<label>价格</label>
<input type="number" step="0.01" name="price" value="<?php echo $_POST['price'] ?? ''; ?>">
</div>
<div class="form-group">
<label>出版日期</label>
<input type="date" name="published_date" value="<?php echo $_POST['published_date'] ?? ''; ?>">
</div>
<div class="form-group">
<label>封面图片</label>
<input type="file" name="cover_image" accept="image/*">
</div>
<div class="form-group">
<label>简介</label>
<textarea name="description" rows="4"><?php echo $_POST['description'] ?? ''; ?></textarea>
</div>
<button type="submit" class="btn btn-primary">保存</button>
<a href="index.php" class="btn btn-secondary">返回</a>
</form>
</div>
公共函数库
<?php
// includes/functions.php
function sanitizeInput($data) {
return htmlspecialchars(strip_tags(trim($data)));
}
function redirect($url) {
header("Location: $url");
exit();
}
function formatPrice($price) {
return '¥' . number_format($price, 2);
}
function generateCSRFToken() {
if (!isset($_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);
}
?>
安全实践
// 密码哈希处理
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
// 验证码示例
session_start();
$randomCode = rand(1000, 9999);
$_SESSION['captcha'] = $randomCode;
// 创建简单的验证码图片
header('Content-Type: image/png');
$image = imagecreatetruecolor(120, 40);
$bg = imagecolorallocate($image, 255, 255, 255);
$textColor = imagecolorallocate($image, 0, 0, 0);
imagefilledrectangle($image, 0, 0, 120, 40, $bg);
imagestring($image, 5, 30, 10, $randomCode, $textColor);
imagepng($image);
imagedestroy($image);
前端样式
/* assets/css/style.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #dee2e6;
}
.btn {
display: inline-block;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-success {
background-color: #28a745;
color: white;
}
.btn-danger {
background-color: #dc3545;
color: white;
}
.btn-secondary {
background-color: #6c757d;
color: white;
text-decoration: none;
}
.table {
width: 100%;
background-color: white;
border-collapse: collapse;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.table th,
.table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #dee2e6;
}
.table th {
background-color: #f8f9fa;
font-weight: 600;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
}
.alert {
padding: 12px 20px;
margin-bottom: 20px;
border-radius: 4px;
}
.alert-danger {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.pagination {
display: flex;
list-style: none;
padding: 20px 0;
justify-content: center;
}
.pagination li {
margin: 0 5px;
}
.pagination a,
.pagination .active {
display: block;
padding: 8px 12px;
border: 1px solid #dee2e6;
border-radius: 4px;
text-decoration: none;
color: #007bff;
}
.pagination .active {
background-color: #007bff;
color: white;
}
📚 进阶实战项目推荐
在线商城系统
- 商品管理(SKU、库存、分类)
- 购物车功能
- 订单管理
- 支付集成(微信/支付宝)
- 优惠券系统
博客/CMS系统
- 文章管理(Markdown编辑)
- 用户权限(管理员/编辑/作者)
- 评论系统
- 分类标签
- SEO优化
API开发项目
// RESTful API示例
// api/books.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$method = $_SERVER['REQUEST_METHOD'];
$conn = getConnection();
switch ($method) {
case 'GET':
// 获取图书列表
$stmt = $conn->query("SELECT * FROM books");
$books = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['status' => 'success', 'data' => $books]);
break;
case 'POST':
// 创建图书
$data = json_decode(file_get_contents('php://input'), true);
$stmt = $conn->prepare("INSERT INTO books (title, author) VALUES (?, ?)");
$stmt->execute([$data['title'], $data['author']]);
echo json_encode(['status' => 'success', 'id' => $conn->lastInsertId()]);
break;
}
🎯 部署与上线
生产环境配置
# .htaccess 安全配置
Options -Indexes
ServerSignature Off
# 防止URL注入
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9/]+)$ index.php?route=$1 [QSA,L]
# 保护配置文件
<FilesMatch "\.(env|ini|log)$">
Order allow,deny
Deny from all
</FilesMatch>
性能优化
// 使用Redis缓存
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 检查缓存
$cached = $redis->get('books_list');
if ($cached) {
$books = json_decode($cached, true);
} else {
// 查询数据库
$stmt = $conn->query("SELECT * FROM books");
$books = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 设置缓存,10分钟过期
$redis->setex('books_list', 600, json_encode($books));
}
💡 学习建议
- 从简单开始:先完成一个简单的CRUD系统
- 逐步增加功能:慢慢加入用户认证、文件上传、分页等特性
- 代码规范:使用PSR-4自动加载规范,确保代码整洁
- 安全第一:从开始就注意SQL注入、XSS攻击防护
- 版本控制:使用Git管理代码,方便回滚和协作
这个实战项目涵盖了PHP开发的绝大多数核心概念,建议你按照项目结构逐步实现,并在理解的基础上尝试添加新功能(如API接口、数据导出、批量操作等),这将帮助你快速提升PHP实战能力。