PHP 实例 – AJAX 投票

关键要点

  • AJAX 投票:通过 AJAX 技术结合 PHP 和 MySQL,实现用户投票并实时更新结果,无需刷新页面,研究表明这提升了用户交互性和体验。
  • 工作流程:JavaScript 发送投票请求到 PHP,PHP 更新 MySQL 数据库并返回结果,客户端动态显示投票统计。
  • 注意事项:需防范重复投票(通过会话或 IP 限制),统一 UTF-8 编码避免中文乱码,处理跨域(CORS)和安全问题(如 SQL 注入、XSS)。

PHP 实例:AJAX 投票

简介

AJAX 投票是一种动态 Web 应用,允许用户通过选择选项进行投票,AJAX 异步发送请求到 PHP,PHP 更新 MySQL 数据库中的投票计数并返回结果,客户端实时更新投票统计。本实例展示如何使用 AJAX、PHP 和 MySQL 实现一个简单的投票系统,用户选择选项后立即看到更新后的投票结果。

示例场景

创建一个投票页面,用户选择喜欢的编程语言(PHP、Python、Java),点击投票后,AJAX 向 PHP 发送请求,PHP 更新数据库并返回投票统计,JavaScript 动态显示结果(如柱状图或百分比)。


完整示例代码

1. MySQL 数据库设置

创建一个数据库 poll_db 和表 poll 用于存储投票选项和计数:

CREATE DATABASE poll_db;
USE poll_db;
CREATE TABLE poll (
    id INT AUTO_INCREMENT PRIMARY KEY,
    option_name VARCHAR(50) NOT NULL,
    votes INT DEFAULT 0
);
INSERT INTO poll (option_name, votes) VALUES 
    ('PHP', 0),
    ('Python', 0),
    ('Java', 0);

2. 前端(index.html)

HTML 和 JavaScript 代码,用于显示投票选项、触发 AJAX 请求并更新结果:

<!DOCTYPE html>
<html>
<head>
    <title>PHP - AJAX 投票</title>
    <meta charset="UTF-8">
    <style>
        #poll { margin: 20px; }
        .option { margin: 10px 0; }
        #results { margin-top: 20px; border: 1px solid #ccc; padding: 10px; }
        .result-item { margin: 5px 0; }
        .bar { background-color: #4CAF50; height: 20px; margin-top: 5px; }
    </style>
</head>
<body>
    <h2>AJAX 投票系统</h2>
    <div id="poll">
        <p>选择您喜欢的编程语言:</p>
        <div class="option">
            <input type="radio" name="vote" value="PHP"> PHP
        </div>
        <div class="option">
            <input type="radio" name="vote" value="Python"> Python
        </div>
        <div class="option">
            <input type="radio" name="vote" value="Java"> Java
        </div>
        <button onclick="submitVote()">投票</button>
    </div>
    <div id="results"></div>

    <script>
        function submitVote() {
            const selectedOption = document.querySelector('input[name="vote"]:checked');
            if (!selectedOption) {
                alert("请选择一个选项!");
                return;
            }
            const option = selectedOption.value;
            fetch("vote.php", {
                method: "POST",
                headers: { "Content-Type": "application/x-www-form-urlencoded" },
                body: "option=" + encodeURIComponent(option)
            })
            .then(response => response.json())
            .then(data => {
                if (data.error) {
                    document.getElementById("results").innerHTML = `<p>${data.error}</p>`;
                    return;
                }
                let html = "<h3>投票结果</h3>";
                const totalVotes = data.reduce((sum, item) => sum + item.votes, 0);
                data.forEach(item => {
                    const percentage = totalVotes ? ((item.votes / totalVotes) * 100).toFixed(1) : 0;
                    html += `
                        <div class="result-item">
                            ${item.option_name}: ${item.votes} 票 (${percentage}%)
                            <div class="bar" style="width: ${percentage}%"></div>
                        </div>`;
                });
                document.getElementById("results").innerHTML = html;
            })
            .catch(error => {
                console.error("错误:", error);
                document.getElementById("results").innerHTML = "<p>投票失败</p>";
            });
        }
    </script>
</body>
</html>

3. 后端 PHP 脚本(vote.php)

PHP 脚本接收投票选项,更新 MySQL 数据库,返回投票统计:

<?php
header('Content-Type: application/json; charset=utf-8');
session_start();

// 防止重复投票
if (isset($_SESSION['hasVoted'])) {
    echo json_encode(['error' => '您已经投过票了!']);
    exit;
}

// 数据库连接
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "poll_db";

$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
    echo json_encode(['error' => '数据库连接失败']);
    exit;
}
mysqli_set_charset($conn, "utf8");

