#!/usr/local/bin/perl ## -----------------------------------------------------------------------------+ ## LIGHT BOARD v5.52 ## (c)1997-1999 KENT WEB (1999/11/25) ## E-MAIL: webmaster@kent-web.com ## WWW: http://www.kent-web.com/ $ver = 'LIGHT v5.52'; # バージョン情報(修正不要) ## -----------------------------------------------------------------------------+ ## [注意事項・合意事項] ## 1.このスクリプトはフリーソフトです。このスクリプトを使用したいかなる損害に ## 対して作者はその責任を一切負いません。 ## 2.設置に関する質問はサポート掲示板にお願いいたします。メールによる質問には ## お答えできません。 ## -----------------------------------------------------------------------------+ ## [設置例] かっこ内はパーミッション ## public_html / index.html (ホームページ) ## | ## +-- light [777] / light.cgi [755] ## light.log [666] ## jcode.pl [644] ## light2.cgi [755] .. 補助プログラム(過去ログ/ログ編集) ## pastno.dat [666] .. 過去ログ用カウントファイル ## ## -----------------------------------------------------------------------------+ #============# # 設定項目 # #============# # 文字コード変換ライブラリ require './jcode.pl'; # 管理者用マスタパスワード(半角英数字) $pass = '11t3m214'; # 過去ログ機能 (0=no 1=yes) : light2.cgi必須 $pastkey = 1; # 過去ログのあるディレクトリ $past_dir = "."; # 過去ログカウントファイル $nofile = './pastno.dat'; # 過去ログ1ファイル当りの行数の限度 $log_line = '150'; # 補助プログラムのファイル名 $light2 = './light2.cgi'; # タグの許可 (0=no 1=yes) $tagkey = 0; # URLの自動リンク (0=no 1=yes) $autolink = 1; # 日付のタイプ (0=洋式 1=和式) $date_type = 0; # スクリプト名 $script = './light.cgi'; # ログファイル名 $logfile = './light.log'; # methodの形式 (POST or GET) $method = 'POST'; # 1ページ当たりの記事表示数 $pagelog = 10; # ファイルロック形式 (0=no 1=symlink 2=open) $lockkey = 1; # ロックファイル名 $lockfile = './light.lock'; # コメント欄改行形式 (soft=手動 hard=強制) $wrap = 'soft'; # sendmailパス(メール通知する時) $sendmail = '/usr/lib/sendmail'; # 自分の記事をメール送信する (0=no 1=yes) $mail_me = 0; # 他サイトから投稿排除する時 (http://からURLを記述) $base_url = "."; #============# # 設定完了 # #============# ## LIGHT BOARDのメイン処理 &decode; if ($mode eq "howto") { &howto; } elsif ($mode eq "find") { &find; } elsif ($mode eq "usr_del") { &usr_del; } elsif ($mode eq "msg") { ®ist; } &html_log; ## --- HTMLのヘッダー sub header { print "Content-type: text/html\n\n"; print "\n\n"; print "\n"; print "$title\n"; if ($bgr) { print "\n"; } else { print "\n"; } } ## --- HTMLのフッター sub footer { ## 著作権表示(削除不可) print "

\n"; print "- Light Board -\n"; print "
\n"; print "\n"; } ## --- 記事表示部 sub html_log { # ブラウザを判断 &get_agent; # ログを読み込み open(LOG,"$logfile") || &error("Can't open $logfile"); @lines = ; close(LOG); # 環境設定部を認識 $init = $lines[0]; ($head,$title,$t_color,$t_size,$t_face,$bgr,$bgc,$text,$link, $vlink,$alink,$home,$max,$subj_color,$name_color,$mail1,$mail2) = split(/<>/,$init); # ログチェック unless ($init =~ /^LIGHT/) { &error("ログが正しくありません。"); } shift(@lines); # クッキーを取得 &get_cookie; # 表示開始 &header; print "
\n"; print "$title
\n"; print "[トップにもどる]\n"; print "[掲示板の使い方]\n"; print "[ワード検索]\n"; # 過去ログのリンク if ($pastkey) { print "[過去ログ]\n"; } # ログ編集機能のリンク print "[管理用]\n"; # 返信モードの場合 if ($mode eq "res") { foreach $line (@lines) { ($number,$date,$name,$email,$subj,$comment) = split(/<>/,$line); if ($number eq "$FORM{'resmode'}") { last; } } $res_comment = "\>\; $comment"; $res_comment =~ s/
/\r\>\; /g; # 返信用項目を作成 if ($subj =~ /^Re/) { $subj =~ s/Re//; $res_sub = "Re\[$number\]" . "$subj"; } else { $res_sub = "Re\[$number\]\: $subj"; } $com_wid = $com_wid + 2; } else { $res_subj = ""; $res_comment = ""; } print <<"EOM";
おなまえ
Eメール
題  名  
コメント
URL
削除キー (記事削除時に使用。英数字で8文字以内)

