他のブラウザでは問題ないのですが、
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へインサートされてしまうのでしょうか?
session 周りはまだ勉強中ですが...
> unset($_SESSION['token']);されるタイミングですが、
> なんと、、全ての処理が終わった後に初めてされているようです。。
> 理想は、以下の「トークンを破棄」の部分で処理されてほしいのですが、、
当該スクリプトがまだ終了していないうちに同じ SID が呼ばれると、セッションデータは以前のままであるという事ですよね。
セッションを終了してしまいますが session_write_close() というのは使えますか?
二重投稿を防ぐ手段として、「 UNIQUE 制約」をつけてDB側で受け付けないようにするのは反則でしょうか?
他にも、
・最新の(直前の)投稿との直接比較
・同一ホストからは、○秒以内は連続書き込みできない
のような設定のものをよく見た気がします。
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 { // 不正アクセスの疑いがあるかも・・・ }
などとしても良いかも・・・。
ご回答ありがとう御座います。
おっしゃる通りの条件分岐でテストしてみましたが、やはり二重投稿されてしますようです。引き続き試行錯誤してみたいと思います。
おかしいですね、、、
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
ご回答ありがとう御座います。
> 当該スクリプトがまだ終了していないうちに同じ SID が呼ばれると、セッションデータは以前のまま
なるほど、そのような性質が問題でしたか、、少しスッキリしました。
「session_write_close()」ですが、これは全く知りませんでした。unset($_SESSION['token']);のすぐ後に session_write_close(); してみたところ、、、、見事に問題が解決されました!!!!
あと、MySQL側でのUNIQUE制約ですが、これは全く考えつきませんでした。どうしても無理そうなら使おうかと思っていましたが、session_write_close();でうまく行きましたので、良かったです。
この度は、誠に有り難う御座いました。
とても勉強になりましたし、本当に助かりましたm(__)m