ScriptBasic講座
[二重投稿を防止]



1.二重投稿を防止

前項で作ったbbs11.basは二重投稿を許してしまうという欠点がありました。
書き込みした直後、ブラウザの更新ボタンを押してみてください。
二重に書き込まれているのが確認できます。

 これは更新時、POSTの内容も再送してしまう為です。

▼更新(F5キー)を押すと以下のような警告が出ます。

『再試行』を選択すると二重書き込みになります。


二重投稿を防止してみましょう。







2.同一内容の記事は投稿させない
二重投稿やいたずらを防止するのに有効なチェック方法は、
まったく同じコメントが以前に書かれていないかチェックする方法です。

-bbs12.bas-
#!/usr/bin/scriba

import cgi.bas

'commentが送信されているか?
IF cgi::POSTParam("comment") <> undef Then CALL kakikomi

'読み込みを表示
CALL yomikomi

'プログラムはここまで
END

'読み込み部分
SUB yomikomi
        print "Content-Type: text/html; charset=euc-jp\n\n"

        print """
        <html><body>
        <form action="bbs12.bas" method="POST">
        お名前:<input type="text" name="onamae" size=20><br>
        Email:<input type="text" name="email" size=20><br>
        ▼コメント<br>
        <textarea name="comment" rows=4 cols=40></textarea><br>
        URL:<input type="text" name="url" value="http://" size=50><br>
        <input type="submit" value="送信">
        </form>
        """

        '読み込み部分(ファイルが存在する場合)
        IF FILEEXISTS("bbslog3.txt") Then
                open "bbslog3.txt" for input as 1

                '最後までループ
                while NOT(EOF(1))
                        'dataに代入
                        line input #1,data

                        'dataが存在するか?
                        IF len(data)>0 Then
                                '分割:<>で分割
                                split data by "<>" to onamae,comdata,email,url
                                
                                
                                
                                'emailが書き込まれているか?
                                IF email <> "" Then 
                                        print "お名前:<a href=\"mailto:",email,"\">",onamae,"</a>"
                                ELSE
                                        print "お名前:",onamae
                                END IF


                                print "<br>",comdata,"<br>"
                                
                                'urlがhttp://以外なら
                                IF url<>"http://\n" Then print "<a href=\"",url,"\">",url,"</a>"
                                
                                print "<hr>"

                        END IF
                wend
                close 1
        ELSE
                print "ファイルがありません"
        END IF

        print "</html></body>"

END SUB

'書き込み部分
SUB kakikomi
        '変数に代入
        comment=cgi::POSTParam("comment")
        onamae=cgi::POSTParam("onamae")
        email=cgi::POSTParam("email")
        url=cgi::POSTParam("url")

        'HTMLタグの置換
        comment=REPLACE(comment,"<","&lt;")
        comment=REPLACE(comment,">","&gt;")

        onamae=REPLACE(onamae,"<","&lt;")
        onamae=REPLACE(onamae,">","&gt;")
        email=REPLACE(email,"<","&lt;")
        email=REPLACE(email,">","&gt;")
        url=REPLACE(url,"<","&lt;")
        url=REPLACE(url,">","&gt;")

        '入力検査部分
        IF onamae="" then CALL errormes("お名前が記入されていません")
        IF comment="" then CALL errormes("コメントが記入されていません")

        '文字数検査
        IF len(comment)>1000 then CALL errormes("コメントが1000文字以下ではありません")
        IF len(onamae)>30 then CALL errormes("お名前が30文字以下ではありません")
        IF len(email)>64 then CALL errormes("Emailが64文字以下ではありません")
        IF len(url)>128 then CALL errormes("URLが128文字以下ではありません")

        '改行を<br>に
        comment=REPLACE(comment,"\r\n","<br>")
        comment=REPLACE(comment,"\r","<br>")
        comment=REPLACE(comment,"\n","<br>")

        '過去のデータをチェック
        IF FILEEXISTS("bbslog3.txt") Then

                        open "bbslog3.txt" for input as 1
                        '最後までループ
                        while NOT(EOF(1))

                                'checkに代入
                                line input #1,check

                                'checkが存在するか?
                                IF len(check)>0 Then
                                        '分割:<>で分割
                                        split check by "<>" to check_onamae,check_comdata,check_email,check_url
                                        IF comment=check_comdata then CALL errormes("過去に同じ内容の書き込みがあります")
                                END IF
                        wend
                        
                        close 1
        END IF



        '書き込み
        open "bbslog3.txt" for append as 1

        'ロック
        LOCK #1,write
        print #1,onamae,"<>",comment,"<>",email,"<>",url,"\n"

        'ロック解除
        LOCK #1,release
        close 1
