使用带有 php 的表单标记防止 Ajax 表单重复提交
Prevent Ajax form double submitting using form tokens with php
****更新****
我的代码似乎没有问题;因为使用完全相同的代码创建新文档完全有效。因此该文件可能已经以某种方式损坏。参见 。
我一辈子都找不到任何相关的问题。
基本上,我有一个通过 Ajax 发送到 php 流程页面的审核表格。验证后,将数据插入 mySQL 数据库。 Ajax 向用户发送信息,主要是错误。我需要一种方法来防止在服务器端使用 php.
进行多次提交
我试过使用没有 Ajax 的表单标记,但没有 Ajax。 $_SESSION
似乎没有转移到表单处理 php 页面。
问题...
$_SESSION['review_form_token']
根本不包含任何数据。如果我错误地打印会话数据,它根本不会打印任何东西!但是,我有一个使用会话的 php 验证码,它可以毫无问题地打印出来。当我在页面加载时设置会话时,它会按预期将令牌打印到隐藏的输入中。我不明白为什么表单令牌没有传递到表单进程。 session_start()
在两个文件上。我试过 ob_start()
无济于事。
请帮我调试一下。
这是我的简化设置...
index.php(在顶部):
<?php
session_start();
$reviewForm_token = md5(uniqid(rand(), true));
$_SESSION['review_form_token'] = $reviewForm_token;
?>
index.php - 表单(某处)
<form id="reviewform" method="post" novalidate>
<input type="text" class="form-control form-style name" name="firstname" size="15" maxlength="40" autocomplete="given-name">
<input type="text" class="form-control form-style name" name="lastname" size="15" maxlength="40" autocomplete="family-name">
<textarea class="form-control form-style" name="review" minlength="50" required></textarea>
<input type="text" class="form-control form-style" name="captcha" autocomplete="off" maxlength="6" required>
<img src="https://via.placeholder.com/200x60" id="captcha-review" alt="Review captcha image" width="200" height="60">
<input type="hidden" name="form_token" value="<?php echo $_SESSION['review_form_token']; ?>">
<button type="submit" name="submit" class="btn btn-primary submit float-right font">Send</button>
<button type="reset" class="btn btn-primary reset font">Reset</button>
</form> <!-- End form -->
index.php - Ajax(在文档底部)
$('#reviewform').submit(function(event) {
// Set some variables
var $this = this,
firstnameInput = $('input[name=firstname]', $this),
lastnameInput = $('input[name=lastname]', $this),
nameInput = $('input.name', $this),
ratingInput = $('input[name=StarRating]', $this),
ratingInputChecked = $('input[name=StarRating]:checked', $this),
stars = $('.star-rating', $this),
reviewInput = $('textarea[name=review]', $this),
captchaInput = $('input[name=captcha]', $this),
form_tokenInput = $('input[name=form_token]', $this),
submitButton = $("button.submit", $this);
// Get the form data
// Must relate to the name attribute...
var formData = {
'firstname': firstnameInput.val(),
'lastname': lastnameInput.val(),
'StarRating': ratingInputChecked.val(),
'review': reviewInput.val(),
'captcha': captchaInput.val(),
'form_token': form_tokenInput.val(),
};
// Process the form
$.ajax({
type: 'POST', // Define the type of HTTP verb we want to use (POST for our form)
url: 'formProcess-review.php', // The url where we want to POST
data: formData, // Our data object
dataType: 'json', // What type of data do we expect back from the server
encode: true
})
.done(function(data) {
// Here we will handle errors and validation messages
if (!data.success) {
// Handle errors for doublepost (form_token) ---------------
if (data.errors.doublepost) {
$('button', $this).parents('.form-row')
.append(label + data.errors.doublepost + '</label>')
.children('label.invalid').attr('id', 'doublepost-error');
}
} else {
// SUCCESS!!
// Thanks!
}
}); // End .done function
// Stop the form from submitting the normal way and refreshing the page
event.preventDefault();
}); // End .submit function
formProcess-review.php
<?php
session_start();
$errors = array(); // array to hold validation errors
$data = array(); // array to pass back data
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$StarRating = $_POST['StarRating'];
$review = $_POST['review'];
$captcha = $_POST['captcha'];
// Form Validation...
if ($_POST['form_token'] !== $_SESSION['review_form_token']) {
$errors['doublepost'] = 'You have already submitted your review, you can not resubmit. If you need to send another review, please reload the page.';
}
// return a response ===========================================================
// if there are any errors in our errors array, return a success boolean of false
if (!empty($errors)) {
// if there are items in our errors array, return those errors
$data['success'] = false;
$data['errors'] = $errors;
} else {
// if there are no errors process our form, then return a message
unset($_SESSION['review_form_token']);
// mySQL inserting data...
// show a message of success and provide a true success variable
$data['success'] = true;
$data['message'] = 'Success!';
}
// return all our data to an AJAX call
echo json_encode($data);
?>
尝试将此选项 'withCredentials' 添加到 ajax 调用:
$.ajax({
type: 'POST',
url: 'formProcess-review.php',
data: formData,
dataType: 'json',
encode: true,
xhrFields: {
withCredentials: true
}
}
可能是 ajax 调用没有将会话 cookie 发送到服务器。
我刚刚尝试了您的代码,Form Token 和 Session token 都在您的 formProcess-[=30= 上被正确捕获].你的代码一定是有其他问题导致的。
简化了Ajax 提交。
$.ajax({
type: 'POST',
url: 'formProcess-review.php',
data: formData,
dataType: 'json',
encode: true
})
.done(function(data) {
alert(data.message);
});
简化形式工艺-review.php
<?php
session_start();
$data['message'] = "Form token = ".$_POST['form_token']." Session value = ".$_SESSION['review_form_token'];
echo json_encode($data);
die();
?>
激励我用相同的代码创建一个全新的 index.php;这似乎工作。我不知道为什么或如何,但原始文件一定已经损坏,迫使它无法正常工作,但仍然让它出现在网络上(很奇怪,嗯?!)
我已经编辑了我的代码以使其更简单并且希望更好。
我在取消设置会话时遇到了问题,所以我现在在 index.php 中的 session_start();
之后直接调用 session_unset();
来取消设置 1 重新加载之前的任何先前会话。
虽然我做了这个改变,但很奇怪以前没有它也能工作。
****更新****
我的代码似乎没有问题;因为使用完全相同的代码创建新文档完全有效。因此该文件可能已经以某种方式损坏。参见
我一辈子都找不到任何相关的问题。 基本上,我有一个通过 Ajax 发送到 php 流程页面的审核表格。验证后,将数据插入 mySQL 数据库。 Ajax 向用户发送信息,主要是错误。我需要一种方法来防止在服务器端使用 php.
进行多次提交我试过使用没有 Ajax 的表单标记,但没有 Ajax。 $_SESSION
似乎没有转移到表单处理 php 页面。
问题...
$_SESSION['review_form_token']
根本不包含任何数据。如果我错误地打印会话数据,它根本不会打印任何东西!但是,我有一个使用会话的 php 验证码,它可以毫无问题地打印出来。当我在页面加载时设置会话时,它会按预期将令牌打印到隐藏的输入中。我不明白为什么表单令牌没有传递到表单进程。 session_start()
在两个文件上。我试过 ob_start()
无济于事。
请帮我调试一下。
这是我的简化设置...
index.php(在顶部):
<?php
session_start();
$reviewForm_token = md5(uniqid(rand(), true));
$_SESSION['review_form_token'] = $reviewForm_token;
?>
index.php - 表单(某处)
<form id="reviewform" method="post" novalidate>
<input type="text" class="form-control form-style name" name="firstname" size="15" maxlength="40" autocomplete="given-name">
<input type="text" class="form-control form-style name" name="lastname" size="15" maxlength="40" autocomplete="family-name">
<textarea class="form-control form-style" name="review" minlength="50" required></textarea>
<input type="text" class="form-control form-style" name="captcha" autocomplete="off" maxlength="6" required>
<img src="https://via.placeholder.com/200x60" id="captcha-review" alt="Review captcha image" width="200" height="60">
<input type="hidden" name="form_token" value="<?php echo $_SESSION['review_form_token']; ?>">
<button type="submit" name="submit" class="btn btn-primary submit float-right font">Send</button>
<button type="reset" class="btn btn-primary reset font">Reset</button>
</form> <!-- End form -->
index.php - Ajax(在文档底部)
$('#reviewform').submit(function(event) {
// Set some variables
var $this = this,
firstnameInput = $('input[name=firstname]', $this),
lastnameInput = $('input[name=lastname]', $this),
nameInput = $('input.name', $this),
ratingInput = $('input[name=StarRating]', $this),
ratingInputChecked = $('input[name=StarRating]:checked', $this),
stars = $('.star-rating', $this),
reviewInput = $('textarea[name=review]', $this),
captchaInput = $('input[name=captcha]', $this),
form_tokenInput = $('input[name=form_token]', $this),
submitButton = $("button.submit", $this);
// Get the form data
// Must relate to the name attribute...
var formData = {
'firstname': firstnameInput.val(),
'lastname': lastnameInput.val(),
'StarRating': ratingInputChecked.val(),
'review': reviewInput.val(),
'captcha': captchaInput.val(),
'form_token': form_tokenInput.val(),
};
// Process the form
$.ajax({
type: 'POST', // Define the type of HTTP verb we want to use (POST for our form)
url: 'formProcess-review.php', // The url where we want to POST
data: formData, // Our data object
dataType: 'json', // What type of data do we expect back from the server
encode: true
})
.done(function(data) {
// Here we will handle errors and validation messages
if (!data.success) {
// Handle errors for doublepost (form_token) ---------------
if (data.errors.doublepost) {
$('button', $this).parents('.form-row')
.append(label + data.errors.doublepost + '</label>')
.children('label.invalid').attr('id', 'doublepost-error');
}
} else {
// SUCCESS!!
// Thanks!
}
}); // End .done function
// Stop the form from submitting the normal way and refreshing the page
event.preventDefault();
}); // End .submit function
formProcess-review.php
<?php
session_start();
$errors = array(); // array to hold validation errors
$data = array(); // array to pass back data
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$StarRating = $_POST['StarRating'];
$review = $_POST['review'];
$captcha = $_POST['captcha'];
// Form Validation...
if ($_POST['form_token'] !== $_SESSION['review_form_token']) {
$errors['doublepost'] = 'You have already submitted your review, you can not resubmit. If you need to send another review, please reload the page.';
}
// return a response ===========================================================
// if there are any errors in our errors array, return a success boolean of false
if (!empty($errors)) {
// if there are items in our errors array, return those errors
$data['success'] = false;
$data['errors'] = $errors;
} else {
// if there are no errors process our form, then return a message
unset($_SESSION['review_form_token']);
// mySQL inserting data...
// show a message of success and provide a true success variable
$data['success'] = true;
$data['message'] = 'Success!';
}
// return all our data to an AJAX call
echo json_encode($data);
?>
尝试将此选项 'withCredentials' 添加到 ajax 调用:
$.ajax({
type: 'POST',
url: 'formProcess-review.php',
data: formData,
dataType: 'json',
encode: true,
xhrFields: {
withCredentials: true
}
}
可能是 ajax 调用没有将会话 cookie 发送到服务器。
我刚刚尝试了您的代码,Form Token 和 Session token 都在您的 formProcess-[=30= 上被正确捕获].你的代码一定是有其他问题导致的。
简化了Ajax 提交。
$.ajax({
type: 'POST',
url: 'formProcess-review.php',
data: formData,
dataType: 'json',
encode: true
})
.done(function(data) {
alert(data.message);
});
简化形式工艺-review.php
<?php
session_start();
$data['message'] = "Form token = ".$_POST['form_token']." Session value = ".$_SESSION['review_form_token'];
echo json_encode($data);
die();
?>
我已经编辑了我的代码以使其更简单并且希望更好。
我在取消设置会话时遇到了问题,所以我现在在 index.php 中的 session_start();
之后直接调用 session_unset();
来取消设置 1 重新加载之前的任何先前会话。
虽然我做了这个改变,但很奇怪以前没有它也能工作。