こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Perl 2重投稿の防止

http://unimakura.jp/php/not-double-post.html
このサイトはPHPとしての参考がかかれていますが、
このようなことを、Perlでしたいのですが、どう記述すればいいのでしょうか??

完了画面での、フォーム再送信を禁止にしたいです。

投稿日時 - 2017-08-05 10:14:10

QNo.9359498

困ってます

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

> をしてみましたが上手くいきませんでした。

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

投稿日時 - 2017-08-08 16:40:49

お礼

原因がわかりました!

いままで

print "Content-type:text/html\n\n";

sub xxxxx{
headerやfooter,endformなど
}

とサブルーチン外に書いていたのを
サブルーチン内に書くとそのページで更新しても
2重投稿はなくなりました!

ありがとうございました!

投稿日時 - 2017-08-10 08:48:04

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(6)

ANo.5

> print "Content-type:text/html\n\n";
これが この後はHTMLですよと宣言しているヘッダなので、
後方で print "Location:~\n\n"を入れてても 転送されずに、HTMLの
一部として表示されてしまう原因です。
なので、これを削除する必要があります。


> を消すとページは表示されなくなりますし
BBSへの書き込み完了のメッセージページを表示しないで
別のURLへ転送することを、狙っての修正なのですから、
それで正解です。

転送したあとが表示できないなら、転送先の指定が悪いか
転送先のページ自体の問題です。

投稿日時 - 2017-08-07 14:02:58

お礼

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」
があります。

投稿日時 - 2017-08-08 10:50:11

ANo.4

> print "Location:bbs.cgi\n\n";
> 双方を試したのですが、文字がでてくるだけで、
> 更新すると2重投稿になってしまうのですが、

ブラウザにLocation:~が表示されるということですね。
ヘッダとしてLocation:~ を出す必要がありますが、
この前のどこかで、別のヘッダ出力やデバック用でprintしていると、
Location:~が、ヘッダ扱いでなくHTML扱いになってしまいます。
printしていないか確認してみましょう。

投稿日時 - 2017-08-07 10:09:09

お礼

そういうことですか・・・
ただデバック用というのが、いまいちピンとこないのですが、

現在
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ということなのですが、これがよくわからないです。。。

投稿日時 - 2017-08-07 11:01:14

ANo.3

> 現在、こんな風にしているのですが、
> また違うのですか?・・・

一応 投稿後に別ページに飛ばして そこでリロードしても二重投稿しないように対策はやってるってことなんですね。

ただこれだと "完了"が出ている間に リロードすると 二重投稿してしまうはずです。
また ヘッダーでのlocation転送ではないのでブラウザのバックボタンで戻ると二重投稿になってしまうのではないでしょうか?

完了メッセージのsub endformの内容を単独のCGIにしといて
&endform;のかわりに
print "Location:その.cgi\n\n";
にするか

完了メッセージがなくてよいのなら
&endform;のかわりに
print "Location:bbs.cgi\n\n";
とするか
して試して見てはどうでしょう。


あと 別件ですが submitボタンをダブルクリックして2発目からは
キャンセルされるJavaScriptを入れたほうがよいかも です。

投稿日時 - 2017-08-05 18:04:34

お礼

ありがとうございます!
print "Location:bbs.cgi\n\n";
双方を試したのですが、文字がでてくるだけで、
更新すると2重投稿になってしまうのですが、

単純にテストで下記のソースだけで試すと、リダイレクト
されるのですが、
サブルーチン側に問題があるのでしょうか?
#!/usr/bin/perl

print "Location: https://www.yahoo.co.jp/\n\n";
exit;
1;

投稿日時 - 2017-08-07 08:42:12

ANo.2

参考サイトの通りのことをperlで行うなら、
CGI::Session.pmを使ってセッション管理することになり、
PHPのように簡単には、行かないですね。

またこのやり方のままだと、セッション変数名が固定なので
ブラウザで投稿画面を2つ開いて、別々の投稿をするということができないので、
問い合わせフォームなら問題ないでしょうけど、
BBSやブログには向かないように思えます。
(例えばBBSならスレッド番号+投稿番号をセッション変数にするなどの工夫が必要かと)


もしくは、リロードでの多重投稿防止だけ考えるなら
もっと簡単に、CGIで投稿処理と、完了画面を分けてしまう方法もあります。

具体的には
フォームからのsumit

投稿処理CGI
 ~画面表示はしないで、ファイルの更新処理のみ~
 最後に print "Location:http://{完了画面のURL}\n\n";

完了画面

これで完了画面をリロードしたりバックボタンで戻っても投稿処理は繰り返されしませんので。

投稿日時 - 2017-08-05 11:48:12

お礼

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

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;
}

現在、こんな風にしているのですが、
また違うのですか?・・・

投稿日時 - 2017-08-05 13:01:18

ANo.1

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

投稿日時 - 2017-08-05 11:01:55

お礼

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

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

投稿日時 - 2017-08-05 13:02:12

あなたにオススメの質問