掲示板(URL自動変換/連続改行・スペース削除)
#! /usr/local/bin/perl use Jcode; $FILE = './dat/board.dat'; #書き込み保存ファイル $MAX = 100; #保存件数 $VIEW = 10; #1ページの表示件数 $TEXTMAX = 1000; #本文文字数制限(全角) $NAMEMAX = 10; #名前文字数制限(全角) $TITLEMAX = 20; #題名文字数制限(全角) $PASSWORD = '1234'; #削除用パスワード $time = time; loadForm(); #フォームデータ取り込み loadData(); #記事データ読み込み print qq(Content-type: text/html; charset=Shift_JIS\n\n); print <<END; #HTML出力 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>掲示板</title> <style type="text/css"> <!-- body { padding:10px 5%; background:#eef } hr { display:none } form { margin:5px 0; padding:5px 0; border-bottom:3px solid #f60 } table { margin:20px 5%; width:90%; border:1px solid #963 } th { background:#fc9; text-align:left } td { padding:10px; background:#fff } h1 { margin:0px; font-size:22px; border-bottom:3px solid #f60 } textarea { width:80% } .small { font-size:12px; text-align:right } .err { padding:10px 0; color:#f33; font-weight:bolder; text-align:center; border-bottom:3px solid #f60 } //--> </style> <script language="JavaScript"> <!-- function check() { //空欄・文字数チェック for(i = 0 ; i < document.form.length ; i++) { with(document.form.elements[i]) { if(value == "") { alert("すべての項目を入力してください!!"); focus(); return false; } if(name == "text" && value.length > $TEXTMAX) { alert("文字数オーバーです!!(" + value.length + "文字)"); focus(); return false; } } } } //--> </script> </head> <body> <h1>掲 示 板</h1> <hr> <form action="$ENV{'SCRIPT_NAME'}" method="POST" name="form" onSubmit="return check()"> 名前:<input type="text" name="name" size="50" maxlength="$NAMEMAX" value="$FORM{'name'}"><br> <br> 題名:<input type="text" name="title" size="50" maxlength="$TITLEMAX"><br> <br> 本文:<textarea name="text" rows="10" cols="70"></textarea><br> <small>※$TEXTMAX字以内 ※HTML使用不可(ホームページアドレス・メールアドレスはリンクに自動変換)</small><br> <br> <input type="hidden" name="mode" value="write"> <input type="submit" value=" 書き込み "><br> </form> <hr> END if($ERR) { #エラーチェック print <<" END"; <div class="err">【エラー】$ERR!!</div> <hr> END } printData(); #記事出力 print <<END; #HTML出力 </body> </html> END exit; #==============================================================================記事出力 sub printData { my $next = $FORM{'next'} + $VIEW; if($next > @DATA) { $next = @DATA; } print qq(<form action="$ENV{'SCRIPT_NAME'}" method="POST">\n); for($i = $FORM{'next'} ; $i < $next ; ++$i) { my ($tm, $name, $title, $text, $agent, $addr) = split(/\t/, $DATA[$i]); my ($sec, $min, $hour, $date, $mon, $year, $day) = localtime($tm); if($title eq "") { $title = "無題"; } # $text =~ s/(http:\/\/[\w\.\/\-\~\?\=\+\%(&)]+)/<a href="$1">$1<\/a>/g; #URL変換 # $text =~ s/([\w\.\-]+@[\w\.\-]+)/<a href="mailto:$1">$1<\/a>/g; #メールアドレス変換 print qq(<table cellspacing="0">); print qq(<tr>); printf qq(<th><input type="radio" name="no" value="%d">【$title】</th>), $i; printf qq(<th class="small">$name [%02d/%02d %02d:%02d]</th>), ++$mon, $date, $hour, $min; print qq(</tr>); # if($FORM{'pass'} eq $PASSWORD) { # print qq(<tr>); # print qq(<th colspan="2" class="small">$agent<br>$addr</th>); # print qq(</tr>); # } print qq(<tr>); print qq(<td colspan="2">$text</td>); print qq(</tr>); print qq(</table>\n); print qq(<hr>\n); } print qq(<div align="right">\n); print qq(<input type="hidden" name="mode" value="delete">\n); print qq(<input type="hidden" name="next" value="$FORM{'next'}">\n); print qq(<input type="password" name="pass" value="$FORM{'pass'}" size="4">\n); print qq(<input type="submit" value=" 削 除 ">\n); print qq(</div>\n); print qq(</form>\n); print qq(<hr>\n); print qq(<center>\n); if($FORM{'next'}) { #前ページへのリンク printf qq(<a href="$ENV{'SCRIPT_NAME'}?next=%d">≪前ページ</a>\n), $FORM{'next'} - $VIEW; } else { print qq(≪前ページ\n); } for($i = 0 ; $i < @DATA ; $i += $VIEW) { #ページへのリンク if($i == $FORM{'next'}) { printf qq(%d\n), $i / $VIEW + 1; } else { printf qq(<a href="$ENV{'SCRIPT_NAME'}?next=$i">%d</a>\n), $i / $VIEW + 1; } } if($next < @DATA) { #次ページへのリンク print qq(<a href="$ENV{'SCRIPT_NAME'}?next=$next">次ページ≫</a>\n); } else { print qq(次ページ≫\n); } print qq(</center>\n); } #==============================================================================読み込み・書き込み・削除 sub loadData { open(FILE, "<$FILE") or ($ERR = "記事ファイルが開けません" and return); #データ読み込み eval{ flock(FILE, 1) }; @DATA = <FILE>; close FILE; if($FORM{'mode'}) { if($FORM{'mode'} eq 'write') { #データ追加 my ($tm, $name, $title, $text) = split(/\t/, $DATA[0]); if($FORM{'text'} eq "") { $ERR = "本文が空白"; return; } if(length($FORM{'text'}) > $TEXTMAX * 2 or length($FORM{'name'}) > $NAMEMAX * 2 or length($FORM{'title'}) > $TITLEMAX * 2 ){ $ERR = "文字数オーバー"; return; } if($FORM{'text'} eq $text) { $ERR = "書き込み済み"; return; } unshift @DATA, "$time\t$FORM{'name'}\t$FORM{'title'}\t$FORM{'text'}\t" . "$ENV{'HTTP_USER_AGENT'}\t$ENV{'REMOTE_ADDR'}\t\n"; while(@DATA > $MAX) { pop @DATA; } } elsif($FORM{'mode'} eq 'delete') { #データ削除 if($FORM{'no'} eq "") { return; } if($FORM{'pass'} ne $PASSWORD) { $ERR = "削除パスワードが違います"; return; } splice @DATA, $FORM{'no'}, 1; } #サンプルにつき書き込み停止 #open(FILE, ">$FILE"); #データ書き込み #eval{ flock(FILE, 2) }; #print FILE @DATA; #close FILE; } } #==============================================================================フォームデータ取り込み sub loadForm { my ($query, $pair); if($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN, $query, $ENV{'CONTENT_LENGTH'}); } else { $query = $ENV{'QUERY_STRING'}; } foreach $pair (split(/&/, $query)) { my ($key, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/chr(hex($1))/eg; $value = Jcode::convert($value, 'sjis'); $value =~ s/&/&/g; $value =~ s/</</g; $value =~ s/>/>/g; $value =~ s/\x81\x40/ /g; #全角スペースを半角スペースに変換 $value =~ s/(\s*\x0D\x0A\s*)+/<br>/g; #改行を<br>に変換(前後のスペース・連続改行削除) $value =~ s/\s+/ /g; #連続スペースをスペース1文字に変換 if($value eq "<br>" or $value eq " ") { #改行・スペースのみの場合 削除 $value = ""; } if(substr($value, 0, 4) eq "<br>") { #先頭が改行の場合 削除 $value =~ s/<br>//; } $FORM{$key} = $value; } }
〔 実行する 〕