本文目录导读:

我来详细介绍PHP实现留言反馈功能的完整方案,包含数据库设计、前端表单、后端处理和列表展示。
数据库设计
首先创建留言反馈表:
CREATE TABLE `feedback` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '留言人姓名', `email` varchar(100) DEFAULT NULL COMMENT '电子邮箱', `phone` varchar(20) DEFAULT NULL COMMENT '联系电话', varchar(200) NOT NULL COMMENT '留言标题', `content` text NOT NULL COMMENT '留言内容', `category` varchar(30) DEFAULT 'general' COMMENT '留言类型', `status` tinyint(1) DEFAULT 0 COMMENT '状态:0未处理,1已处理', `reply` text DEFAULT NULL COMMENT '管理员回复', `ip_address` varchar(45) DEFAULT NULL COMMENT 'IP地址', `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `status` (`status`), KEY `created_at` (`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='留言反馈表';
数据库连接类
config/database.php:
<?php
class Database {
private $host = 'localhost';
private $db_name = 'your_database';
private $username = 'root';
private $password = '';
private $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host={$this->host};dbname={$this->db_name};charset=utf8mb4",
$this->username,
$this->password
);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "连接失败: " . $e->getMessage();
}
return $this->conn;
}
}
?>
提交留言页面
feedback_form.php:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">留言反馈</title>
<style>
.feedback-form {
max-width: 600px;
margin: 50px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 3px;
}
.form-group textarea {
height: 150px;
resize: vertical;
}
.submit-btn {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 3px;
cursor: pointer;
}
.submit-btn:hover {
background-color: #0056b3;
}
.error-message {
color: red;
margin-bottom: 10px;
}
.success-message {
color: green;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="feedback-form">
<h2>留言反馈</h2>
<?php if (isset($_GET['success'])): ?>
<div class="success-message">留言提交成功!</div>
<?php endif; ?>
<?php if (isset($_GET['error'])): ?>
<div class="error-message">
<?php echo htmlspecialchars($_GET['error']); ?>
</div>
<?php endif; ?>
<form action="process_feedback.php" method="POST">
<div class="form-group">
<label for="name">姓名 *</label>
<input type="text" id="name" name="name" required maxlength="50">
</div>
<div class="form-group">
<label for="email">电子邮箱</label>
<input type="email" id="email" name="email" maxlength="100">
</div>
<div class="form-group">
<label for="phone">联系电话</label>
<input type="tel" id="phone" name="phone" maxlength="20">
</div>
<div class="form-group">
<label for="category">留言类型</label>
<select id="category" name="category">
<option value="general">一般咨询</option>
<option value="suggestion">意见建议</option>
<option value="complaint">投诉反馈</option>
<option value="other">其他</option>
</select>
</div>
<div class="form-group">
<label for="title">留言标题 *</label>
<input type="text" id="title" name="title" required maxlength="200">
</div>
<div class="form-group">
<label for="content">留言内容 *</label>
<textarea id="content" name="content" required maxlength="2000"></textarea>
</div>
<button type="submit" class="submit-btn">提交留言</button>
</form>
</div>
</body>
</html>
处理留言提交
process_feedback.php:
<?php
session_start();
require_once 'config/database.php';
// 创建验证码校验(可选)
// if ($_POST['captcha'] !== $_SESSION['captcha']) {
// header('Location: feedback_form.php?error=验证码错误');
// exit;
// }
// 验证字段
$errors = [];
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$category = trim($_POST['category'] ?? 'general');
$title = trim($_POST['title'] ?? '');
$content = trim($_POST['content'] ?? '');
// 基本验证
if (empty($name)) {
$errors[] = '姓名不能为空';
}
if (empty($title)) {
$errors[] = '标题不能为空';
}
if (empty($content)) {
$errors[] = '留言内容不能为空';
}
if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = '邮箱格式不正确';
}
// 长度验证
if (mb_strlen($name) > 50) {
$errors[] = '姓名不能超过50字';
}
if (mb_strlen($title) > 200) {
$errors[] = '标题不能超过200字';
}
if (mb_strlen($content) > 2000) {
$errors[] = '留言内容不能超过2000字';
}
if (!empty($errors)) {
$error_msg = implode('; ', $errors);
header("Location: feedback_form.php?error=" . urlencode($error_msg));
exit;
}
// 获取客户端IP
$ip_address = $_SERVER['REMOTE_ADDR'];
// 防刷验证:同一IP 5分钟内只能留言一次
$database = new Database();
$db = $database->getConnection();
$stmt = $db->prepare("SELECT COUNT(*) FROM feedback
WHERE ip_address = :ip
AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)");
$stmt->bindParam(':ip', $ip_address);
$stmt->execute();
$recent_count = $stmt->fetchColumn();
if ($recent_count > 0) {
header('Location: feedback_form.php?error=操作太频繁,请5分钟后再试');
exit;
}
try {
$sql = "INSERT INTO feedback (name, email, phone, category, title, content, ip_address, created_at)
VALUES (:name, :email, :phone, :category, :title, :content, :ip_address, NOW())";
$stmt = $db->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->bindParam(':category', $category);
$stmt->bindParam(':title', $title);
$stmt->bindParam(':content', $content);
$stmt->bindParam(':ip_address', $ip_address);
$stmt->execute();
// 可选:发送通知邮件
// sendNotificationEmail($title, $content);
header('Location: feedback_form.php?success=1');
} catch(PDOException $e) {
header('Location: feedback_form.php?error=系统错误,请稍后重试');
}
?>
留言列表展示
feedback_list.php:
<?php
require_once 'config/database.php';
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$perPage = 10;
$offset = ($page - 1) * $perPage;
$database = new Database();
$db = $database->getConnection();
// 查询总记录数
$countStmt = $db->query("SELECT COUNT(*) FROM feedback WHERE status = 1");
$totalRecords = $countStmt->fetchColumn();
$totalPages = ceil($totalRecords / $perPage);
// 查询当前页数据
$sql = "SELECT * FROM feedback
WHERE status = 1
ORDER BY created_at DESC
LIMIT :limit OFFSET :offset";
$stmt = $db->prepare($sql);
$stmt->bindParam(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$feedbacks = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">留言列表</title>
<style>
.feedback-list {
max-width: 800px;
margin: 50px auto;
}
.feedback-item {
border: 1px solid #ddd;
margin-bottom: 20px;
padding: 15px;
border-radius: 5px;
}
.feedback-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
color: #666;
}
.feedback-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.feedback-content {
line-height: 1.6;
margin-bottom: 10px;
}
.feedback-reply {
background-color: #f8f9fa;
padding: 10px;
border-left: 3px solid #007bff;
margin-top: 10px;
}
.pagination {
text-align: center;
margin-top: 20px;
}
.pagination a {
display: inline-block;
padding: 5px 10px;
margin: 0 2px;
border: 1px solid #ddd;
text-decoration: none;
color: #333;
}
.pagination a.active {
background-color: #007bff;
color: white;
border-color: #007bff;
}
</style>
</head>
<body>
<div class="feedback-list">
<h2>留言列表</h2>
<?php if (empty($feedbacks)): ?>
<p>暂无留言</p>
<?php else: ?>
<?php foreach ($feedbacks as $feedback): ?>
<div class="feedback-item">
<div class="feedback-header">
<span>留言人:<?php echo htmlspecialchars($feedback['name']); ?></span>
<span>类型:<?php echo htmlspecialchars($feedback['category']); ?></span>
<span><?php echo date('Y-m-d H:i', strtotime($feedback['created_at'])); ?></span>
</div>
<div class="feedback-title">
<?php echo htmlspecialchars($feedback['title']); ?>
</div>
<div class="feedback-content">
<?php echo nl2br(htmlspecialchars($feedback['content'])); ?>
</div>
<?php if (!empty($feedback['reply'])): ?>
<div class="feedback-reply">
<strong>管理员回复:</strong>
<?php echo nl2br(htmlspecialchars($feedback['reply'])); ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<div class="pagination">
<?php if ($page > 1): ?>
<a href="?page=<?php echo $page - 1; ?>">上一页</a>
<?php endif; ?>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<a href="?page=<?php echo $i; ?>"
class="<?php echo $i == $page ? 'active' : ''; ?>">
<?php echo $i; ?>
</a>
<?php endfor; ?>
<?php if ($page < $totalPages): ?>
<a href="?page=<?php echo $page + 1; ?>">下一页</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</body>
</html>
管理员后台回复
admin_reply.php(需要登录验证):
<?php
// 需要管理员登录验证
require_once 'config/database.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$id = (int)$_POST['id'];
$reply = trim($_POST['reply']);
$database = new Database();
$db = $database->getConnection();
$sql = "UPDATE feedback
SET reply = :reply,
status = 1,
updated_at = NOW()
WHERE id = :id";
$stmt = $db->prepare($sql);
$stmt->bindParam(':reply', $reply);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
if ($stmt->execute()) {
header('Location: admin_feedback_list.php?success=1');
} else {
header('Location: admin_feedback_list.php?error=1');
}
}
?>
关键安全措施
// 1. CSRF防护
session_start();
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
// 表单中添加:<input type="hidden" name="csrf_token" value="<?php echo $token; ?>">
// 提交时验证
// 2. XSS防护
$safe_content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
// 3. SQL注入防护 - 使用预处理语句(已实现)
// 4. 频次限制
file_put_contents('rate_limit.log', date('Y-m-d H:i:s') . " - IP: $ip_address\n", FILE_APPEND);
可选功能扩展
- 邮件通知:提交留言后发送邮件通知管理员
- 验证码:添加图形验证码或Google reCAPTCHA
- 附件上传:允许上传图片或文件
- 状态标记:管理员标记已处理/未处理
- 搜索筛选:按时间、类型、状态筛选
- API接口:提供RESTful API供前端调用
这个完整的留言反馈系统包含了数据库设计、前端展示、后端处理和安全管理,你可以根据需要调整样式和功能,建议在实际部署时添加更多的安全措施,如内容过滤、防XSS攻击等。