EOM if ($FORM{'page'} eq '') { $page = 0; } else { $page = $FORM{'page'}; } # 記事数を取得 $end_data = @lines - 1; $page_end = $page + ($pagelog - 1); if ($page_end >= $end_data) { $page_end = $end_data; } foreach ($page .. $page_end) { ($number,$date,$name,$email,$subj,$comment,$url,$host,$pwd) = split(/<>/,$lines[$_]); if ($email) { $name = "$name"; } if ($url) { $url = "http://$url\n"; } # 自動リンク if ($autolink) { &auto_link($comment); } print "\n"; print "\n"; print "
[$number] $subj "; print "投稿者:$name "; print "投稿日:$date 
\n"; print "\n"; print "\n"; print "\n"; print "
\n"; print "
$comment

$url


\n"; } print "\n"; # 改頁処理 $next_line = $page_end + 1; $back_line = $page - $pagelog; # 前頁処理 if ($back_line >= 0) { print "\n"; } # 次頁処理 if ($page_end ne $end_data) { print "\n"; } # ユーザ記事削除フォーム print "
\n"; print "\n"; print "\n"; print "
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; print "以下のフォームから自分の投稿記事を削除できます
\n"; print "■記事No\n"; print "■削除キー\n"; print "\n"; print "\n"; print "
\n"; &footer; exit; } ## --- ログ書き込み処理 sub regist { # 他サイトからのアクセスを排除 if ($base_url ne ".") { $ref_url = $ENV{'HTTP_REFERER'}; $ref_url =~ s/\?(.|\n)*//ig; $ref_url =~ s/\%7E/\~/ig; if ($ref_url && $ref_url !~ $base_url) { &error("不正なアクセスです。"); } } # フォームセキュリティ if ($name eq "") { &error("名前が入力されていません。"); } if ($comment eq "") { &error("コメントが入力されていません。"); } if ($email && $email !~ /(.*)\@(.*)\.(.*)/) { &error("Eメールの入力内容が正しくありません。"); } # ファイルロック if ($lockkey == 1) { &lock1; } elsif ($lockkey == 2) { &lock2; } # ログを開く open(LOG,"$logfile") || &error("Can't open $logfile"); @lines = ; close(LOG); # ログチェック $init = $lines[0]; unless ($init =~ /^LIGHT/) { &error("ログが正しくありません。"); } # 設定を認識 ($head,$title,$t_color,$t_size,$t_face,$bgr, $bgc,$text,$link,$vlink,$alink,$home,$max, $subj_color,$name_color,$mail1,$mail2) = split(/<>/,$init); # 二重投稿の禁止 ($knum,$kdate,$kname,$kemail,$ksub,$kcom) = split(/<>/,$lines[1]); if ($name eq $kname && $comment eq $kcom) { &error("二重投稿は禁止です"); } shift(@lines); ## 過去ログを取得する場合 if ($pastkey && $#lines >= $max-1) { &pastlog; } # 記事Noカウント及び最大記事数超を切り捨て $number = $knum + 1; if ($#lines >= $max-1) { splice(@lines,$max-1); } # 削除キーを暗号化 if ($pwd) { &pass_ango($pwd); } # ホスト名を取得 &get_host; # ログをフォーマット unshift (@lines,"$number<>$date<>$name<>$email<>$sub<>$comment<>$url<>$host<>$ango<>\n"); # ヘッダ部を付加 unshift (@lines,$init); # ログを更新 open(LOG,">$logfile") || &error("Can't write $logfile"); print LOG @lines; close(LOG); # ロック解除 if (-e $lockfile) { unlink($lockfile); } # クッキーを発行 &set_cookie; # メール処理 if ($mail1 && $mail_me == 0 && $email ne "$mail1") { &mailto; } elsif ($mail1 && $mail_me) { &mailto; } } ## --- フォームからのデータ処理 sub decode { if ($ENV{'REQUEST_METHOD'} eq "POST") { if ($ENV{'CONTENT_LENGTH'} > 51200) { &error("投稿量が大きすぎます。"); } read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # S-JIS変換 &jcode'convert(*value,'sjis'); # タグ処理 if ($tagkey == 0) { $value =~ s/\"/"/g; $value =~ s//>/g; } else { $value =~ s///g; $value =~ s/<>/<>/g; } $FORM{$name} = $value; } $name = $FORM{'name'}; $name =~ s/\r//g; $name =~ s/\n//g; $comment = $FORM{'comment'}; $comment =~ s/\r\n/
/g; $comment =~ s/\r/
/g; $comment =~ s/\n/
/g; $email = $FORM{'email'}; $email =~ s/\r//g; $email =~ s/\n//g; $url = $FORM{'url'}; $url =~ s/\r//g; $url =~ s/\n//g; $url =~ s/^http\:\/\///; $mode = $FORM{'mode'}; $pwd = $FORM{'pwd'}; $pwd =~ s/\r//g; $pwd =~ s/\n//g; $sub = $FORM{'sub'}; $sub =~ s/\r//g; $sub =~ s/\n//g; if ($sub eq "") { $sub = "無題"; } # 日時の取得 $ENV{'TZ'} = "JST-9"; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; $mon++; if ($mon < 10) { $mon = "0$mon"; } if ($mday < 10) { $mday = "0$mday"; } if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } # 日時のフォーマット if ($date_type) { $youbi = ('日','月','火','水','木','金','土') [$wday]; $date = "$year年$mon月$mday日 ($youbi) $hour時$min分"; } else { $youbi = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat') [$wday]; $date = "$year/$mon/$mday($youbi) $hour\:$min"; } } ## --- 掲示板の使い方メッセージ sub howto { # ログを読み込み open(LOG,"$logfile") || &error("Can't open $logfile"); @lines = ; close(LOG); # 環境設定部を認識 ($head,$title,$t_color,$t_size,$t_face,$bgr,$bgc,$text,$link,$vlink,$alink,$home,$max,$subj_color,$name_color,$mail1,$mail2) = split(/<>/,$lines[0]); if ($tagkey == 0) { $tag_msg = "投稿内容には、タグは一切使用できません。\n"; } else { $tag_msg = "コメント欄には、タグ使用をすることができます。\n"; } &header; print <<"HTML"; [掲示板にもどる]
掲示板の利用上の注意

  1. この掲示板はクッキー対応です。1度記事を投稿いただくと、おなまえ、Eメール、URL、削除キーの情報は2回目以降は自動入力されます。(ただし利用者のブラウザがクッキー対応の場合)

  2. $tag_msg

  3. 記事を投稿する上での必須入力項目は「おなまえ」「メッセージ」です。Eメール、URL、題名、削除キーは任意です。

  4. 記事には、半角カナは一切使用しないで下さい。文字化けの原因となります。

  5. 記事の投稿時に「削除キー」にパスワード(英数字で8文字以内)を入れておくと、その記事は次回削除キーによって削除することができます。

  6. 記事の保持件数は最大 $max件です。それを超えると古い順に自動削除されます。

  7. 既存の記事に簡単に「返信」することができます。各記事にある「返信」ボタンを押すと投稿フォームが返信用となります。

  8. 過去の投稿記事から「キーワード」によって簡易検索ができます。トップメニューの「ワード検索」のリンクをクリックすると検索モードとなります。

  9. 管理者が著しく不利益と判断する記事や他人を誹謗中傷する記事は\予\告\なく削除することがあります。