// 获取投票选项并防止 SQL 注入
$option = isset($_POST['option']) ? $conn->real_escape_string($_POST['option']) : '';
if (!$option) {
    echo json_encode(['error' => '无效的投票选项']);
    exit;
}

// 更新投票计数
$sql = "UPDATE poll SET votes = votes + 1 WHERE option_name = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $option);
$stmt->execute();

// 标记用户已投票
$_SESSION['hasVoted'] = true;

// 获取投票统计
$sql = "SELECT option_name, votes FROM poll";
$result = $conn->query($sql);
$results = [];
while ($row = $result->fetch_assoc()) {
    $results[] = $row;
}

echo json_encode($results);

$stmt->close();
$conn->close();
?>

运行环境设置

  1. 服务器环境:确保运行 PHP 的 Web 服务器(如 Apache 或 Nginx),支持 PHP 7.0 或以上,MySQL 数据库已配置。
  2. 文件放置:将 index.htmlvote.php 放在 Web 服务器的同一目录下。
  3. 数据库配置:在 vote.php 中更新数据库连接参数($servername$username$password$dbname)。
  4. 测试:在浏览器访问 index.html,选择一个选项,点击“投票”按钮,查看实时更新的投票结果。

示例输出

选择“PHP”并投票后,页面可能显示:

投票结果
PHP: 1 票 (50.0%)
[绿色进度条,宽度 50%]
Python: 0 票 (0.0%)
[绿色进度条,宽度 0%]
Java: 1 票 (50.0%)
[绿色进度条,宽度 50%]

技术分析

工作原理

  1. 用户交互:用户选择投票选项并点击“投票”按钮,触发 JavaScript 的 submitVote() 函数。
  2. AJAX 请求:使用 Fetch API 发送 POST 请求到 vote.php,携带投票选项。
  3. PHP 处理:PHP 检查是否重复投票,连接 MySQL,更新投票计数,返回所有选项的投票统计(JSON 格式)。
  4. 客户端更新:JavaScript 解析 JSON 响应,计算百分比,动态渲染结果和进度条。

注意事项

  • 中文字符编码:研究表明,中文字符可能导致乱码,需确保 HTML、PHP 和 MySQL 均使用 UTF-8 编码:
  • HTML:<meta charset="UTF-8">
  • PHP:header('Content-Type: application/json; charset=utf-8')
  • MySQL:mysqli_set_charset($conn, "utf8")
  • 重复投票:通过 session_start()$_SESSION['hasVoted'] 防止同一用户重复投票。也可使用 IP 地址或数据库记录用户投票。
  • 跨域问题(CORS):若 AJAX 请求跨域,需在 PHP 添加 CORS 头:
  header('Access-Control-Allow-Origin: *');
  header('Access-Control-Allow-Methods: POST');
  • 安全性
  • SQL 注入:使用预处理语句(mysqli_prepare)或 real_escape_string() 防止注入。
  • XSS 攻击:对输出数据(如 option_name)使用 htmlspecialchars() 过滤。
    php $results[] = [ 'option_name' => htmlspecialchars($row['option_name']), 'votes' => $row['votes'] ];
  • CSRF 攻击:可添加 CSRF 令牌验证,防止恶意请求。
  • 性能:对于高流量投票,建议使用数据库索引和缓存(如 Redis)优化查询性能。

