PHP随机数生成器与$_POST对比验证失效问题排查
解决PHP表单反垃圾随机数验证失效的问题
咱先搞明白为啥会出这问题哈——你的随机数生成逻辑在页面加载和表单提交时会重新生成新值,导致验证时对比的根本不是用户看到的那组数字之和!
举个例子:用户打开页面时,生成的是3+5=8,用户输入8提交;这时候页面重新执行PHP代码,又生成了2+4=6,然后拿6去对比用户输入的8,那肯定提示错误啊!
给你俩靠谱的解决方案,按需选就行:
方案一:用Session存储正确答案(更安全)
这种方法会把用户看到的那组数字的和存在服务器端的Session里,提交时用这个存储的值验证,不会被用户篡改。
步骤:
- 在所有PHP代码最顶部开启Session(必须放在任何输出之前)
- 生成随机数时,把数字和正确的和存入Session,避免刷新页面就变题
- 验证时用Session里的正确和对比用户输入的值
代码修改:
首先加Session初始化:
session_start(); // 一定要放在PHP代码最开头,不能有任何HTML输出之前
然后修改随机数生成逻辑:
// 只有当Session里没存题的时候才生成新题 if (!isset($_SESSION['correct_sum'])) { $num1 = mt_rand(1, 9); $num2 = mt_rand(1, 9); $_SESSION['num1'] = $num1; $_SESSION['num2'] = $num2; $_SESSION['correct_sum'] = $num1 + $num2; $str1 = (string) $num1; $str2 = (string) $num2; } else { // 如果已经有存的题,就用之前的数字显示 $num1 = $_SESSION['num1']; $num2 = $_SESSION['num2']; $str1 = (string) $num1; $str2 = (string) $num2; }
最后修改验证逻辑:
if (isset($_POST["submit"])) { $name = $_POST['name']; $email = $_POST['email']; $message = $_POST['message']; $human = intval($_POST['human']); $from = 'STEM and Buds Contact Form'; $to = 'saifanchey@gmail.com'; $subject = $_POST['subject']; $reason = $_POST['reason']; // 用Session里的正确和验证 if ($human !== $_SESSION['correct_sum']) { $errHuman = 'Your anti-spam is incorrect'; } // 验证完可以销毁Session里的值,避免用户刷新后重复用同一道题 unset($_SESSION['correct_sum'], $_SESSION['num1'], $_SESSION['num2']); }
方案二:用隐藏表单字段存储正确答案(更简单)
这种方法直接把正确的和放在表单的隐藏字段里,提交时一起传回来验证,优点是不用折腾Session,缺点是懂点前端的用户能通过查看源码看到答案,但对付普通垃圾机器人足够了。
代码修改:
在HTML的验证输入框旁边加一个隐藏字段:
<div class="form-group"> <label for="human" class="col-sm-2 control-label"><?php echo $str1 . " + " . $str2 . " = ?"; ?></label> <div class="col-sm-10"> <input type="text" class="form-control" id="human" name="human" placeholder="Your Answer"> <!-- 添加这个隐藏字段存正确的和 --> <input type="hidden" name="correct_sum" value="<?php echo $sum; ?>"> <?php echo "<p class='text-danger'>$errHuman</p>"; ?> </div> </div>
然后修改验证逻辑:
if (isset($_POST["submit"])) { $name = $_POST['name']; $email = $_POST['email']; $message = $_POST['message']; $human = intval($_POST['human']); // 获取隐藏字段里的正确和 $correct_sum = intval($_POST['correct_sum']); $from = 'STEM and Buds Contact Form'; $to = 'saifanchey@gmail.com'; $subject = $_POST['subject']; $reason = $_POST['reason']; // 用隐藏字段的值验证 if ($human !== $correct_sum) { $errHuman = 'Your anti-spam is incorrect'; } }
选哪个方案看你的需求,追求安全选Session,图省事选隐藏字段,两种都能解决你现在的问题~
内容的提问来源于stack exchange,提问作者Saif Ali
相关产品推荐
相关产品推荐