HTML &footer; exit; } ## --- ワード検索サブルーチン sub find { # ログを読み込み open(LOG,"$logfile") || &error("Can't open $logfile"); @lines = ; close(LOG); # 環境設定部を認識 ($head,$title,$t_color,$t_size,$t_face,$bgr,$bgc,$text,$link,$vlink,$alink,$home,$max,$subj_color,$name_color,$mail1,$mail2) = split(/<>/,$lines[0]); &header; print <<"HTML"; [掲示板にもどる]
ワード検索

■検索したいキーワードを入力し、検索条件を選択し「検索する」を押してください。
■複数のキーワードを入力するときは、半角スペースで区切って下さい。

キーワード
検索条件 AND OR
HTML # ワード検索の実行と結果表示 if ($FORM{'word'} ne "") { # 入力内容を整理 $cond = $FORM{'cond'}; $word = $FORM{'word'}; $word =~ s/ / /g; $word =~ s/\t/ /g; @pairs = split(/ /,$word); shift(@lines); # 検索処理 foreach $line (@lines) { $flag = 0; foreach $pair (@pairs){ if (index($line,$pair) >= 0){ $flag = 1; if ($cond eq 'or') { last; } } else { if ($cond eq 'and'){ $flag = 0; last; } } } if ($flag == 1) { push(@new,$line); } } # 検索終了 $count = @new; print "
検索結果:$count件