END SUB


'errormesサブルーチン
SUB errormes(errmessage)
        'メッセージを出力
        print "Content-Type: text/html; charset=euc-jp\n\n"
        print "<html><body>",errmessage,"</body></html>"
        'ここでプログラム終了
        END
END SUB

今回の変更点は以下の部分です。

'過去のデータをチェック
IF FILEEXISTS("bbslog3.txt") Then
  open "bbslog3.txt" for input as 1
  '最後までループ
  while NOT(EOF(1))
    'checkに代入
    line input #1,check
    'checkが存在するか?
    IF len(check)>0 Then
          '分割:<>で分割
           split check by "<>" to check_onamae,check_comdata,check_email,check_url
           IF comment=check_comdata then CALL errormes("過去に同じ内容の書き込みがあります")
    END IF
   wend

close 1

END IF



これは読み込み部分の応用です。
bbslog3.txtの存在を確認した後、bbslog3.txtをopenで開きます。whileで1行ずつ読み取りを開始します。
行はcheck変数に入り、len(check)>0が真(TRUE)なら、つまり空白行でなければthen以降を実行、splitでcheckを<>で分解、
to以降に記載されている各変数に代入していきます。 comment=check_comdataでコメントが重複していないか調べます。
もし、重複していれば"過去に同じ内容の書き込みがあります"とエラーになるわけです。


その他の変更点:bbs11.basからbbs12.basに変更しました







3.書き込み後の更新(リロード)は出来ないの?
1で説明したように、大抵のブラウザには更新ボタン(リロード)がついています。
ですが、bbs12.basで対策しましたのでこの更新機能を使うと過去に同じ内容の書き込みがありますとの
警告メッセージが出てしまい正常に更新が出来ません。本来の目的である二重投稿は防ぎましたが、
その代償が『リロードできない』となると・・・あまり使い勝手のよい掲示板とはいえません







4.リダイレクトせよ

CGIの便利な機能に、リダイレクト(他のURLに転送させること)させる機能があります。
使い方もいたって簡単です。

今までprint "Content-Type: text/html; charset=euc-jp\n\n"と書いてきた部分を
print "Location:リダイレクト先URL\n\n"に変えるだけです。

こうすることによりブラウザにリダイレクト情報を送信します。ブラウザはリダイレクト先URLを表示します。
リダイレクト後の更新ではPOSTの内容が再送されることはありません。
このリダイレクトの方法はCGIであれば、言語にかかわらず利用できます。

この機能を応用することにより、条件ごとにURLを振り分けたりできます。
(例:リダイレクト先はhtmlでもかまわないので、ケータイの場合は指定したURLに転送する等)
▼備考
HTMLによるリダイレクトの方法やjavascriptによるリダイレクトの方法もあります。
HTMLでのリダイレクトは<META>タグを使う方法ですが、瞬時にリダイレクトできないのが欠点です
javascriptで実現することも出来ますが、ブラウザが対応していない場合がありあります。







5.リロードしても、大丈夫!!

-bbs13.bas-
#!/usr/bin/scriba

import cgi.bas

'commentが送信されているか?
IF cgi::POSTParam("comment") <> undef Then CALL kakikomi

'読み込みを表示
CALL yomikomi

'プログラムはここまで
END

