PHP项目如何实现留言反馈功能?

wen PHP项目 10

本文目录导读:

PHP项目如何实现留言反馈功能?

  1. 数据库设计
  2. 数据库连接类
  3. 提交留言页面
  4. 处理留言提交
  5. 留言列表展示
  6. 管理员后台回复
  7. 关键安全措施
  8. 可选功能扩展

我来详细介绍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攻击等。

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