本文目录导读:

我来介绍PHP项目实现用户反馈处理的完整方案,涵盖前端收集、后端处理和后台管理。
数据库设计
反馈表单表
CREATE TABLE `feedback` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL COMMENT '用户ID(未登录可为null)', `type` tinyint(4) NOT NULL COMMENT '反馈类型:1-功能建议 2-BUG报告 3-产品问题 4-其他', varchar(200) NOT NULL COMMENT '反馈标题', `content` text NOT NULL COMMENT '反馈内容', `contact` varchar(100) DEFAULT NULL COMMENT '联系方式', `screenshot` varchar(500) DEFAULT NULL COMMENT '截图路径', `status` tinyint(4) DEFAULT '0' COMMENT '状态:0-待处理 1-处理中 2-已解决 3-已关闭', `priority` tinyint(4) DEFAULT '2' COMMENT '优先级:1-紧急 2-普通 3-低', `admin_reply` text COMMENT '管理员回复', `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
反馈处理日志表
CREATE TABLE `feedback_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `feedback_id` int(11) NOT NULL, `action` varchar(50) NOT NULL COMMENT '操作类型', `operator` int(11) NOT NULL COMMENT '操作人', `remark` text COMMENT '备注', `created_at` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_feedback_id` (`feedback_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
前端反馈提交页面
feedback_form.php
<!DOCTYPE html>
<html>
<head>用户反馈</title>
</head>
<body>
<div class="container">
<h2>用户反馈</h2>
<form id="feedbackForm" method="post" enctype="multipart/form-data" action="submit_feedback.php">
<div class="form-group">
<label>反馈类型</label>
<select name="type" required>
<option value="1">功能建议</option>
<option value="2">BUG报告</option>
<option value="3">产品问题</option>
<option value="4">其他</option>
</select>
</div>
<div class="form-group">
<label>标题</label>
<input type="text" name="title" required maxlength="200">
</div>
<div class="form-group">
<label>详细描述</label>
<textarea name="content" rows="5" required></textarea>
</div>
<div class="form-group">
<label>联系方式(选填)</label>
<input type="text" name="contact" placeholder="邮箱或手机号">
</div>
<div class="form-group">
<label>截图(选填)</label>
<input type="file" name="screenshot" accept="image/*">
</div>
<button type="submit">提交反馈</button>
</form>
</div>
<script>
document.getElementById('feedbackForm').onsubmit = async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('submit_feedback.php', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
alert('感谢您的反馈!');
this.reset();
} else {
alert(result.message || '提交失败,请重试');
}
} catch (error) {
alert('网络错误,请重试');
}
};
</script>
</body>
</html>
后端处理代码
submit_feedback.php
<?php
session_start();
require_once 'config.php';
require_once 'functions.php';
header('Content-Type: application/json');
try {
// 验证必要字段
if (empty($_POST['title']) || empty($_POST['content'])) {
throw new Exception('标题和内容不能为空');
}
// 上传截图
$screenshotPath = null;
if (isset($_FILES['screenshot']) && $_FILES['screenshot']['error'] == 0) {
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($_FILES['screenshot']['type'], $allowedTypes)) {
throw new Exception('只支持JPG、PNG、GIF格式的图片');
}
$uploadDir = 'uploads/feedback/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$fileName = uniqid() . '_' . basename($_FILES['screenshot']['name']);
$filePath = $uploadDir . $fileName;
if (!move_uploaded_file($_FILES['screenshot']['tmp_name'], $filePath)) {
throw new Exception('截图上传失败');
}
$screenshotPath = $filePath;
}
// 插入数据库
$pdo = getDBConnection();
$stmt = $pdo->prepare("INSERT INTO feedback
(user_id, type, title, content, contact, screenshot, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, 0, NOW())");
$stmt->execute([
$_SESSION['user_id'] ?? null,
$_POST['type'],
$_POST['title'],
$_POST['content'],
$_POST['contact'] ?? null,
$screenshotPath
]);
// 发送通知(可选)
sendNotification($feedbackId);
echo json_encode(['success' => true, 'message' => '反馈提交成功']);
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
后台管理界面
admin_feedback.php
<?php
session_start();
require_once 'config.php';
require_once 'functions.php';
// 验证管理员权限
if (!isAdmin()) {
header('Location: login.php');
exit;
}
$pdo = getDBConnection();
// 获取反馈列表
$stmt = $pdo->query("SELECT f.*, u.username
FROM feedback f
LEFT JOIN users u ON f.user_id = u.id
ORDER BY f.created_at DESC");
$feedbacks = $stmt->fetchAll();
// 处理回复提交
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['reply'])) {
$feedbackId = $_POST['feedback_id'];
$replyContent = $_POST['reply_content'];
$stmt = $pdo->prepare("UPDATE feedback SET
admin_reply = ?,
status = 2,
updated_at = NOW()
WHERE id = ?");
$stmt->execute([$replyContent, $feedbackId]);
// 记录日志
$logStmt = $pdo->prepare("INSERT INTO feedback_log
(feedback_id, action, operator, remark)
VALUES (?, 'reply', ?, ?)");
$logStmt->execute([$feedbackId, $_SESSION['admin_id'], '管理员回复']);
header('Location: admin_feedback.php?msg=回复成功');
exit;
}
?>
<!DOCTYPE html>
<html>
<head>反馈管理</title>
<style>
.feedback-card { border: 1px solid #ddd; padding: 15px; margin: 10px 0; }
.status-badge { padding: 3px 8px; border-radius: 3px; }
.status-pending { background: #ffc107; }
.status-processing { background: #17a2b8; color: white; }
.status-resolved { background: #28a745; color: white; }
.status-closed { background: #6c757d; color: white; }
</style>
</head>
<body>
<h2>用户反馈管理</h2>
<div class="filter-bar">
<select id="statusFilter" onchange="filterFeedbacks()">
<option value="">全部状态</option>
<option value="0">待处理</option>
<option value="1">处理中</option>
<option value="2">已解决</option>
<option value="3">已关闭</option>
</select>
</div>
<?php foreach ($feedbacks as $feedback): ?>
<div class="feedback-card" data-status="<?= $feedback['status'] ?>">
<div class="feedback-header">
<span class="status-badge status-<?=
['pending', 'processing', 'resolved', 'closed'][$feedback['status']]
?>">
<?= ['待处理', '处理中', '已解决', '已关闭'][$feedback['status']] ?>
</span>
<span>用户:<?= htmlspecialchars($feedback['username'] ?: '匿名') ?></span>
<span>时间:<?= $feedback['created_at'] ?></span>
</div>
<h3><?= htmlspecialchars($feedback['title']) ?></h3>
<p><?= nl2br(htmlspecialchars($feedback['content'])) ?></p>
<?php if ($feedback['screenshot']): ?>
<div class="screenshot">
<img src="<?= $feedback['screenshot'] ?>" alt="截图" style="max-width: 300px;">
</div>
<?php endif; ?>
<?php if ($feedback['admin_reply']): ?>
<div class="reply-box">
<h4>管理员回复:</h4>
<p><?= nl2br(htmlspecialchars($feedback['admin_reply'])) ?></p>
</div>
<?php endif; ?>
<div class="actions">
<form method="post" class="reply-form">
<input type="hidden" name="feedback_id" value="<?= $feedback['id'] ?>">
<textarea name="reply_content" placeholder="输入回复内容" required></textarea>
<button type="submit" name="reply">回复并解决</button>
</form>
<button onclick="changeStatus(<?= $feedback['id'] ?>, 1)">标记处理中</button>
<button onclick="changeStatus(<?= $feedback['id'] ?>, 3)">关闭</button>
</div>
</div>
<?php endforeach; ?>
<script>
function changeStatus(id, status) {
if (!confirm('确认修改状态?')) return;
fetch('update_feedback_status.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({id: id, status: status})
}).then(response => response.json()).then(data => {
if (data.success) location.reload();
});
}
function filterFeedbacks() {
const status = document.getElementById('statusFilter').value;
document.querySelectorAll('.feedback-card').forEach(card => {
if (!status || card.dataset.status === status) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
</script>
</body>
</html>
电子邮件通知
send_notification.php
<?php
function sendFeedbackNotification($feedbackId, $type) {
$adminEmail = 'admin@example.com';
$subject = '新的用户反馈通知';
$message = "收到新的用户反馈 #{$feedbackId}\n";
$message .= "类型:" . getFeedbackType($type) . "\n";
$message .= "请在后台查看详情。";
mail($adminEmail, $subject, $message);
}
function sendReplyNotification($userEmail, $feedbackTitle) {
$subject = '您的反馈已收到回复';
$message = "您关于「{$feedbackTitle}」的反馈已收到回复,请查看。";
mail($userEmail, $subject, $message);
}
状态更新API
update_feedback_status.php
<?php
session_start();
header('Content-Type: application/json');
require_once 'config.php';
require_once 'functions.php';
// 验证管理员权限
if (!isAdmin()) {
echo json_encode(['success' => false, 'message' => '无权限']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
try {
$pdo = getDBConnection();
$stmt = $pdo->prepare("UPDATE feedback SET
status = ?,
updated_at = NOW()
WHERE id = ?");
$stmt->execute([$input['status'], $input['id']]);
// 记录日志
$logStmt = $pdo->prepare("INSERT INTO feedback_log
(feedback_id, action, operator, remark)
VALUES (?, 'status_change', ?, ?)");
$statusNames = ['待处理', '处理中', '已解决', '已关闭'];
$logStmt->execute([
$input['id'],
$_SESSION['admin_id'],
"状态变更为:{$statusNames[$input['status']]}"
]);
echo json_encode(['success' => true]);
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
配置文件
config.php
<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_NAME', 'feedback_system');
define('DB_USER', 'root');
define('DB_PASS', '');
// 邮件配置
define('SMTP_HOST', 'smtp.example.com');
define('SMTP_PORT', 587);
define('SMTP_USER', 'noreply@example.com');
define('SMTP_PASS', 'password');
// 文件上传配置
define('MAX_FILE_SIZE', 5 * 1024 * 1024); // 5MB
define('ALLOWED_EXTENSIONS', ['jpg', 'jpeg', 'png', 'gif']);
function getDBConnection() {
try {
$pdo = new PDO(
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
DB_USER,
DB_PASS,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
return $pdo;
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
}
安全建议
- CSRF防护:添加CSRF token验证
- XSS防护:输出时使用
htmlspecialchars() - 文件上传安全:验证文件类型和大小
- SQL注入防护:使用预处理语句
- 访问控制:后台管理需要权限验证
- 数据验证:前后端都要验证输入数据
这个方案提供了完整的用户反馈处理流程,包括提交、存储、回复和状态管理,可以根据实际需求进行扩展,比如添加邮件通知、微信通知、数据分析等功能。