'読み込み部分
SUB yomikomi
        print "Content-Type: text/html; charset=euc-jp\n\n"

        print """
        <html><body>
        <form action="bbs13.bas" method="POST">
        お名前:<input type="text" name="onamae" size=20><br>
        Email:<input type="text" name="email" size=20><br>
        ▼コメント<br>
        <textarea name="comment" rows=4 cols=40></textarea><br>
        URL:<input type="text" name="url" value="http://" size=50><br>
        <input type="submit" value="送信">
        </form>
        """

        '読み込み部分(ファイルが存在する場合)
        IF FILEEXISTS("bbslog3.txt") Then
                open "bbslog3.txt" for input as 1

                '最後までループ
                while NOT(EOF(1))
                        'dataに代入
                        line input #1,data

                        'dataが存在するか?
                        IF len(data)>0 Then
                                '分割:<>で分割
                                split data by "<>" to onamae,comdata,email,url
                                
                                
                                
                                'emailが書き込まれているか?
                                IF email <> "" Then 
                                        print "お名前:<a href=\"mailto:",email,"\">",onamae,"</a>"
                                ELSE
                                        print "お名前:",onamae
                                END IF


                                print "<br>",comdata,"<br>"
                                
                                'urlがhttp://以外なら
                                IF url<>"http://\n" Then print "<a href=\"",url,"\">",url,"</a>"
                                
                                print "<hr>"

                        END IF
                wend
                close 1
        ELSE
                print "ファイルがありません"
        END IF

        print "</html></body>"

END SUB

'書き込み部分
SUB kakikomi
        '変数に代入
        comment=cgi::POSTParam("comment")
        onamae=cgi::POSTParam("onamae")
        email=cgi::POSTParam("email")
        url=cgi::POSTParam("url")

        'HTMLタグの置換
        comment=REPLACE(comment,"<","&lt;")
        comment=REPLACE(comment,">","&gt;")

        onamae=REPLACE(onamae,"<","&lt;")
        onamae=REPLACE(onamae,">","&gt;")
        email=REPLACE(email,"<","&lt;")
        email=REPLACE(email,">","&gt;")
        url=REPLACE(url,"<","&lt;")
        url=REPLACE(url,">","&gt;")

        '入力検査部分
        IF onamae="" then CALL errormes("お名前が記入されていません")
        IF comment="" then CALL errormes("コメントが記入されていません")

        '文字数検査
        IF len(comment)>1000 then CALL errormes("コメントが1000文字以下ではありません")
        IF len(onamae)>30 then CALL errormes("お名前が30文字以下ではありません")
        IF len(email)>64 then CALL errormes("Emailが64文字以下ではありません")
        IF len(url)>128 then CALL errormes("URLが128文字以下ではありません")

        '改行を<br>に
        comment=REPLACE(comment,"\r\n","<br>")
        comment=REPLACE(comment,"\r","<br>")
        comment=REPLACE(comment,"\n","<br>")

        '過去のデータをチェック
        IF FILEEXISTS("bbslog3.txt") Then

                        open "bbslog3.txt" for input as 1
                        '最後までループ
                        while NOT(EOF(1))

                                'checkに代入
                                line input #1,check

                                'checkが存在するか?
                                IF len(check)>0 Then
                                        '分割:<>で分割
                                        split check by "<>" to check_onamae,check_comdata,check_email,check_url
                                        IF comment=check_comdata then CALL errormes("過去に同じ内容の書き込みがあります")
                                END IF
                        wend
                        
                        close 1
        END IF



        '書き込み
        open "bbslog3.txt" for append as 1

        'ロック
        LOCK #1,write
        print #1,onamae,"<>",comment,"<>",email,"<>",url,"\n"

        'ロック解除
        LOCK #1,release
        close 1
        
        print "Location:http://127.0.0.1/cgi-bin/bbs13.bas\n\n"
        END
END SUB


'errormesサブルーチン
SUB errormes(errmessage)
        'メッセージを出力
        print "Content-Type: text/html; charset=euc-jp\n\n"
        print "<html><body>",errmessage,"</body></html>"
        'ここでプログラム終了
        END
END SUB

書き込み部分(kakikomiサブルーチン)の最後にprint "Location:http://127.0.0.1/cgi-bin/bbs13.bas\n\n"ENDを追加、
例によってファイル名をbbs13.basに変更しました。

print "Location:http://127.0.0.1/cgi-bin/bbs13.bas\n\n"でまったく同じCGI(bbs13.cgi)にリダイレクトしています。
このようにして、リロードしてもPOSTの中身を再送しないようにしています。
次のENDでプログラムを終了しています。
その他は以前のプログラムと同じです

戻る

ウメ研究所