考えてみたらもそっといじれそうだったので、またいじってみました。前回以上にお気軽かつ確実な二重送信・多重送信の防止が期待できそうなヨカーン。
そもそも二重送信・多重送信の定義って、こんな感じのはず。
- 同一のメソッドで
- 同一内容のデータが
- 複数回に渡って
- サーバにポストされる
つまり、二重送信・多重送信を判断するには、前回ポストされたデータと今回ポストされたデータとを比較して、全く同じだったらダウト、ということにすればいい。
つことで、これらを自動的に処理する関数【Ticket::isReload()】が追加されました。わーパチパチ!使い方はこんな感じで。
<?php
require_once 'Ticket.class.php';
session_start();
if (Ticket::isReload()) {
echo 'リロードだよ';
} else {
echo 'リロードじゃないよ';
}
?>
ポストされたデータをまるっとセッションに埋め込むのはアレがナニなので、serialize後にmd5ハッシュを出して、それを保存するようにしています。
なお、「純粋なリロード」と「画面遷移後のsubmitボタンの再押下」とを厳密に区別したい場合は、フォーム内に時刻情報を埋め込んであげれば解決できるかと思います。Smarty使ってたらこんな感じですかね?
<input type="hidden" name="time" value="{$smarty.now}" />
ソースよくみてないけど。
毎回サーバからのレスポンス毎にランダム(って表現も微妙だけど)なCookie埋めこんで同じCookieからの2度目以上のリクエストを破棄するという実装はどうでしょうか。
基本的には仰るとおりの実装をしてると思われます。
この程度の機能じゃPEARにコミットできないだろうなあ…
PHPでの$_SESSIONさんの挙動がよくわかんないんですけど、有効期限かどうかはCookie君に判断させられる情報じゃないかと思うのですよ。
逆に$_SESSIONさんが自分の中でCookie君と話を付けてくれるのであればこんなに面倒なクラスを作る必要が無いと思うのでう。
あー。
{$smarty.now}は、『意図的に行われた同一データの多重送信(=有効)』と『リロード(=無効)』とを区別したい時、異なるハッシュを出す目的で入れただけなのであって、有効期限を設定することが目的ではないですよ。
そもそも$_SESSIONさんは「複数の値を詰め込むことが目的のCookie君」という役割だし、$_SESSIONの扱いに慣れてくるとsetcookie()で複数Cookie出すのマンドクサだし、なにより普段取り扱い対象となるスーパーグローバル変数($_GET / $_POST / $_SESSION / $_COOKIEとか)は少ないほうが楽だしで、結果として$_SESSION一辺倒の実装になりました。
※PEAR::Auth(ログイン認証機能)も$_SESSIONにexpireを格納して有効期限設定してたから、まいっか、てのもありました。
> 面倒
マジですか?定数の定義を含めても60ステップに収めたのに…しくしくしく…
何にしろ、意見をいただけるのはありがたいです。
周りに同業者がいないもので。
今更ちゃんとコードみてみますた。
これはいいコードですね。
一点気になったのが。
> 基本的には仰るとおりの実装をしてると思われます。
例えばぁゃιぃ人がPOSTで完了する前にGETで叩いてきたりするとこれは通ってしまう気がするんですが。
> これはいいコードですね。
> これはいいコードですね。
> これはいいコードですね。
初めて言われた!
ありがとうございます。ううう…(うれし泣き)
> 例えばぁゃιぃ人がPOSTで完了する前にGETで叩いてきたりするとこれは通ってしまう気がするんですが。
言われてみれば、この実装は確かに穴があるような気がしてきました。REQUEST_METHODチェックをしてないので、現状では連続GETすらリロード扱いになっちゃいますね。もそっと練ってみることにします。