\n"; print "

    \n"; foreach $line (@new) { ($number,$date,$name,$email,$subj,$comment,$url) = split(/<>/,$line); if ($email) { $name = "$name"; } if ($url) { $url = "http://$url"; } # 結果を表示 print "
  1. [$number] $subj\n"; print "投稿者:$name 投稿日:$date

    \n"; print "

    $comment

    $url


    \n"; } print "
\n"; } &footer; exit; } ## --- ブラウザを判断しフォーム幅を調整 sub get_agent { # ブラウザ情報を取得 $agent = $ENV{'HTTP_USER_AGENT'}; $nam_wid = 20; $subj_wid = 25; $com_wid = 56; $url_wid = 50; # MSIE3の場合 if ($agent =~ /MSIE 3/i) { $nam_wid = 30; $subj_wid = 40; $com_wid = 65; $url_wid = 48; } # MSIE4の場合 elsif ($agent =~ /MSIE 4/i || $agent =~ /MSIE 5/i) { $nam_wid = 30; $subj_wid = 38; $com_wid = 58; $url_wid = 68; } } ## --- クッキーの発行 sub set_cookie { ($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg,$ydayg,$isdstg) = gmtime(time + 60*24*60*60); $yearg += 1900; if ($secg < 10) { $secg = "0$secg"; } if ($ming < 10) { $ming = "0$ming"; } if ($hourg < 10) { $hourg = "0$hourg"; } if ($mdayg < 10) { $mdayg = "0$mdayg"; } $mong = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', 'Oct','Nov','Dec') [$mong]; $youbi = ('Sunday','Monday','Tuesday','Wednesday','Thursday', 'Friday','Saturday') [$wdayg]; $date_gmt = "$youbi, $mdayg\-$mong\-$yearg $hourg:$ming:$secg GMT"; $cook="name\:$name\,email\:$email\,url\:$url\,pwd\:$pwd"; print "Set-Cookie: LIGHTBBS=$cook; expires=$date_gmt\n"; } ## --- クッキーを取得 sub get_cookie { @pairs = split(/\;/,$ENV{'HTTP_COOKIE'}); foreach $pair (@pairs) { local($name, $value) = split(/\=/, $pair); $name =~ s/ //g; $DUMMY{$name} = $value; } @pairs = split(/\,/,$DUMMY{'LIGHTBBS'}); foreach $pair (@pairs) { local($name, $value) = split(/\:/, $pair); $COOKIE{$name} = $value; } $c_name = $COOKIE{'name'}; $c_email = $COOKIE{'email'}; $c_url = $COOKIE{'url'}; $c_pwd = $COOKIE{'pwd'}; if ($FORM{'name'}) { $c_name = $FORM{'name'}; } if ($FORM{'email'}) { $c_email = $FORM{'email'}; } if ($url) { $c_url = $url; } if ($FORM{'pwd'}) { $c_pwd = $FORM{'pwd'}; } } ## --- エラー処理 sub error { if (-e $lockfile) { unlink($lockfile); } print "Content-type: text/html\n\n"; print "\n\n"; print "

