PHP项目如何实现用户满意度调查?

wen java案例 1

本文目录导读:

PHP项目如何实现用户满意度调查?

  1. 数据库设计(MySQL / PostgreSQL)
  2. 后端核心逻辑(PHP)
  3. 前端展示(HTML + JavaScript + AJAX)
  4. 结果统计与分析(后台管理)
  5. 增强功能建议
  6. 完整项目结构示例
  7. 安全注意事项
  8. 第三方库(可选)

在PHP项目中实现用户满意度调查,通常需要涵盖前端展示后端逻辑数据存储结果分析四个部分,以下是完整的实现方案:


数据库设计(MySQL / PostgreSQL)

首先创建一个调查表和反馈记录表。

-- 调查问卷表
CREATE TABLE surveys (
    id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,          -- 调查标题
    description TEXT,                     -- 描述
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at DATETIME NULL,             -- 过期时间(可选)
    status TINYINT DEFAULT 1              -- 1=启用 0=禁用
);
-- 调查问题表
CREATE TABLE survey_questions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    survey_id INT NOT NULL,
    question_text TEXT NOT NULL,          -- 问题内容
    question_type VARCHAR(50) NOT NULL,   -- rating(评分), radio(单选), text(文本)
    options JSON NULL,                    -- 选项(JSON格式,如["1分","2分","3分"])
    sort_order INT DEFAULT 0,
    FOREIGN KEY (survey_id) REFERENCES surveys(id) ON DELETE CASCADE
);
-- 用户反馈记录表
CREATE TABLE survey_responses (
    id INT AUTO_INCREMENT PRIMARY KEY,
    survey_id INT NOT NULL,
    user_id INT NULL,                     -- 可选:关联用户(匿名则不填)
    ip_address VARCHAR(45) NULL,          -- 防止刷票
    submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (survey_id) REFERENCES surveys(id) ON DELETE CASCADE
);
-- 问题答案表(一对多:一条反馈对应多个答案)
CREATE TABLE survey_answers (
    id INT AUTO_INCREMENT PRIMARY KEY,
    response_id INT NOT NULL,
    question_id INT NOT NULL,
    answer_value TEXT,                    -- 答案值(评分值/选项文本/用户输入)
    FOREIGN KEY (response_id) REFERENCES survey_responses(id) ON DELETE CASCADE,
    FOREIGN KEY (question_id) REFERENCES survey_questions(id) ON DELETE CASCADE
);

后端核心逻辑(PHP)

1 加载调查问卷

