• ベストアンサー

Perl 2重投稿の防止

http://unimakura.jp/php/not-double-post.html このサイトはPHPとしての参考がかかれていますが、 このようなことを、Perlでしたいのですが、どう記述すればいいのでしょうか?? 完了画面での、フォーム再送信を禁止にしたいです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.6

> をしてみましたが上手くいきませんでした。 どう上手く行かなかったのかです。  InternalServerErrorなら、エラーログはどう記録されているのか  真っ白い画面なら、ソースHTML表示でどう記述されているのか  ブラウザのURL表示は転送URLにはなったが、それがNot found表示なのか 等々の次第で原因と対策は変わります。

perlhogehoge
質問者

お礼

原因がわかりました! いままで print "Content-type:text/html\n\n"; sub xxxxx{ headerやfooter,endformなど } とサブルーチン外に書いていたのを サブルーチン内に書くとそのページで更新しても 2重投稿はなくなりました! ありがとうございました!

その他の回答 (5)

回答No.5

> print "Content-type:text/html\n\n"; これが この後はHTMLですよと宣言しているヘッダなので、 後方で print "Location:~\n\n"を入れてても 転送されずに、HTMLの 一部として表示されてしまう原因です。 なので、これを削除する必要があります。 > を消すとページは表示されなくなりますし BBSへの書き込み完了のメッセージページを表示しないで 別のURLへ転送することを、狙っての修正なのですから、 それで正解です。 転送したあとが表示できないなら、転送先の指定が悪いか 転送先のページ自体の問題です。

perlhogehoge
質問者

お礼

print "Content-type:text/html\n\n"; を消してしまうと、 ページそのものが見えなくなります。 試しに、print "Content-type:text/html\n\n"; より前に、 sub endform{ print "Location: URL\n\n"; exit; 1; } をしてみましたが上手くいきませんでした。 bbs.cgi側------------------------ require "bbscommon.pl"; use warnings; use Encode; use CGI; my $form = new CGI; if($form->param('send')){&printdata($log = $log);} printdata = 書込処理の中にendformへ移動する「&endform」 があります。

回答No.4

> print "Location:bbs.cgi\n\n"; > 双方を試したのですが、文字がでてくるだけで、 > 更新すると2重投稿になってしまうのですが、 ブラウザにLocation:~が表示されるということですね。 ヘッダとしてLocation:~ を出す必要がありますが、 この前のどこかで、別のヘッダ出力やデバック用でprintしていると、 Location:~が、ヘッダ扱いでなくHTML扱いになってしまいます。 printしていないか確認してみましょう。

perlhogehoge
質問者

お礼

そういうことですか・・・ ただデバック用というのが、いまいちピンとこないのですが、 現在 bbs.cgi bbscommon.pl の2つがあり bbscommon.plには print "Content-type:text/html\n\n"; これは入っており bbscommon.plの方にsub endformがあります。 他にもこのファイルにはページHTMLの部分 書込フォームであったりエラーフォーム、headerfooter などが入っております。 bbs.cgiは基本的に書込処理や削除処理、ページ表示(for)などです。 この場合 print "Content-type:text/html\n\n"; を消すとページは表示されなくなりますし、 どのように対処するのでしょうか? #!/usr/bin/perl print "Location: https://www.yahoo.co.jp/\n\n"; exit; 1; これだけ、別のファイルにするのでしょうか? ただこれで、書込処理後にprint "location: URL"; ですると、これまたブラウザで表示されてしまいます。 bbs.cgi側にはContent-type:text/html\n\n"; これは、ないのですが、 おそらく デバック用でprintということなのですが、これがよくわからないです。。。

回答No.3

> 現在、こんな風にしているのですが、 > また違うのですか?・・・ 一応 投稿後に別ページに飛ばして そこでリロードしても二重投稿しないように対策はやってるってことなんですね。 ただこれだと "完了"が出ている間に リロードすると 二重投稿してしまうはずです。 また ヘッダーでのlocation転送ではないのでブラウザのバックボタンで戻ると二重投稿になってしまうのではないでしょうか? 完了メッセージのsub endformの内容を単独のCGIにしといて &endform;のかわりに print "Location:その.cgi\n\n"; にするか 完了メッセージがなくてよいのなら &endform;のかわりに print "Location:bbs.cgi\n\n"; とするか して試して見てはどうでしょう。 あと 別件ですが submitボタンをダブルクリックして2発目からは キャンセルされるJavaScriptを入れたほうがよいかも です。

perlhogehoge
質問者

お礼

ありがとうございます! print "Location:bbs.cgi\n\n"; 双方を試したのですが、文字がでてくるだけで、 更新すると2重投稿になってしまうのですが、 単純にテストで下記のソースだけで試すと、リダイレクト されるのですが、 サブルーチン側に問題があるのでしょうか? #!/usr/bin/perl print "Location: https://www.yahoo.co.jp/\n\n"; exit; 1;

回答No.2

参考サイトの通りのことをperlで行うなら、 CGI::Session.pmを使ってセッション管理することになり、 PHPのように簡単には、行かないですね。 またこのやり方のままだと、セッション変数名が固定なので ブラウザで投稿画面を2つ開いて、別々の投稿をするということができないので、 問い合わせフォームなら問題ないでしょうけど、 BBSやブログには向かないように思えます。 (例えばBBSならスレッド番号+投稿番号をセッション変数にするなどの工夫が必要かと) もしくは、リロードでの多重投稿防止だけ考えるなら もっと簡単に、CGIで投稿処理と、完了画面を分けてしまう方法もあります。 具体的には フォームからのsumit ↓ 投稿処理CGI  ~画面表示はしないで、ファイルの更新処理のみ~  最後に print "Location:http://{完了画面のURL}\n\n"; ↓ 完了画面 これで完了画面をリロードしたりバックボタンで戻っても投稿処理は繰り返されしませんので。

perlhogehoge
質問者

お礼

ご回答ありがとうございます。 if($form->param('send')){&send();} ↑書込処理で これの最後に &endform として、 sub endform{ print <<END; <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=$CHARSET"> <title>完了</title> <script language="JavaScript"> <!-- mnt = 0.5; url = "bbs.cgi"; function jumpPage() { location.href = url; } setTimeout("jumpPage()",mnt*1000) //--> </script> </head> <body> 完了 ※自動で戻ります。戻らない場合は下記の「戻る」をクリック<br> <input type="button" value=" 戻る " height:30px" onclick="location.href='bbs.cgi"> </body> </html> END exit; 1; } 現在、こんな風にしているのですが、 また違うのですか?・・・

  • t_ohta
  • ベストアンサー率38% (5253/13739)
回答No.1

投稿を受付るプログラムで処理後にHTMLを出力するのでは無く、受付完了ページへリダイレクトを掛けるようにすればリロードの問題は解決します。

perlhogehoge
質問者

お礼

ご回答ありがとうございます。 もしよろしければ、もう少し具体的に教えていただけませんか? もしくは、参考のサイトを教えてほしいです;;

関連するQ&A

専門家に質問してみよう