PHP阻止F5重新提交|没有重定向

时间:2017-01-08 17:06:10

标签: php html post form-submit

当用户通过Post方法发送表单数据时,我想阻止F5重新提交。

  • 我不希望将用户重定向到同一页面;
  • 我需要在正确提交时闪烁消息;
  • 在submition之后清理所有$ _POST
  • 我不能使用javascript,只能使用PHP;

所以,首先,我有一个页面,其中有一个提交信息/数据的表单,当正确提交时,我想要闪回一条带有正面反馈的消息,并清理$ _POST ['vars']中的所有数据。

PHP代码:

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $error= '';  

    if (!$_POST['name']) { 
        $error.= '- Introduza o seu Nome.<br>'; 
    }

    if (!$_POST['email']) {
        $error.= '- Introduza o seu Email.<br>';  
    }

    if (!$_POST['message']) { 
        $error.= '- Introduza a sua mensagem.<br>';  
    }

    if (empty($_POST['check'])) { 
        $error.= '- Por favor, confirme que é um humano.<br>'; 
    }

    if ($error) { 
        $result="Temos erros no formulário. Por favor corriga os seguinte(s):<br> $error";
    } else { 
        mail("email@email", "Mensagem de Contato", "Nome: ".$_POST['name']. "Email: ". $_POST['email'] . "Mensagem: " . $_POST['message'] ); 
        $result='A sua mensagem foi enviada. Obrigado<br>';  
    }
}
?> 

HTML:

<div class="container">
  <div class="row">
    <div class="col-md-6 col-md-offset-3">
    <h1>Formulário de Contato</h1>
    <p>Envie mensagem pelo formulário em baixo</p>
    <?php if (isset($_POST['submit'])) {
      echo $result;
    }
    ?>
    <br>
      <form method="post" action="" role="form">
        <div class="form-group">
          <input type="text" name="name" class="form-control" placeholder="Coloque aqui o seu nome" value="<?php
            if (isset($_POST['name'])) {
              echo $_POST['name'];
            }
          ?>">
        </div>
        <div class="form-group">
          <input type="email" name="email" class="form-control" placeholder="O seu email" value="<?php
            if (isset($_POST['email'])) {
              echo $_POST['email'];
            }
          ?>">
        </div>
        <div class="form-group">
          <textarea name="message" name="message" class="form-control" cols="30" rows="10" placeholder="Escreva a sua mensagem"><?php
            if (isset($_POST['message'])) {
              echo $_POST['message'];
            }
          ?></textarea>
        </div>
        <div class="checkbox">
          <label>
            <input type="checkbox" name="check" >Confirma que é humano.
          </label>
        </div>
        <div align="center">
        <input type="submit" name="submit" class="btn btn-secondary" value="Enviar Mensagem">
        </div>
        </div>
      </form>
    </div>
  </div>
</div>

1 个答案:

答案 0 :(得分:4)

让我们看看要求:

  • 我不能使用javascript,只能使用PHP;
  • 您不想重定向。

因此,当浏览器 收到FORM时,它只能将其提交给PHP。不允许使用Javascript / AJAX恶作剧。所以按F5 将是不可避免的

&#34;清算$ _POST&#34;意味着没有 - 您无法从服务器修改浏览器可能(重新)发布的数据,除非浏览器已经信任您并已下载相应的Javascript。

一旦交易完成,能够远程更改_POST将是一个可怕的安全漏洞(想想电子支付)。

但你要做的就是不重复操作。您无需清除$_POST即可执行此操作。我们唯一可以做的就是识别重新提交并以不同方式对待它(在这种情况下,再次发送邮件);这就是我们需要做的一切。

我们通过在FORM中添加唯一的,不可重复使用的ID来实现此目的,例如,当页面是用PHP制作的时候uniqueid()

<input type="hidden" name="nonce" value="0cf8059606c73ab872cd8e0064" />

浏览器接收表单,用户提交表单。各个字段填充_POST。

服务器接收POST,并将nonce保存在$_SESSION数组中......并检查这是第一次在_POST中看到该nonce。

if (!in_array($_POST['nonce'], $_SESSION['posts'])) {
    // It is the first time. We add it to the list of "seen" nonces.
    $_SESSION['posts'][] = $_POST['nonce'];
    do_something_with($_POST);
} else {
    print '<div class="errormessage">Please do not resubmit.</div>';
}

或者,如果不成功,我们可以简单地运行测试并死掉:

if (in_array($_POST['nonce'], $_SESSION['posts'])) {
    die('Não atualize a pagina. Click <a href="/">aqui</a> para voltar para a home.');
}

进一步改进(针对其他情况)

当然,如果在回复提交时生成的页面再次具有FORM(例如,可以一个接一个地插入多个记录),则需要重新生成 uniqueid隐藏字段

所以F5将提交一个独特的&#34;已经看过&#34;并且完全忽略_POST字段,而使用收到的新数据的诚实提交将提供一个新的,但尚未看到的值,因此允许发布。

更确定的是,您可以在提交之前(即首次打开表单时)生成uniqueid并将存储在会话中。然后,在提交时,您将只接受为该会话生成的ID:

if (array_key_exists('nonce', $_POST)) {
    $nonce = $_POST['nonce'];
    unset($_POST['nonce']); // for transparency with extant code
    if (array_key_exists($nonce, $_SESSION['securePosts'])) {
        if ($_SESSION['securePosts'][$nonce]) {
            $error = false;
            // Punch the ticket so it can't be reused
            $_SESSION['securePosts'][$nonce] = false;
        } else {
            $error = 'FORM resubmitted';
        }
    } else {
        $error = 'Someone sent a fake FORM or a FORM from an expired session';
    }
}

if (!$error) {
    // We can treat $_POST as legit.

    // Here the code that "does something".
}

$uniqueid = secureUniqueId();
$_SESSION['securePosts'][$uniqueid] = true; // Ready to be triggered

print "<input type=\"hidden\" name=\"nonce\" value=\"{$uniqueid}\" />";
// If no error, empty DIV
print "<div id=\"error\">{$error}</div>";

邮政/ DontRedirect /获取?

上述方法不支持支持书签成功&#34;成功&#34;页。

能够&#34;书签&#34; &#34;结果&#34;对于初学者,您需要在网址中添加唯一ID:

<form method="POST" action="?nonce={$nonce}">

这样,当您单击SUBMIT时,同一页面会在$_GET['nonce']参数中收到nonce。缺少nonce意味着我们需要生成一个空表单。

然后,在提交时,您需要将nonce存储在数据库中或以某种方式将nonce与结果一起保存:

nonce               results (in separate columns)
eb72ab1736a32...    invoice=1234,amount=32,...

此时,当你收到一个随机数时,

1. it is not in the database, and there is POST.
   - do whatever needs to be done and update the database accordingly.

2. is in the database, and there is a POST.
   - it is a resubmission. Ignore it, or display an error

3. is not in the database, and there is no POST.
   - it's a prankster, or a database error.

4. is in the database, and there is no POST.
   - is a bookmark. Display the success page as in (1).

如果用户按下F5,他就是(2)。如果他将页面保存为书签,则URL中的nonce来自最近完成的提交,因此用户在case(1)中,并根据case(4)设置为继续。