よもやまチョモランマ

メールフォームの重複送信・再送信問題

「同じ内容の勤怠報告がたて続けに来る(たまに10回20回、秒まで同じ時刻)」というのは前からありましたが、最近になって「2ヶ月分の勤怠報告がまとめて届く」という事例がふってわきました。

PHP工房さんに問い合わせても、原因・打開策は得られず。
でも、あいかわらず神対応で、いくつかヒントをいただきました。

結論としては、今回は「送信完了ページをHTMLにする」ことにいたしました。

現象の再現

スマホで送信完了後、そのタブを閉じずに放置していることが原因ではないかと疑っていた。
案の定、そうすることで再送信が起こることを実機で確認できた。
でも、なぜ、出しっぱなしだと再送信される?
画面に表示されるたびリロードされていることに気付いた。なにこれ。

PHPの悲しい性

「メールフォーム リロード」で調べているうちに
「PHPメルフォがリロードで重複送信する問題はわりと有名」と知る。
送信完了ページをPHPから吐き出している限り(そのページのURLが「.php」である限り)この罠にかかる。
スマホが勝手にリロードするたびに、PHPは律儀に送信してしまうのだ。

スマホの暴走

「スマホ 勝手にリロード」で調べているうちに
「iOS10のアップデートから常時リロードがデフォルトになった」という情報にかする。
もしそれが本当なら、世のスマホはみんなそうなってゆくのではなかろうか。
さらに「iOS13のバグでは?」という話もある。
もう、デフォルトであれバグであれ、リロードはされるもんだと思ったほうがいい。

PHPで回避できないか

ブラウザにリロードさせないとか、されても再送信を受け付けないとか、出来ないものか?
調べてはみたが、難しすぎて出来る気がしない。

【参考】
PHPブラウザ更新(F5)で二重送信・重複送信される現象を防止する
リロードによる多重投稿を防止する

送信完了ページがPHPでなければ良いのでは?

どこかの知恵袋にそんな回答があった。
たしかに、HTMLファイルならいくらリロードされても何も起こりようがない。
さいわい、メルフォのPHPには「サンクスページ」を指定する項目がある。

こうして、送信完了ページのHTMLファイルが増えることとなりました。

PHPの変更箇所

1. 79行目の「送信完了後に自動的に指定のページに移動」を「1」にする
2. 82行目の「送信完了後に表示するページURL」を入れる
3. 381行目から「エラーがあるとき」のコードを書いておく

	<!DOCTYPE html>
	<html lang="ja">
	<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
	<link rel="stylesheet" href="style.css">
	<title>入力エラー</title>
	</head>
	<body>
	<h3>入力エラー</h3>
	<h4><?php echo $errm; ?></h4>
	<p>上記の入力内容をご確認ください</p>
	<input type="submit" value="戻る" class="submitbtn non" alt="入力画面に戻る" onClick="history.back()">
	</body>
	</html>

まとめ

「完了画面をリロードされたら再送信される」のが、お約束であったにもかかわらず問題にならなかったのは、送信者の多くがPCだったから。PCであれば、わざわざ完了画面でリロードしたりしませんし、再送信されることは稀だったはずです。

そもそも普通の人は「リロード」をあまり知りません。
PCでもスマホでも率先してやらないはずです。

だからこそ、スマホが「出しっぱなしで長い期間が経ったページを最新状態にしてあげる機能」として自動更新をデフォルトにするのは、自然な流れにも思えます。

スマホでネットをする人のほうが多くなっている以上、これからは「サンクスページ」は常にHTMLにしたほうが良さそうです。