ERROR !

\n"; print "

$_[0]\n"; print "


\n"; &footer; exit; } ## --- 記事削除処理 sub usr_del { if ($FORM{'usr_no'} eq "" || $FORM{'usr_key'} eq "") { &error("削除No又は削除キーが入力されていません。"); } # ロック開始 if ($lockkey == 1) { &lock1; } elsif ($lockkey == 2) { &lock2; } # ログを読み込む open(DB,"$logfile") || &error("Can't open $logfile"); @lines = ; close(DB); # ログチェック $init = $lines[0]; unless ($init =~ /^LIGHT/) { &error("ログが正しくありません。"); } shift(@lines); @new = (); $no_del = 0; ## マスターパスワードによる記事削除 ## if ($FORM{'usr_key'} eq "$pass"){ foreach $line (@lines){ ($number,$date,$name,$email,$subj,$comment,$url,$host,$ango) = split(/<>/,$line); $flag=0; if ($FORM{'usr_no'} eq "$number") { $flag=1; } if ($flag == 0) { push(@new,$line); } } } ## 削除キーによる記事削除 ## else { foreach $line (@lines) { ($number,$date,$name,$email,$subj,$comment,$url,$host,$ango) = split(/<>/,$line); $flag = 0; if ($FORM{'usr_no'} eq "$number") { if ($ango eq "") { $no_del = 1; last; } # パスワードを照合 &pass_shogo($FORM{'usr_key'}); if ($check eq "yes") { $flag = 1; } else { $no_del = 2; last; } } if ($flag == 0) { push(@new,$line); } } if ($no_del == 1) { &error("削除キーが設定されていません。"); } elsif ($no_del == 2) { &error("パスワードが違います。"); } } ## ログを更新 ## unshift(@new,$init); open(DB,">$logfile") || &error("Can't write $logfile"); print DB @new; close(DB); # ロック解除 if (-e $lockfile) { unlink($lockfile); } } ## --- ロックファイル(symlink関数) sub lock1 { local($retry) = 5; while (!symlink(".", $lockfile)) { if (--$retry <= 0) { &error("LOCK is BUSY"); } sleep(1); } } ## --- ロックファイル(open関数) sub lock2 { local($flag) = 0; foreach (1 .. 5) { if (-e $lockfile) { sleep(1); } else { open(LOCK,">$lockfile"); close(LOCK); $flag = 1; last; } } if ($flag == 0) { &error("LOCK is BUSY"); } } ## --- メール送信 sub mailto { $mail_sub = "$title に投稿がありました。"; &jcode'convert(*mail_sub,'jis'); &jcode'convert(*name,'jis'); &jcode'convert(*sub,'jis'); &jcode'convert(*comment,'jis'); if ($date_type) { &jcode'convert(*date,'jis'); } $comment =~ s/
/\n/g; $comment =~ s/<//g; $comment =~ s/&/\&/g; # メールアドレスがない場合はダミーメールに置き換え if ($FORM{'email'} eq "") { $email = "nomail\@xxx.xxx"; } if (!open(MAIL,"| $sendmail -t")) { &error("メール送信に失敗しました。");} print MAIL "To: $mail1\n"; print MAIL "From: $email\n"; if ($mail2) { print MAIL "CC: $mail2\n"; } print MAIL "Subject: $mail_sub\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-type: text/plain; charset=ISO-2022-JP\n"; print MAIL "Content-Transfer-Encoding: 7bit\n"; print MAIL "X-Mailer: $ver\n\n"; print MAIL "--------------------------------------------------------\n"; print MAIL "TIME : $date\n"; print MAIL "NAME : $name\n"; print MAIL "EMAIL: $FORM{'email'}\n"; if ($url ne "") { print MAIL "URL : http://$url\n"; } if ($FORM{'sub'} eq "") { $sub = "no title"; } print MAIL "TITLE: $sub\n\n"; print MAIL "$comment\n\n"; print MAIL "--------------------------------------------------------\n"; close(MAIL); } ## --- パスワード暗号処理 sub pass_ango { $now = time; ($p1, $p2) = unpack("C2", $now); $wk = $now / (60*60*24*7) + $p1 + $p2 - 8; @saltset = ('a'..'z','A'..'Z','0'..'9','.','/'); $nsalt = $saltset[$wk % 64] . $saltset[$now % 64]; $ango = crypt($_[0], $nsalt); } ## --- パスワード照合処理 sub pass_shogo { if ($ango =~ /^\$1\$/) { $crptkey = 3; } # FreeBSDサーバ対応 else { $crptkey = 0; } $check = "no"; if (crypt($_[0], substr($ango,$crptkey,2)) eq "$ango") { $check = "yes"; } } ## --- 自動リンク sub auto_link { $_[0] =~ s/([^=^\"]|^)(http\:[\w\.\~\-\/\?\&\+\=\:\@\%\;\#]+)/$1$2<\/a>/g; } ## --- 過去ログ生成 sub pastlog { $new_flag = 0; open(NUM,"$nofile") || &error("Can't open $nofile"); $count = ; close(NUM); # 過去ログのファイル名を定義 $pastfile = "$past_dir\/$count\.html"; # 過去ログがない場合、新規に自動生成する unless(-e $pastfile) { &new_log; } if ($new_flag == 0) { open (DB,"$pastfile") || &error("Can't open $pastfile"); @past = ; close(DB); } # 規定の行数をオーバーすると、次ファイルを自動生成する if ($#past > $log_line) { &next_log; } $pst_line = $lines[$max-1]; $pst_line =~ s/\n//g; ($pnumber,$pdate,$pname,$pemail,$psubj,$pcomment,$purl,$phost) = split(/<>/, $pst_line); if ($pemail ne "") { $pname = "$pname"; } if ($purl ne "") { $purl = "http://$purl"; } # 自動リンク if ($autolink) { &auto_link($pcomment); } $html = <<"HTML"; [$pnumber] $psubj 投稿者:$pname 投稿日:$pdate