改进版本:结合 jQuery

以下是使用 jQuery 实现的 AJAX 投票系统,简化 AJAX 操作:

前端(index.html)

<!DOCTYPE html>
<html>
<head>
    <title>PHP - AJAX 投票 (jQuery)</title>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        #poll { margin: 20px; }
        .option { margin: 10px 0; }
        #results { margin-top: 20px; border: 1px solid #ccc; padding: 10px; }
        .result-item { margin: 5px 0; }
        .bar { background-color: #4CAF50; height: 20px; margin-top: 5px; }
    </style>
</head>
<body>
    <h2>AJAX 投票系统 (jQuery)</h2>
    <div id="poll">
        <p>选择您喜欢的编程语言:</p>
        <div class="option">
            <input type="radio" name="vote" value="PHP"> PHP
        </div>
        <div class="option">
            <input type="radio" name="vote" value="Python"> Python
        </div>
        <div class="option">
            <input type="radio" name="vote" value="Java"> Java
        </div>
        <button id="voteButton">投票</button>
    </div>
    <div id="results"></div>

    <script>
        $(document).ready(function() {
            $("#voteButton").click(function() {
                const selectedOption = $("input[name='vote']:checked").val();
                if (!selectedOption) {
                    alert("请选择一个选项!");
                    return;
                }
                $.ajax({
                    url: "vote.php",
                    type: "POST",
                    data: { option: selectedOption },
                    dataType: "json",
                    success: function(data) {
                        let html = "<h3>投票结果</h3>";
                        if (data.error) {
                            html = `<p>${data.error}</p>`;
                        } else {
                            const totalVotes = data.reduce((sum, item) => sum + item.votes, 0);
                            data.forEach(item => {
                                const percentage = totalVotes ? ((item.votes / totalVotes) * 100).toFixed(1) : 0;
                                html += `
                                    <div class="result-item">
                                        ${item.option_name}: ${item.votes} 票 (${percentage}%)
                                        <div class="bar" style="width: ${percentage}%"></div>
                                    </div>`;
                            });
                        }
                        $("#results").html(html);
                    },
                    error: function() {
                        $("#results").html("<p>投票失败</p>");
                    }
                });
            });
        });
    </script>
</body>
</html>

后端(vote.php):保持不变。

对比表:AJAX 实现方式

方法优点缺点适用场景
XMLHttpRequest广泛支持,控制力强代码复杂,调试稍麻烦传统 AJAX 应用
Fetch API现代 API,语法简洁,支持 Promise旧浏览器支持有限现代 Web 应用
jQuery AJAX简单易用,跨浏览器兼容性好依赖 jQuery 库,增加加载时间快速开发,传统项目

优势与局限性

  • 优势
  • 实时更新投票结果,提升用户体验。
  • JSON 格式轻量,易于解析。
  • PHP 和 MySQL 支持复杂投票逻辑。
  • 局限性
  • 需防止重复投票(如通过会话或 IP)。
  • 跨域请求需配置 CORS。
  • 安全性需关注,如 SQL 注入和 XSS。

学习建议

未来趋势与展望

研究表明,AJAX 投票是动态 Web 应用的典型案例,未来 Fetch API 和 WebSocket 将进一步优化实时交互。PHP 开发者应关注 RESTful API 设计和安全最佳实践,以应对高流量投票场景。

结论

通过 AJAX、PHP 和 MySQL 实现的投票系统,允许用户投票并实时查看结果。本实例展示了如何使用 Fetch API 和 PHP 的 MySQLi 扩展完成投票功能,注意编码一致性、重复投票防范和安全性。jQuery 提供了更简洁的替代方案,适合快速开发。

引用来源:

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注