You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP投票系统按钮提交异常:投票写入错误数据库ID求助

PHP投票系统投票按钮匹配错误问题的解决方法

问题描述

开发PHP投票系统时遇到bug:点击Vote按钮后,$_POST["submit$i"]会匹配到之前点击过的按钮对应的循环项,导致投票被错误写入其他数据库ID的请愿中。由于部分请愿的Status并非'in voting',无法直接把循环索引$i当作数据库操作的ID使用。

原代码如下:

<!DOCTYPE html>
<html>
<?php
include 'dbconn.php'; //sql db connection
$result = mysqli_query($conn,"SELECT * FROM `Petitions` WHERE `Status` = 'in voting' LIMIT 50");
$data = $result->fetch_all(MYSQLI_ASSOC);
$i = 1; // index of item in foreach
?>
<body>
    <div class="main">
    <div class="blank"></div>
    <?php foreach($data as $row): ?> //foreach
    <div class="petition">
        <div class="header">
            <?= htmlspecialchars($row['Title']) ?>
        </div>
        <div class="text">
            <?= htmlspecialchars($row['Text']) ?>
        </div>
        <div>
                <?php //function for button
                if (isset($_POST["submit$i"])) {
                    $iid = $row['id'];
                    $morevote = $row['Votes'] + 1;
                    $morevoted = mysqli_query($conn,"UPDATE `Petitions` SET `Votes`= $morevote WHERE `id` = $iid LIMIT 50");
                    $morevoted = mysqli_query($conn,"UPDATE `Petitions` SET `Votes`= $morevote WHERE `id` = $iid LIMIT 50");
                }
                ?>
            <form method="post" class="vote">
                        <input type="submit" name="submit<?php echo $i; ?>" value="Vote"/>
                    <?= htmlspecialchars($row['Votes']) ?>/<?= htmlspecialchars($row['Needed votes']) ?>
                    </form>
        </div>
        <div class="blank1"></div>  
       </div>
       <?php $i++;?>
       <?php endforeach ?>
           <div class="blank2"></div>
     </div>
</body>
</html>

问题根源

原代码依赖循环索引$i标识提交按钮,但$i只是页面渲染时的顺序编号,和数据库id没有绑定关系。如果后续有请愿的Status从'in voting'变为其他状态,下次页面加载时$i的编号会重新排序,导致之前的submit$i对应关系失效,点击按钮时就会匹配到错误的循环项,进而更新错误的数据库ID。

解决方案(隐藏字段法)

核心思路是让表单直接携带对应的数据库id,彻底摆脱对循环索引的依赖,同时修复原代码的SQL注入风险。

修改后的代码如下:

<!DOCTYPE html>
<html>
<?php
include 'dbconn.php'; //sql db connection

// 先处理投票提交逻辑,放在循环前避免重复执行
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['petition_id'])) {
    $petition_id = $_POST['petition_id'];
    // 用预处理语句防止SQL注入,同时只允许更新处于投票中的请愿
    $stmt = $conn->prepare("UPDATE `Petitions` SET `Votes` = `Votes` + 1 WHERE `id` = ? AND `Status` = 'in voting'");
    $stmt->bind_param("i", $petition_id);
    $stmt->execute();
    $stmt->close();
}

// 拉取处于投票中的请愿数据
$result = mysqli_query($conn,"SELECT * FROM `Petitions` WHERE `Status` = 'in voting' LIMIT 50");
$data = $result->fetch_all(MYSQLI_ASSOC);
?>
<body>
    <div class="main">
    <div class="blank"></div>
    <?php foreach($data as $row): ?>
    <div class="petition">
        <div class="header">
            <?= htmlspecialchars($row['Title']) ?>
        </div>
        <div class="text">
            <?= htmlspecialchars($row['Text']) ?>
        </div>
        <div>
            <form method="post" class="vote">
                <!-- 添加隐藏字段存储数据库ID,直接传递真实的请愿ID -->
                <input type="hidden" name="petition_id" value="<?= $row['id'] ?>">
                <input type="submit" name="vote_submit" value="Vote"/>
                <?= htmlspecialchars($row['Votes']) ?>/<?= htmlspecialchars($row['Needed votes']) ?>
            </form>
        </div>
        <div class="blank1"></div>  
    </div>
    <?php endforeach ?>
        <div class="blank2"></div>
    </div>
</body>
</html>

关键修改点

  • 将投票处理逻辑移到循环之前,避免每次循环重复执行判断和更新
  • 每个表单添加hidden字段petition_id,直接携带数据库真实id,彻底解决循环索引与数据库ID不匹配的问题
  • 使用MySQLi预处理语句替代直接拼接SQL,避免SQL注入风险
  • 更新SQL中增加Status = 'in voting'判断,确保只有当前处于投票状态的请愿才能被投票,避免无效操作
  • 提交按钮统一命名为vote_submit,不再依赖循环索引,简化提交判断逻辑

内容的提问来源于stack exchange,提问作者A1gg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:04:59