$pcomment

$purl


HTML @news = (); foreach $line (@past) { if ($line =~ //i) { last; } push (@news,$line); if ($line =~ //i) { push (@news,"$html"); } } push (@news,"\n\n"); open(DB,">$pastfile") || &error("Can't write $pastfile"); print DB @news; close(DB); }## --- 過去ログ完了 --- ## # 過去ログ次ファイル生成ルーチン sub next_log { # 次ファイルのためのカウントアップ $count++; # カウントファイル更新 open(NUM,">$nofile") || &error("Can't write $nofile"); print NUM "$count"; close(NUM); $pastfile = "$past_dir\/$count\.html"; &new_log; } # 新規過去ログファイル生成ルーチン sub new_log { $new_flag = 1; $past[0] = "過去ログ\n"; $past[1] = "
\n"; $past[2] = "<\!--HAJIME-->\n"; $past[3] = "<\!--OWARI-->\n"; $past[4] = "\n"; # 新規過去ログファイルを生成更新 open(DB,">$pastfile") || &error("Can't write $pastfile"); print DB @past; close(DB); # パーミッションを666へ。 chmod(0666,"$pastfile"); } ## --- ホスト名を取得 sub get_host { $host = $ENV{'REMOTE_HOST'}; $addr = $ENV{'REMOTE_ADDR'}; if ($host eq "" || $host eq "$addr") { $host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2); } if ($host eq "") { $host = $addr; } }