SQLテーブルにテキストを送信する簡単なフォームがあります。問題は、ユーザーがテキストを送信した後、ページを更新でき、フォームに再度入力せずにデータが再度送信されることです。テキストが送信された後、ユーザーを別のページにリダイレクトすることはできますが、ユーザーが同じページに留まるようにします。
各ユーザーに一意のセッションIDを与え、それを別の値と比較して、私が抱えている問題を解決したことを読んだことを覚えていますが、それがどこにあるか忘れていました。
Post/Redirect/Getパターンを使用します。 http://en.wikipedia.org/wiki/Post/Redirect/Get
私のWebサイトでは、メッセージをCookieまたはセッションに保存し、投稿後にリダイレクトし、Cookie /セッションを読み取り、そのセッションまたはCookie変数の値をクリアします。
また、JavaScriptのアプローチwindow.history.replaceState
を使用して、更新および戻るボタンでの再送信を防ぐことができることを指摘したいと思います。
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
ここで概念実証: https://dtbaker.net/files/prevent-post-resubmit.php
Post/Redirect/Getアプローチを引き続きお勧めしますが、これは新しいJSソリューションです。
実際にこれを処理するには、リダイレクト後取得パターンを使用する必要がありますが、何らかの理由でPRGが実行できない位置になった場合(たとえば、フォーム自体がインクルード内にあり、リダイレクトを防止している場合)、リクエストパラメーターの一部をハッシュできますコンテンツに基づいて文字列を作成し、まだ送信していないことを確認します。
//create digest of the form submission:
$messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);
//and check it against the stored value:
$sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';
if($messageIdent!=$sessionMessageIdent){//if its different:
//save the session var:
$_SESSION['messageIdent'] = $messageIdent;
//and...
do_your_thang();
} else {
//you've sent this already!
}
セッション変数を介してフォームの再送信を許可できます
まず、テキストボックスにRand()を設定し、フォームページに$ _SESSION ['Rand']を設定する必要があります
<form action="" method="post">
<?php
$Rand=rand();
$_SESSION['Rand']=$Rand;
?>
<input type="hidden" value="<?php echo $Rand; ?>" name="randcheck" />
Your Form's Other Field
<input type="submit" name="submitbtn" value="submit" />
</form>
テキストボックス$ _POST ['randcheck']の値で$ _SESSION ['Rand']をチェックした後
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['Rand'])
{
//Your Code here
}
フォームが処理されると、別のページにリダイレクトされます。
... process complete....
header('Location: thankyou.php');
同じページにリダイレクトすることもできます。
コメントのようなことをしていて、ユーザーが同じページに留まるようにしたい場合は、Ajaxを使用してフォーム送信を処理できます。
ヘッダーを使用してページをリダイレクトします。
header("Location:your_page.php");
同じページまたは異なるページにリダイレクトできます。
データベースに挿入した後、$ _ POSTの設定を解除します。
unset($_POST);
このjavascript行を使用して、フォームが送信されると、更新時にフォームの再送信を要求するポップアップをブロックします。
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
この行をファイルのフッターに配置して、魔法を見てください
次の回避策を見つけました。 POST
オブジェクトを操作することにより、history
リクエストの処理後にリダイレクトをエスケープできます。
これでHTMLフォームができました:
<form method=POST action='/process.php'>
<input type=submit value=OK>
</form>
サーバーでこのフォームを処理するとき、次のようにLocation
ヘッダーを設定することにより、ユーザーを/the/result/page
にリダイレクトする代わりに:
$cat process.php
<?php
process POST data here
...
header('Location: /the/result/page');
exit();
?>
POST
edデータを処理した後、小さな<script>
と結果/the/result/page
をレンダリングします
<?php
process POST data here
render the <script> // see below
render `/the/result/page` // OK
?>
レンダリングする必要のある<script>
:
<script>
window.onload = function() {
history.replaceState("", "", "/the/result/page");
}
</script>
結果は次のとおりです。
ご覧のとおり、フォームデータはPOST
edからprocess.php
スクリプトです。
このスクリプトはPOST
edデータを処理し、/the/result/page
を一度にレンダリングします:
POST
データがありません(F5)POST
はありませんUPD
別の解決策として、 機能リクエストMozilla FireFoxチームが、ユーザーがNextPage
ヘッダーのように機能するLocation
ヘッダーを設定できるようにしますpost/redirect/get
パターンを廃止します。
要するに。サーバープロセスがPOST
データを正常に形成すると、次のようになります。
NextPage
の代わりにLocation
ヘッダーをセットアップしますpost/redirect/get
パターンのPOST
要求に対してレンダリングするように、GET
フォームデータを処理した結果をレンダリングしますブラウザは、NextPage
ヘッダーを見ると順番に:
NextPage
値でwindow.location
を調整しますGET
リクエストをreNextPage
フォームデータの代わりにPOST
にネゴシエートします実装すればこれは優れていると思いますか? =)
非常に確実な方法は、一意のIDを投稿に実装し、
<input type='hidden' name='post_id' value='".createPassword(64)."'>
次に、コードでこれを行います:
if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
$_SESSION['post_id'] = $_POST['post_id'];
//do post stuff
} else {
//normal display
}
function createPassword($length)
{
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= ($length - 1)) {
$num = Rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
Moobの投稿の洗練されたバージョン。 POSTのハッシュを作成し、セッションCookieとして保存し、セッションごとにハッシュを比較します。
// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );
$post_hash = md5( json_encode( $_POST ) );
if( session_start() )
{
$post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
$_SESSION[ 'post_hash' ] = $post_hash;
session_write_close();
}
else
{
$post_resubmitted = false;
}
if ( $post_resubmitted ) {
// POST was resubmitted
}
else
{
// POST was submitted normally
}
フォームデータを使用した後、同じページにリダイレクトするだけで機能します。私はそれを試しました。
header('location:yourpage.php');
データベースに挿入した後、unset()メソッドを呼び出してデータをクリアします。
nset($ _ POST);
更新データの挿入を防ぐには、レコードの挿入後に同じページまたは別のページにページをリダイレクトします。
header( 'Location:'。$ _ SERVER ['PHP_SELF']);
リダイレクトなしでphpフォームの再送信を防ぐ方法。 (session_startの後の)$ _SESSIONと$ _POSTフォームを使用している場合、次のようなことができます。
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
// do your stuff, save data into database, etc
}
あなたのhtmlフォームにこれを入れてください:
<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
$_SESSION['act'] = 1;
} else {
$_SESSION['act'] = 2;
}
}
?>
そのため、フォームが送信されるたびに、新しいアクトが生成され、セッションに保存され、アクト後のアクトと比較されます。
Ps:Getフォームを使用している場合、すべてのPOSTをGETで簡単に変更できます。
基本的に、そのページからリダイレクトする必要がありますが、インターネットの速度が遅い場合でも問題が発生する可能性があります(サーバーサイドからヘッダーをリダイレクト)
基本的なシナリオの例:
解決する方法
クライアント側
サーバ側
Keverw answerのPost/Redirect/Getパターンを使用するのは良い考えです。しかし、あなたはあなたのページにとどまることができません(そして、これはあなたが求めていたものだと思いますか?)さらに、時々 fail :
サーバーの遅延のために最初の送信が完了する前にWebユーザーが更新され、特定のユーザーエージェントでHTTP POST要求が重複する場合。
別のオプションは、次のようにテキストをSQLデータベースに書き込む必要がある場合にセッションに保存することです。
if($_SERVER['REQUEST_METHOD'] != 'POST')
{
$_SESSION['writeSQL'] = true;
}
else
{
if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
{
$_SESSION['writeSQL'] = false;
/* save $_POST values into SQL */
}
}
他の人が言ったように、post/redirect/getを使用することはできません。しかし同時に、サーバー側でやりたいことを行うのは非常に簡単です。
POSTページでは、単にユーザー入力を検証しますが、操作は行わず、代わりにSESSION配列にコピーします。次に、メインの送信ページに再度リダイレクトします。メインの送信ページは、使用しているSESSION配列が存在するかどうかを確認することから始まります。存在する場合は、ローカル配列にコピーして設定を解除します。そこから行動することができます。
このようにして、すべての主要な作業を一度だけ実行し、やりたいことを達成します。
その後、巨大なプロジェクトでの再提出を防ぐための解決策を探しました。コードは$ _GETと$ _POSTで非常に機能し、予期しないバグのリスクなしにフォーム要素の動作を変更することはできません。だから、ここに私のコードがあります:
<!-- language: lang-php -->
<?php
// Very top of your code:
// Start session:
session_start();
// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
// Store Post Form Data in Session Variable
$_SESSION["POST"] = $_POST;
// Reload Page if there were no outputs
if ( ! headers_sent() ) {
// Build URL to reload with GET Parameters
// Change https to http if your site has no ssl
$location = "https://" . $_SERVER['HTTP_Host'] . $_SERVER['REQUEST_URI'];
// Reload Page
header( "location: " . $location, true, 303 );
// Stop any further progress
die();
}
}
// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
$_POST = $_SESSION["POST"];
// Tell PHP that POST is sent
$_SERVER['REQUEST_METHOD'] = 'POST';
}
// Your code:
?><html>
<head>
<title>GET/POST Resubmit</title>
</head>
<body>
<h1>Forms:</h1>
<h2>GET Form:</h2>
<form action="index.php" method="get">
<input type="text" id="text_get" value="test text get" name="text_get"/>
<input type="submit" value="submit">
</form>
<h2>POST Form:</h2>
<form action="index.php" method="post">
<input type="text" id="text_post" value="test text post" name="text_post"/>
<input type="submit" value="submit">
</form>
<h2>POST Form with GET action:</h2>
<form action="index.php?text_get2=getwithpost" method="post">
<input type="text" id="text_post2" value="test text get post" name="text_post2"/>
<input type="submit" value="submit">
</form>
<h2>File Upload Form:</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" value="submit">
</form>
<h1>Results:</h1>
<h2>GET Form Result:</h2>
<p>text_get: <?php echo $_GET["text_get"]; ?></p>
<h2>POST Form Result:</h2>
<p>text_post: <?php echo $_POST["text_post"]; ?></p>
<h2>POST Form with GET Result:</h2>
<p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
<p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
<h2>File Upload:</h2>
<p>file:
<pre><?php if ( ! empty( $_FILES ) ) {
echo print_r( $_FILES, true );
} ?></pre>
</p>
<p></p>
</body>
</html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );
$ _GETではなく、$ _ POSTの再送信を回避するためにのみ機能します。しかし、これは私が必要とする動作です。再送信の問題は、ファイルのアップロードでは機能しません!