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
相关产品推荐
相关产品推荐

