如何用PHP项目搭建投票系统?

wen PHP项目 1

本文目录导读:

如何用PHP项目搭建投票系统?

  1. 系统基础架构
  2. 核心功能实现
  3. 前端界面示例
  4. 安全防护措施
  5. 进阶功能扩展
  6. 部署建议

我来帮你规划一个PHP投票系统的搭建方案,这是一个相对完整的系统设计,我会从基础架构到核心功能逐步说明。

系统基础架构

环境要求

- PHP 7.4+
- MySQL 5.7+ 
- Web服务器:Apache/Nginx
- 推荐框架:Laravel/ThinkPHP(或原生PHP)

数据库设计

-- 投票主题表
CREATE TABLE `votes` (
  `id` int(11) NOT NULL AUTO_INCREMENT, varchar(200) NOT NULL COMMENT '投票标题',
  `description` text COMMENT '投票描述',
  `type` tinyint(1) DEFAULT '0' COMMENT '0单选 1多选',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `status` tinyint(1) DEFAULT '1' COMMENT '0关闭 1开启',
  `created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);
-- 投票选项表
CREATE TABLE `vote_options` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `vote_id` int(11) NOT NULL,
  `option_name` varchar(100) NOT NULL COMMENT '选项名称',
  `votes_count` int(11) DEFAULT '0' COMMENT '得票数',
  `sort_order` int(3) DEFAULT '0' COMMENT '排序',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`vote_id`) REFERENCES `votes`(`id`) ON DELETE CASCADE
);
-- 投票记录表
CREATE TABLE `vote_records` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `vote_id` int(11) NOT NULL,
  `option_id` int(11) NOT NULL,
  `user_id` int(11) COMMENT '用户ID(可空,匿名投票)',
  `ip_address` varchar(45) COMMENT 'IP地址(防刷票)',
  `created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_vote` (`vote_id`, `user_id`, `ip_address`)
);

核心功能实现

创建投票(Create.php)

<?php
// 简单原生PHP示例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = $_POST['title'];
    $options = $_POST['options']; // 数组
    $type = $_POST['type'];
    $start_time = $_POST['start_time'];
    $end_time = $_POST['end_time'];
    // 开启事务
    $conn->begin_transaction();
    try {
        // 插入投票主表
        $stmt = $conn->prepare("INSERT INTO votes (title, description, type, start_time, end_time) VALUES (?, ?, ?, ?, ?)");
        $stmt->bind_param("ssiss", $title, $description, $type, $start_time, $end_time);
        $stmt->execute();
        $vote_id = $conn->insert_id;
        // 插入选项
        $stmt = $conn->prepare("INSERT INTO vote_options (vote_id, option_name, sort_order) VALUES (?, ?, ?)");
        $order = 1;
        foreach ($options as $option) {
            $stmt->bind_param("isi", $vote_id, $option, $order++);
            $stmt->execute();
        }
        $conn->commit();
        echo json_encode(['success' => true, 'vote_id' => $vote_id]);
    } catch (Exception $e) {
        $conn->rollback();
        echo json_encode(['success' => false, 'error' => $e->getMessage()]);
    }
}

投票功能(Vote.php)

<?php
function castVote($vote_id, $option_ids, $user_info) {
    // 1. 验证投票是否有效
    $vote = checkVoteValid($vote_id);
    if (!$vote) {
        return ['error' => '投票已结束或不存在'];
    }
    // 2. 检查是否已投票(防止重复)
    if (checkAlreadyVoted($vote_id, $user_info)) {
        return ['error' => '您已经投过票了'];
    }
    // 3. 验证选项数量(单选/多选)
    if ($vote['type'] == 0 && count($option_ids) > 1) {
        return ['error' => '此为单选投票'];
    }
    // 4. 记录投票
    $conn->begin_transaction();
    try {
        foreach ($option_ids as $option_id) {
            // 插入投票记录
            $stmt = $conn->prepare("INSERT INTO vote_records (vote_id, option_id, user_id, ip_address) VALUES (?, ?, ?, ?)");
            $stmt->bind_param("iiis", $vote_id, $option_id, $user_info['id'], $_SERVER['REMOTE_ADDR']);
            $stmt->execute();
            // 更新选项得票数
            $conn->query("UPDATE vote_options SET votes_count = votes_count + 1 WHERE id = $option_id");
        }
        $conn->commit();
        return ['success' => true];
    } catch (Exception $e) {
        $conn->rollback();
        return ['error' => '投票失败,请重试'];
    }
}

查看结果(Results.php)

<?php
// 获取投票结果
function getVoteResults($vote_id) {
    $vote = $conn->query("SELECT * FROM votes WHERE id = $vote_id")->fetch_assoc();
    // 获取各选项得票
    $options = $conn->query("
        SELECT vo.*, 
               (vo.votes_count / total.total_votes * 100) as percentage
        FROM vote_options vo
        CROSS JOIN (
            SELECT SUM(votes_count) as total_votes 
            FROM vote_options 
            WHERE vote_id = $vote_id
        ) total
        WHERE vo.vote_id = $vote_id
        ORDER BY vo.sort_order
    ");
    // 总投票人数
    $total_voters = $conn->query("
        SELECT COUNT(DISTINCT user_id) as voters 
        FROM vote_records 
        WHERE vote_id = $vote_id
    ")->fetch_assoc()['voters'];
    return [
        'vote' => $vote,
        'options' => $options,
        'total_voters' => $total_voters
    ];
}

前端界面示例

<!-- 投票表单 -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">投票系统</title>
    <style>
        .vote-container {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
        }
        .vote-item {
            margin: 10px 0;
            padding: 10px;
            border: 1px solid #ddd;
        }
        .progress-bar {
            height: 20px;
            background: #e0e0e0;
            border-radius: 10px;
            overflow: hidden;
        }
        .progress-fill {
            height: 100%;
            background: #4CAF50;
            transition: width 0.3s;
        }
        .btn-vote {
            background: #007bff;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="vote-container">
        <!-- 投票表单 -->
        <form id="voteForm" onsubmit="submitVote(event)">
            <h2>你最喜欢的编程语言是?</h2>
            <div class="vote-item">
                <label>
                    <input type="radio" name="option" value="1" required>
                    PHP
                </label>
            </div>
            <div class="vote-item">
                <label>
                    <input type="radio" name="option" value="2">
                    JavaScript
                </label>
            </div>
            <div class="vote-item">
                <label>
                    <input type="radio" name="option" value="3">
                    Python
                </label>
            </div>
            <button type="submit" class="btn-vote">提交投票</button>
        </form>
        <!-- 实时结果 -->
        <div id="results">
            <h3>当前结果</h3>
            <div class="vote-item">
                <span>PHP</span>
                <div class="progress-bar">
                    <div class="progress-fill" style="width: 45%;">45%</div>
                </div>
                <span>45票</span>
            </div>
            <!-- 更多选项... -->
        </div>
    </div>
    <script>
    function submitVote(event) {
        event.preventDefault();
        const formData = new FormData(event.target);
        fetch('vote.php', {
            method: 'POST',
            body: formData
        })
        .then(response => response.json())
        .then(data => {
            if(data.success) {
                alert('投票成功!');
                loadResults(); // 刷新结果
            } else {
                alert(data.error || '投票失败');
            }
        });
    }
    function loadResults() {
        fetch('results.php?vote_id=1')
        .then(response => response.json())
        .then(data => {
            // 更新结果展示
            updateDisplay(data);
        });
    }
    // 自动刷新(每10秒)
    setInterval(loadResults, 10000);
    </script>
</body>
</html>

安全防护措施

防刷票机制

// IP限制
function checkIPLimit($vote_id) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $time_limit = date('Y-m-d H:i:s', strtotime('-1 hour'));
    $count = $conn->query("
        SELECT COUNT(*) as cnt 
        FROM vote_records 
        WHERE vote_id = $vote_id 
        AND ip_address = '$ip' 
        AND created_at > '$time_limit'
    ")->fetch_assoc()['cnt'];
    return $count < 3; // 每小时最多3次
}
// 验证码(Google reCAPTCHA)
function verifyCaptcha($token) {
    $secret = 'YOUR_SECRET_KEY';
    $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=$token");
    $data = json_decode($response);
    return $data->success;
}

SQL注入防护

// 使用预处理语句
$stmt = $conn->prepare("SELECT * FROM votes WHERE id = ?");
$stmt->bind_param("i", $vote_id);
$stmt->execute();
// 输入过滤
$title = htmlspecialchars(strip_tags($_POST['title']), ENT_QUOTES, 'UTF-8');

进阶功能扩展

  1. 用户系统集成:对接用户登录体系,支持实名投票
  2. 多语言支持:使用gettext或PHP数组实现国际化
  3. 图表展示:集成Chart.js或ECharts生成可视化结果
  4. 定时任务:使用cron或Laravel Task Scheduling自动关闭投票
  5. 数据分析:记录投票时间分布,分析用户行为
  6. 导出功能:支持CSV/Excel导出投票数据

部署建议

# Nginx配置示例
server {
    listen 80;
    server_name vote.yourdomain.com;
    root /var/www/vote-system/public;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

这个方案涵盖了一个完整投票系统的基本功能,根据实际需求,你可以选择使用框架(推荐Laravel)来快速开发,或者基于原生PHP构建轻量级系统,记得在生产环境中做好性能优化和安全防护。

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