// get_survey.php
<?php
function getActiveSurvey(PDO $pdo) {
    $stmt = $pdo->prepare("
        SELECT * FROM surveys 
        WHERE status = 1 
          AND (expires_at IS NULL OR expires_at > NOW())
        ORDER BY created_at DESC 
        LIMIT 1
    ");
    $stmt->execute();
    $survey = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($survey) {
        // 获取问题列表
        $stmtQ = $pdo->prepare("
            SELECT * FROM survey_questions 
            WHERE survey_id = ? 
            ORDER BY sort_order ASC
        ");
        $stmtQ->execute([$survey['id']]);
        $survey['questions'] = $stmtQ->fetchAll(PDO::FETCH_ASSOC);
    }
    return $survey;
}

2 提交反馈

// submit_survey.php
<?php
session_start();
function submitFeedback(PDO $pdo, array $answers, int $surveyId, ?int $userId = null) {
    try {
        $pdo->beginTransaction();
        // 1. 记录反馈
        $ip = $_SERVER['REMOTE_ADDR'] ?? null;
        $stmt = $pdo->prepare("
            INSERT INTO survey_responses (survey_id, user_id, ip_address) 
            VALUES (?, ?, ?)
        ");
        $stmt->execute([$surveyId, $userId, $ip]);
        $responseId = $pdo->lastInsertId();
        // 2. 逐条保存答案
        $answerStmt = $pdo->prepare("
            INSERT INTO survey_answers (response_id, question_id, answer_value) 
            VALUES (?, ?, ?)
        ");
        foreach ($answers as $questionId => $value) {
            $answerStmt->execute([$responseId, $questionId, $value]);
        }
        $pdo->commit();
        return ['success' => true, 'response_id' => $responseId];
    } catch (Exception $e) {
        $pdo->rollBack();
        return ['success' => false, 'error' => $e->getMessage()];
    }
}

3 防止重复提交(示例)

// 在提交函数前检查(基于IP+用户ID+时间窗口)
function canSubmit(PDO $pdo, int $surveyId, ?int $userId, string $ip): bool {
    $minInterval = 60 * 60; // 1小时
    $stmt = $pdo->prepare("
        SELECT COUNT(*) FROM survey_responses 
        WHERE survey_id = ? 
          AND (user_id = ? OR ip_address = ?)
          AND submitted_at > DATE_SUB(NOW(), INTERVAL ? SECOND)
    ");
    $stmt->execute([$surveyId, $userId, $ip, $minInterval]);
    return $stmt->fetchColumn() == 0;
}

前端展示(HTML + JavaScript + AJAX)

1 问卷页面(异步加载)

<!DOCTYPE html>
<html>
<head>满意度调查</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="survey-container"></div>
<script>
$(document).ready(function() {
    $.get('api/get_survey.php', function(response) {
        if (response.error) {
            $('#survey-container').html('<p>暂无调查问卷</p>');
            return;
        }
        let html = `<h2>${response.title}</h2>
                    <p>${response.description}</p>
                    <form id="survey-form">`;
        response.questions.forEach(function(q) {
            html += `<div class="question-block">
                        <label>${q.question_text}</label>`;
            if (q.question_type === 'rating') {
                // 1-5分评分
                html += '<div class="rating">';
                for (let i = 1; i <= 5; i++) {
                    html += `<input type="radio" name="q_${q.id}" value="${i}"> ${i}分 `;
                }
                html += '</div>';
            } else if (q.question_type === 'radio') {
                const options = JSON.parse(q.options);
                options.forEach(function(opt) {
                    html += `<label><input type="radio" name="q_${q.id}" value="${opt}"> ${opt}</label>`;
                });
            } else { // text
                html += `<textarea name="q_${q.id}" rows="3"></textarea>`;
            }
            html += '</div>';
        });
        html += '<button type="submit">提交反馈</button></form>';
        $('#survey-container').html(html);
    }, 'json');
    // 提交处理
    $(document).on('submit', '#survey-form', function(e) {
        e.preventDefault();
        const formData = $(this).serialize();
        $.post('api/submit_survey.php', formData, function(response) {
            if (response.success) {
                alert('感谢您的反馈!');
                $('#survey-container').html('<p>已提交,谢谢参与!</p>');
            } else {
                alert('提交失败:' + (response.error || '请稍后重试'));
            }
        }, 'json');
    });
});
</script>
</body>
</html>

结果统计与分析(后台管理)

// get_survey_stats.php
<?php
function getSurveyStats(PDO $pdo, int $surveyId): array {
    // 总参与人数
    $total = $pdo->prepare("SELECT COUNT(*) FROM survey_responses WHERE survey_id=?");
    $total->execute([$surveyId]);
    $stats['total_responses'] = $total->fetchColumn();
    // 每题统计
    $stmt = $pdo->prepare("
        SELECT q.id, q.question_text, q.question_type, q.options,
               a.answer_value
        FROM survey_questions q
        LEFT JOIN survey_answers a ON q.id = a.question_id
        WHERE q.survey_id = ?
    ");
    $stmt->execute([$surveyId]);
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // 按问题分组统计
    foreach ($results as $row) {
        $qid = $row['id'];
        if (!isset($stats['questions'][$qid])) {
            $stats['questions'][$qid] = [
                'text' => $row['question_text'],
                'type' => $row['question_type'],
                'counts' => [],
                'texts' => []  // 文本答案
            ];
        }
        $val = $row['answer_value'];
        if ($row['question_type'] === 'text') {
            $stats['questions'][$qid]['texts'][] = $val;
        } else {
            if (!isset($stats['questions'][$qid]['counts'][$val])) {
                $stats['questions'][$qid]['counts'][$val] = 0;
            }
            $stats['questions'][$qid]['counts'][$val]++;
        }
    }
    // 计算评分平均分(rating类型)
    foreach ($stats['questions'] as $qid => &$q) {
        if ($q['type'] === 'rating') {
            $sum = array_sum(array_map(function($v, $k) {
                return $v * $k;
            }, $q['counts'], array_keys($q['counts'])));
            $total = array_sum($q['counts']);
            $q['average'] = $total > 0 ? round($sum / $total, 2) : 0;
        }
    }
    return $stats;
}

增强功能建议

功能 实现思路
验证码 使用 google/recaptcha 或自定义验证码,在提交前验证
匿名模式 提交时移除user_id/IP记录,仅保留时间戳
分页/多页问卷 前端使用步骤切换,后端一次性提交所有数据
自动触发 在用户完成某个操作(如订单完成、客服结束)后,弹窗或自动跳转
报告导出 使用 PhpSpreadsheet 生成 Excel 或 CSV 文件

完整项目结构示例

project/
├── index.php          # 前端问卷页面
├── admin/
│   ├── stats.php      # 后台统计页面
│   └── export.php     # 数据导出
├── api/
│   ├── get_survey.php # 获取问卷接口
│   └── submit_survey.php # 提交反馈接口
├── includes/
│   ├── db.php         # 数据库连接
│   └── functions.php  # 公共函数
└── assets/
    └── styles.css     # 样式文件

安全注意事项

  • SQL注入:使用预处理语句(如 PDO 的 prepare + 参数绑定)
  • XSS攻击:输出答案时使用 htmlspecialchars() 转义
  • 重复提交:结合 IP + User-Agent + 时间窗口限制
  • CSRF保护:在表单中嵌入 Token 并验证
  • 数据加密:敏感信息(如用户ID)建议加密存储

第三方库(可选)

  • PHPphpmailer(发送调查邀请邮件)、mpdf(生成PDF报告)
  • 前端Chart.js(绘制统计图表)、Bootstrap(美化界面)

如果你需要更具体的代码实现(如带图表展示的统计页面或自动发送邮件提醒),欢迎继续追问!

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