人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHP,MYSQLにて、フォームから送信されるデータの「二重投稿防止」についての質問です。

他のブラウザでは問題ないのですが、
safariで送信ボタンを連打しテストしてみますと二重投稿になってしまいました。
このロジックでは何か不足があるのでしょうか?

現在以下のようなロジックになっております。
--------------▼コード ここから--------------
<?php
//セッションスタート
Session::sessionStart();

//トークン発行
if (!isset($_SESSION['token'])) {
$_SESSION['token'] = Str::getRandomString(24);
}

//POSTかつ二重投稿でなければ保存
if ($_SERVER['REQUEST_METHOD'] == 'POST' && $_POST['token'] == $_SESSION['token']) {
//トークンを破棄
unset($_SESSION['token']);
//DBへデータを保存
hoge::insert($_POST['data']);
}
?>

<?php if ($_SERVER['REQUEST_METHOD'] == 'GET') { ?>
<html><body>
<form method="post" action="tes.php">
<input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
<input type="text" name="data" />
<input type="submit" value="送信" />
</form>
</body></html>
<?php } ?>
--------------▲コード ここまで--------------

「//DBへデータを保存」の直前に「unset($_SESSION['token'])」しているのにも関わらず、
なぜ複数回DBへインサートされてしまうのでしょうか?

●質問者: uniuniko
●カテゴリ:インターネット ウェブ制作
✍キーワード:24 DB hoge MySQL PHP
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● kn1967
●35ポイント
if (!isset($_SESSION['token'])) {
 $_SESSION['token'] = Str::getRandomString(24);
} elsif ($_SERVER['REQUEST_METHOD'] == 'POST' && $_POST['token'] == $_SESSION['token']) {
 unset($_SESSION['token']);
 hoge::insert($_POST['data']);
}

といったような具合に、初回アクセス時には

データベース書き込み判定処理などに行かないようにすればよろしいかと・・・。

さらに細かく

if (!isset($_SESSION['token'])) {
 $_SESSION['token'] = Str::getRandomString(24);
} elsif ($_SERVER['REQUEST_METHOD'] != 'POST') {
// 不正アクセスの疑いがあるかも・・・
} elsif ($_POST['token'] == $_SESSION['token']) {
 unset($_SESSION['token']);
 hoge::insert($_POST['data']);
} else {
// 不正アクセスの疑いがあるかも・・・
}

などとしても良いかも・・・。

◎質問者からの返答

ご回答ありがとう御座います。

おっしゃる通りの条件分岐でテストしてみましたが、やはり二重投稿されてしますようです。引き続き試行錯誤してみたいと思います。

おかしいですね、、、


2 ● tezcello
●200ポイント ベストアンサー

session 周りはまだ勉強中ですが...


> unset($_SESSION['token']);されるタイミングですが、

> なんと、、全ての処理が終わった後に初めてされているようです。。

> 理想は、以下の「トークンを破棄」の部分で処理されてほしいのですが、、

当該スクリプトがまだ終了していないうちに同じ SID が呼ばれると、セッションデータは以前のままであるという事ですよね。

セッションを終了してしまいますが session_write_close() というのは使えますか?


二重投稿を防ぐ手段として、「 UNIQUE 制約」をつけてDB側で受け付けないようにするのは反則でしょうか?

他にも、

・最新の(直前の)投稿との直接比較

・同一ホストからは、○秒以内は連続書き込みできない

のような設定のものをよく見た気がします。

◎質問者からの返答

ご回答ありがとう御座います。


> 当該スクリプトがまだ終了していないうちに同じ SID が呼ばれると、セッションデータは以前のまま


なるほど、そのような性質が問題でしたか、、少しスッキリしました。


「session_write_close()」ですが、これは全く知りませんでした。unset($_SESSION['token']);のすぐ後に session_write_close(); してみたところ、、、、見事に問題が解決されました!!!!


あと、MySQL側でのUNIQUE制約ですが、これは全く考えつきませんでした。どうしても無理そうなら使おうかと思っていましたが、session_write_close();でうまく行きましたので、良かったです。

この度は、誠に有り難う御座いました。

とても勉強になりましたし、本当に助かりましたm(__)m

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