- 产品列表展示:以卡片形式展示所有产品。
- 产品详情页:点击产品后,可以查看大图、名称、详细描述和价格。
- 后台管理:可以登录后台,添加、编辑和删除产品。
- 基础样式:使用现代的卡片式布局,响应式设计,在手机和电脑上都能良好显示。
项目结构
我们创建一个清晰的目录结构,这对于项目的维护至关重要。

/product-website/
├── admin/ # 后台管理目录
│ ├── index.php # 后台登录页面
│ ├── login.php # 处理登录逻辑
│ ├── dashboard.php # 后台管理面板
│ ├── create.php # 添加新产品页面
│ ├── edit.php # 编辑产品页面
│ ├── process.php # 处理创建/编辑的逻辑
│ └── delete.php # 处理删除的逻辑
│
├── assets/ # 静态资源目录
│ └── css/
│ └── style.css # 主样式文件
│
├── config/ # 配置文件目录
│ └── database.php # 数据库连接配置
│
├── images/ # 产品图片存放目录
│ ├── product1.jpg
│ ├── product2.jpg
│ └── ... # 上传的产品图片将放在这里
│
├── partials/ # 页面片段(公共部分)
│ ├── header.php # 公共头部
│ └── footer.php # 公共底部
│
├── index.php # 网站首页,展示所有产品
├── product.php # 产品详情页
└── logout.php # 后台登出脚本
第1步:数据库准备
您需要一个数据库来存储产品信息,请执行以下SQL语句来创建products表。
CREATE DATABASE `product_showcase`; USE `product_showcase`; CREATE TABLE `products` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `description` text NOT NULL, `price` decimal(10, 2) NOT NULL, `image` varchar(255) NOT NULL, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
第2步:PHP源码文件
我们按照上面的目录结构,逐一创建每个文件。
config/database.php - 数据库连接配置
<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_USER', 'root'); // 您的数据库用户名
define('DB_PASS', ''); // 您的数据库密码
define('DB_NAME', 'product_showcase'); // 您的数据库名
// 创建连接
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
// 检查连接是否成功
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// 设置字符集,防止中文乱码
$conn->set_charset("utf8mb4");
?>
assets/css/style.css - 样式文件
/* 全局样式 */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
margin: 0;
background-color: #f4f4f4;
color: #333;
}
.container {
max-width: 1100px;
margin: auto;
overflow: hidden;
padding: 0 2rem;
}
/* 头部样式 */
.header {
background: #333;
color: #fff;
padding: 1rem 0;
text-align: center;
}
/* 产品卡片样式 */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 2rem;
padding: 2rem 0;
}
.product-card {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
transition: transform 0.2s;
text-align: center;
}
.product-card:hover {
transform: translateY(-5px);
}
.product-card img {
max-width: 100%;
height: 200px;
object-fit: cover;
}
.product-info {
padding: 1.5rem;
}
.product-info h3 {
margin: 0 0 0.5rem 0;
font-size: 1.2rem;
}
.product-info p {
color: #777;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.btn {
display: inline-block;
background: #007bff;
color: #fff;
padding: 0.8rem 1.5rem;
text-decoration: none;
border-radius: 5px;
border: none;
cursor: pointer;
font-size: 1rem;
transition: background 0.2s;
}
.btn:hover {
background: #0056b3;
}
.btn-danger {
background: #dc3545;
}
.btn-danger:hover {
background: #c82333;
}
.btn-success {
background: #28a745;
}
.btn-success:hover {
background: #218838;
}
/* 详情页样式 */
.product-detail {
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
.product-detail img {
max-width: 100%;
max-height: 500px;
object-fit: contain;
border: 1px solid #ddd;
}
.product-detail-content h2 {
margin-top: 0;
}
.product-detail-content p {
font-size: 1.1rem;
color: #555;
}
.product-detail-content .price {
font-size: 1.5rem;
font-weight: bold;
color: #007bff;
margin: 1rem 0;
}
/* 后台管理样式 */
.admin-panel .btn {
margin-right: 0.5rem;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.8rem;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box; /* 确保padding不会影响总宽度 */
}
.form-group textarea {
height: 150px;
resize: vertical;
}
partials/header.php - 公共头部
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"><?php echo isset($page_title) ? $page_title . ' - ' : ''; ?>产品展示网站</title>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<header class="header">
<div class="container">
<h1>我的产品展示网站</h1>
<nav>
<a href="index.php">首页</a>
<a href="admin/index.php">后台管理</a>
</nav>
</div>
</header>
<div class="container">
partials/footer.php - 公共底部
</div> <!-- .container -->
<footer class="header" style="margin-top: 2rem;">
<div class="container">
<p>© <?php echo date('Y'); ?> 产品展示网站. All Rights Reserved.</p>
</div>
</footer>
</body>
</html>
第3步:前台页面 (用户访问)
index.php - 首页 (产品列表)
<?php
$page_title = '首页';
require_once 'config/database.php';
require_once 'partials/header.php';
// 从数据库获取所有产品
$sql = "SELECT * FROM products ORDER BY created_at DESC";
$result = $conn->query($sql);
?>
<h2>全部产品</h2>
<div class="product-grid">
<?php if ($result->num_rows > 0): ?>
<?php while($row = $result->fetch_assoc()): ?>
<div class="product-card">
<img src="images/<?php echo htmlspecialchars($row['image']); ?>" alt="<?php echo htmlspecialchars($row['name']); ?>">
<div class="product-info">
<h3><?php echo htmlspecialchars($row['name']); ?></h3>
<p><?php echo htmlspecialchars(substr($row['description'], 0, 100)) . '...'; ?></p>
<p class="price">¥ <?php echo htmlspecialchars($row['price']); ?></p>
<a href="product.php?id=<?php echo $row['id']; ?>" class="btn">查看详情</a>
</div>
</div>
<?php endwhile; ?>
<?php else: ?>
<p>暂无产品。</p>
<?php endif; ?>
</div>
<?php
require_once 'partials/footer.php';
?>
product.php - 产品详情页
<?php
require_once 'config/database.php';
// 检查是否有ID参数
if (!isset($_GET['id']) || empty($_GET['id'])) {
die('无效的产品ID');
}
$product_id = $_GET['id'];
// 获取单个产品信息
$stmt = $conn->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("i", $product_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
die('产品未找到');
}
$product = $result->fetch_assoc();
$page_title = $product['name'];
require_once 'partials/header.php';
?>
<div class="product-detail">
<div>
<img src="images/<?php echo htmlspecialchars($product['image']); ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
</div>
<div class="product-detail-content">
<h2><?php echo htmlspecialchars($product['name']); ?></h2>
<p class="price">¥ <?php echo htmlspecialchars($product['price']); ?></p>
<p><?php echo nl2br(htmlspecialchars($product['description'])); ?></p>
<a href="index.php" class="btn">返回列表</a>
</div>
</div>
<?php
$stmt->close();
$conn->close();
require_once 'partials/footer.php';
?>
第4步:后台管理页面
admin/index.php - 后台登录页
<?php
session_start();
// 如果已经登录,直接跳转到管理面板
if (isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true) {
header('Location: dashboard.php');
exit;
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">后台登录</title>
<link rel="stylesheet" href="../assets/css/style.css">
<style>
body { background: #f4f4f4; display: flex; justify-content: center; align-items: center; height: 100vh; }
.login-form { background: #fff; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); width: 100%; max-width: 400px; }
.login-form h2 { text-align: center; margin-bottom: 1.5rem; }
</style>
</head>
<body>
<div class="login-form">
<h2>管理员登录</h2>
<form action="login.php" method="post">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn" style="width: 100%;">登录</button>
</form>
</div>
</body>
</html>
admin/login.php - 处理登录逻辑
<?php
session_start();
// 简单的用户名密码验证,实际项目中应使用更安全的方式(如哈希密码)
$admin_username = 'admin';
$admin_password = 'password123'; // 请务必修改默认密码!
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'];
$password = $_POST['password'];
if ($username === $admin_username && $password === $admin_password) {
$_SESSION['admin_logged_in'] = true;
header('Location: dashboard.php');
exit;
} else {
$error = "用户名或密码错误";
header('Location: index.php?error=' . urlencode($error));
exit;
}
}
?>
admin/dashboard.php - 后台管理面板
<?php
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
header('Location: index.php');
exit;
}
require_once '../config/database.php';
require_once '../partials/header.php'; // 使用前台的header,但可以修改为专用的admin_header
?>
<h2>管理面板</h2>
<p>欢迎, 管理员!</p>
<a href="create.php" class="btn btn-success">添加新产品</a>
<hr style="margin: 2rem 0;">
<h3>产品列表</h3>
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background: #f0f0f0;">
<th style="border: 1px solid #ddd; padding: 8px;">ID</th>
<th style="border: 1px solid #ddd; padding: 8px;">名称</th>
<th style="border: 1px solid #ddd; padding: 8px;">价格</th>
<th style="border: 1px solid #ddd; padding: 8px;">操作</th>
</tr>
</thead>
<tbody>
<?php
$sql = "SELECT * FROM products";
$result = $conn->query($sql);
if ($result->num_rows > 0):
while($row = $result->fetch_assoc()): ?>
<tr>
<td style="border: 1px solid #ddd; padding: 8px;"><?php echo $row['id']; ?></td>
<td style="border: 1px solid #ddd; padding: 8px;"><?php echo htmlspecialchars($row['name']); ?></td>
<td style="border: 1px solid #ddd; padding: 8px;">¥ <?php echo htmlspecialchars($row['price']); ?></td>
<td style="border: 1px solid #ddd; padding: 8px;">
<a href="edit.php?id=<?php echo $row['id']; ?>" class="btn">编辑</a>
<a href="delete.php?id=<?php echo $row['id']; ?>" class="btn btn-danger" onclick="return confirm('确定要删除这个产品吗?');">删除</a>
</td>
</tr>
<?php endwhile;
else: ?>
<tr>
<td colspan="4" style="border: 1px solid #ddd; padding: 8px; text-align: center;">暂无产品</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<a href="../logout.php" class="btn btn-danger" style="margin-top: 1rem;">退出登录</a>
<?php require_once '../partials/footer.php'; ?>
admin/create.php - 添加产品页面
<?php
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
header('Location: index.php');
exit;
}
require_once '../partials/header.php';
?>
<h2>添加新产品</h2>
<form action="process.php" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="name">产品名称</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="number" id="price" name="price" step="0.01" required>
</div>
<div class="form-group">
<label for="description">产品描述</label>
<textarea id="description" name="description" required></textarea>
</div>
<div class="form-group">
<label for="image">产品图片</label>
<input type="file" id="image" name="image" accept="image/*" required>
</div>
<button type="submit" class="btn btn-success">添加产品</button>
<a href="dashboard.php" class="btn">取消</a>
</form>
<?php require_once '../partials/footer.php'; ?>
admin/edit.php - 编辑产品页面
<?php
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
header('Location: index.php');
exit;
}
require_once '../config/database.php';
if (!isset($_GET['id']) || empty($_GET['id'])) {
die('无效的产品ID');
}
$product_id = $_GET['id'];
$stmt = $conn->prepare("SELECT * FROM products WHERE id = ?");
$stmt->bind_param("i", $product_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
die('产品未找到');
}
$product = $result->fetch_assoc();
require_once '../partials/header.php';
?>
<h2>编辑产品</h2>
<form action="process.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="<?php echo $product['id']; ?>">
<input type="hidden" name="current_image" value="<?php echo $product['image']; ?>">
<div class="form-group">
<label for="name">产品名称</label>
<input type="text" id="name" name="name" value="<?php echo htmlspecialchars($product['name']); ?>" required>
</div>
<div class="form-group">
<label for="price">价格</label>
<input type="number" id="price" name="price" step="0.01" value="<?php echo htmlspecialchars($product['price']); ?>" required>
</div>
<div class="form-group">
<label for="description">产品描述</label>
<textarea id="description" name="description" required><?php echo htmlspecialchars($product['description']); ?></textarea>
</div>
<div class="form-group">
<label for="image">更换产品图片 (留空则不更换)</label>
<input type="file" id="image" name="image" accept="image/*">
</div>
<button type="submit" class="btn btn-success">更新产品</button>
<a href="dashboard.php" class="btn">取消</a>
</form>
<?php
$stmt->close();
$conn->close();
require_once '../partials/footer.php';
?>
admin/process.php - 处理创建和编辑的逻辑
<?php
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
header('Location: index.php');
exit;
}
require_once '../config/database.php';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$id = $_POST['id'] ?? null;
$name = $_POST['name'];
$price = $_POST['price'];
$description = $_POST['description'];
$current_image = $_POST['current_image'];
$new_image_name = $current_image; // 默认使用当前图片名
// 处理图片上传
if (isset($_FILES['image']) && $_FILES['image']['error'] == 0) {
$target_dir = "../images/";
$imageFileType = strtolower(pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION));
$new_image_name = uniqid("product_", true) . "." . $imageFileType;
$target_file = $target_dir . $new_image_name;
// 检查文件是否为真实图片
$check = getimagesize($_FILES["image"]["tmp_name"]);
if($check !== false) {
if (move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)) {
// 图片上传成功,删除旧图片(如果存在且不是默认图)
if (!empty($current_image) && file_exists($target_dir . $current_image)) {
unlink($target_dir . $current_image);
}
} else {
die("抱歉,上传文件时出错。");
}
} else {
die("文件不是有效的图片。");
}
}
if ($id) {
// 更新产品
$stmt = $conn->prepare("UPDATE products SET name=?, price=?, description=?, image=? WHERE id=?");
$stmt->bind_param("sdssi", $name, $price, $description, $new_image_name, $id);
$message = "产品更新成功!";
} else {
// 添加新产品
$stmt = $conn->prepare("INSERT INTO products (name, price, description, image) VALUES (?, ?, ?, ?)");
$stmt->bind_param("sdss", $name, $price, $description, $new_image_name);
$message = "产品添加成功!";
}
if ($stmt->execute()) {
header('Location: dashboard.php?message=' . urlencode($message));
exit;
} else {
die("错误: " . $stmt->error);
}
$stmt->close();
}
$conn->close();
?>
admin/delete.php - 处理删除的逻辑
<?php
session_start();
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
header('Location: index.php');
exit;
}
require_once '../config/database.php';
if (!isset($_GET['id']) || empty($_GET['id'])) {
die('无效的产品ID');
}
$product_id = $_GET['id'];
// 先获取图片名
$stmt = $conn->prepare("SELECT image FROM products WHERE id = ?");
$stmt->bind_param("i", $product_id);
$stmt->execute();
$result = $stmt->get_result();
$product = $result->fetch_assoc();
$image_name = $product['image'];
// 删除数据库记录
$stmt = $conn->prepare("DELETE FROM products WHERE id = ?");
$stmt->bind_param("i", $product_id);
if ($stmt->execute()) {
// 删除物理图片文件
if (!empty($image_name) && file_exists("../images/" . $image_name)) {
unlink("../images/" . $image_name);
}
header('Location: dashboard.php?message=产品删除成功!');
exit;
} else {
die("删除失败: " . $stmt->error);
}
$stmt->close();
$conn->close();
?>
logout.php - 登出脚本
<?php
session_start();
// 清除所有session变量
$_SESSION = array();
// 销毁session
session_destroy();
// 重定向到首页
header('Location: index.php');
exit;
?>
如何使用
- 环境准备:确保您有一个支持PHP和MySQL的环境,例如XAMPP、WAMP或MAMP。
- 创建目录和文件:按照上面的目录结构,在您的Web服务器根目录下创建所有文件和文件夹。
- 配置数据库:
- 修改
config/database.php文件中的数据库用户名、密码和数据库名。 - 使用MySQL客户端(如phpMyAdmin)执行第1步的SQL语句来创建数据库和表。
- 修改
- 设置权限:确保
images目录有写入权限,以便上传图片。 - 访问网站:
- 前台访问:
http://localhost/product-website/ - 后台访问:
http://localhost/product-website/admin/index.php- 默认登录用户名:
admin - 默认登录密码:
password123
- 默认登录用户名:
- 前台访问:
- 开始使用:登录后台后,您就可以添加、编辑和删除产品了。
如何扩展
- 分页:当产品很多时,可以在
index.php中添加分页功能。 - 用户注册/登录:可以为网站添加用户系统,让用户收藏产品或发表评论。
- 购物车和订单:这是电商网站的核心功能,需要更复杂的逻辑和数据库设计。
- 更强大的后台:可以添加产品分类、标签、库存管理等功能。
- 前端框架:可以引入Vue.js或React来构建更动态和交互性强的用户界面。
这份源码是一个非常好的起点,它结构清晰,功能完整,非常适合学习和二次开发。

