我有一个多表单向导,必须完成几个步骤,这个脚本的开发与普通脚本非常不同,我的脚本避免了用户填写的数据丢失,避免了丢失步骤用户。
脚本的步骤保存在会话中,避免返回到开头,使它们始终保持在用户的当前步骤中。
但是我必须遵循的步骤中存在漏洞问题。
如果恶意用户更改了URL的值,请按以下方式:
localhost/wizard/saveTemp.php?step=6
该用户可以随意跳过这些步骤。
用户在步骤1中的示例,但我修改了网址并自动跳转到第6步。
那么如何通过在PHP中添加强化控件来防止它们取笑系统,用户无法从步骤1跳到步骤3或步骤6,但必须继续步骤1,2,3的顺序, 4,5,6等等。
我的脚本向导
<?php
session_start();
if (isset($_GET['p'])) {
session_destroy();
session_start();
}
?>
<script>
var currentStep = <?php echo $step ?>; // Variable indicating the current step, data selected with PHP sessions
var radio = <?php echo $radio ?>; //Value of the radius selected
function show_step(step) {
var data = $("#form").serialize();
var url = 'saveTemp.php?step=' + step;
var valid = true;
// [OPTIONAL] Validate only if you are going forward
if (currentStep < step) {
// We search all the fields within the current step.
$('#step' + currentStep).find('input,textarea,select').each((idx, el) => {
let $field = $(el);
let $fieldCont = $field.closest('.form-group');
// If the field is a checkbox or a radio and an option was not selected
if (($field.prop('type') == 'checkbox' || $field.prop('type') == 'radio') &&
!$fieldCont.find('input[name="'+$field.prop('name')+'"]:checked').length) {
$fieldCont.addClass('error');
valid = false;
}
// If the field is NOT a checkbox or a radio and is empty
else if ($field.prop('type') != 'checkbox' && $field.prop('type') != 'radio' &&
!$field.val()) {
$fieldCont.addClass('error');
valid = false;
} else {
$fieldCont.removeClass('error');
}
});
}
// If at least one field was not completed
if (!valid) {
return;
}
//
$.ajax({
type: "POST",
url: url,
data: data
}).done(function(resp){
$('#radio').val(resp.radio);
if (step === 2) {
var radio = parseInt(resp.radio);
switch(radio) {
case 1:
urlform = './app/themes/pay_paypal.php'
break;
case 2:
urlform = './app/themes/pay_paypal2.php'
break;
case 3:
urlform = './app/themes/pay_paypal3.php'
break;
default:
urlform = './app/themes/pay_paypal4.php'
break;
}
$('#divPay').load(urlform,function(responseTxt, statusTxt, xhr){
if(statusTxt === "success") {
$('#step' + currentStep).css("display", "none");
$('#step' + step).fadeIn("slow");
currentStep = step;
}
if(statusTxt === "error") {
//
}
});
} else {
$('#step' + currentStep).css("display", "none");
$('#step' + step).fadeIn("slow");
currentStep = step;
}
});
};
$(function() {
show_step(currentStep);
$('a.next').click(e => {
e.preventDefault();
show_step(currentStep + 1);
});
$('a.back').click(e => {
e.preventDefault();
show_step(currentStep - 1);
});
});
</script>
HTML结构
<form id="form">
<div id="step1" class="step">
<h1>Step 1</h1>
<a href="#next" class="next">next</a>
</div>
<div id="step2" class="step">
<h1>Step 2</h1>
<a href="#back" class="back">back</a>
<a href="#next" class="next">next</a>
</div>
<div id="step3" class="step">
<h1>Step 3</h1>
<a href="#back" class="back">back</a>
<a href="#next" class="next">next</a>
</div>
<div id="step4" class="step">
<h1>Step 3</h1>
<a href="#back" class="back">back</a>
<a href="#next" class="next">next</a>
</div>
<div id="step5" class="step">
<h1>Step 3</h1>
<a href="#back" class="back">back</a>
<a href="#next" class="next">next</a>
</div>
<div id="step6" class="step">
<h1>Step 4</h1>
<a href="#back" class="back">back</a>
</div>
</form>
saveTemp.php 或者可以通过POST方法而不是GET方法接收步骤,从而避免更改网址(saveTemp.php? Step = 6)
<?php
session_start();
$step = isset($_GET['step']) ? $_GET['step'] : 1;
// We save the form data in a session variable
$_SESSION['data_form'] = $_POST;
// we also add the step to the array, you can not use this name (__step__) as name in the form
$dataForm = (isset($_SESSION['data_form']) && is_array($_SESSION['data_form'])) ? $_SESSION['data_form'] :array();
$sStep = isset($dataForm['__step__']) ? $dataForm['__step__'] : 1;
$step = isset($step) ? $step : $sStep;
$radio = isset($dataForm['radio']) ? $dataForm['radio'] : 1;
$_SESSION['data_form']['__step__'] = $step;
header('Content-Type: application/json');
$json = array(
'radio' => $radio,
'step' => $step
);
echo json_encode($json);
答案 0 :(得分:13)
完成表单处理后,将步骤放入会话变量中。当您处理下一次提交时,请检查$step
是下一步。
$last_step = isset($_SESSION['step']) ? $_SESSION['step'] : 0;
if ($step > $last_step + 1) {
die("You can't jump directly from step $last_step to $step");
}
在脚本结束时,一旦验证了所有信息,请将步骤保存在会话变量中:
$_SESSION['step'] = $step;
完整代码:
<?php
session_start();
$step = isset($_GET['step']) ? $_GET['step'] : 1;
$last_step = isset($_SESSION['data_form']['__step__']) ? $_SESSION['data_form']['__step__'] : 0;
if ($step > $last_step + 1) {
die(json_encode(array('error' => 'Invalid step')));
}
// We save the form data in a session variable
$_SESSION['data_form'] = $_POST;
// we also add the step to the array, you can not use this name (__step__) as name in the form
$dataForm = (isset($_SESSION['data_form']) && is_array($_SESSION['data_form'])) ? $_SESSION['data_form'] :array();
$sStep = isset($dataForm['__step__']) ? $dataForm['__step__'] : 1;
$step = isset($step) ? $step : $sStep;
$radio = isset($dataForm['radio']) ? $dataForm['radio'] : 1;
$_SESSION['data_form']['__step__'] = $step;
header('Content-Type: application/json');
$json = array(
'radio' => $radio,
'step' => $step
);
echo json_encode($json);
答案 1 :(得分:1)
我建议你不要这样做。
我的意思是:我发现你也会验证用户输入,并且如果当前的用户没有正确填充,则不允许用户继续下一步。
我还发现你至少在服务器端验证输入。
默认情况下没有子表单是有效的(没有任何用户输入),或者,如果是这样,你可以简单地添加一个隐藏的输入并在某些事件上自动填充(例如加载表单步骤);您需要做的唯一事情是每次请求任何步骤时重新验证整个表单(直到所需步骤)。
如果客户端请求,例如步骤6但未验证步骤5,则只需将http-redirect标头发送到第5步,并且可选地,一些最小的html错误建议执行此操作并提供手动执行此操作的链接。