#! /opt/gnu/bin/perl ;# ↑このパスはプロバイダによって違うので調べて設定する ;# (これはこのスクリプトの最初の1行になければならず、それより上に空行があってもいけません。) ;# (この設定が必要ないサーバもあります。一般的な場合を想定して解説を入れています。) ;# (他に、プロバイダからアナウンスされている情報を十分理解しておいてください。) ;# ;# FBBS ver 1.0 based on ;# 簡易BBS version 7.5(フリーソフト) ;# ;# Script written by Kazu.Y ;# Created on: 02/05/96 ;# Last Modified on: 11/06/97 ;# I can be reached at: rescue@ask.or.jp ;# Scripts Found at: http://www.ask.or.jp/~rescue/cgitips/ ;# Script moditied by T.Tajima (takeshi@comp.cs.gunma-u.ac.jp) ;# ;# <利用規定の抜粋> ;# 1.このスクリプトは自分で使うために承諾なしに自由に改造することができます。 ;# 2.改造の有無にかかわらず、このスクリプトを再配布することはできません。 ;# 3.このシステムを有償で他人に設置してあげたりする行為は無断ではできません。 ########################################################################################### # # 基本構成(初期設定はこの構成を前提に解説します) # # public_html(ホームページディレクトリ) # | # |-- cgi-bin(任意のディレクトリ) # | # |-- jcode.pl (755) # |-- fbbs.cgi (755) # |-- fbbs.dat (666) # |-- pic (755) # |-- pic-back.gif (バックグランド) # |-- menu-*.gif (メニュー用) # |-- m*.gif (FACE画像:男) # |-- f*.gif (FACE画像:女) # |-- t{u,d}{l,r}.gif (吹き出し枠) # # ・この minibbs.pl は minibbs.cgi にファイル名を変更する # ・minibbs.dat は中身が空っぽのファイルをパソコン上で作成して転送する # ・このシステムに必要な3つのファイルを同じ場所に設置する # ・( )内はパーミッッション値 # ・jcode.plは中身を全くいじらずにそのままアスキー転送する # ・jcode.plはjperlでは利用できないので注意すること # ・これら3つのファイルはアスキーモードで取り扱う(転送)すること # ########################################################################################### #----------------# # 初期設定 # #----------------# #--- 必ずあなたの環境に合わせて書き替える項目 --------------------------------------------# # 削除モード移行パスワードの設定(''内に任意のパスワードを記述する) $password = 'password'; # 掲示板の名前 $title = 'FBBS ver 1.0'; # 画像ディレクトリ $dir = './pic'; # 画像縦幅 $fwidth = 104; # 画像横幅 $fheight = 128; # BBS横幅 $tablewidth = 600; # このスクリプトをURLで設定 $reload = 'http://yourdomain/cgi/fbbs.cgi'; # 画面の「終了」ボタンの表示先をURLで設定 $modoru = 'http://yourdomain/yourpage.html'; #--- 必要に応じて設定する項目 ------------------------------------------------------------# # 文字色や背景などの設定(通常のタグ) # 題名と投稿者色はスクリプト内のタグを探して設定してください。 $body = ""; # タグを使えるようにするかどうかの設定 # については入力フォームが用意してあるので、いたずらやタグの # 閉じ忘れ等による混乱を避けるためにできるだけ使えないようにしておくことをお勧めします。 # 使える:1 使えない:0 $tag = 0; # 1ページに表示する件数 $def = 10; # 書き込み件数の最大登録数の設定です。この件数を超えると、古いものから削除されていきます。 # ページ処理機能が付きましたので、この件数を大きくしても一度に表示される記事数は限定されます。 # 記録されたファイルの巨大化を防止する為に、ある程度の件数で自動削除されるようにします。 $max = '50'; # 日本語コード変換ライブラリ # この jcode.pl を minibbs.cgi と違うディレクトリに設置する場合は相対的に設定すること require './jcode.pl'; # 内容が書き込まれる記録ファイルのパスを設定 # この minibbs.dat を minibbs.cgi と違うディレクトリに設置する場合は相対的に設定すること $file = './fbbs.dat'; # 海外サーバ等で時差が生じる場合は修正します # 海外時間に+9時間する場合 = localtime(time + 9*60*60); # 海外時間に−9時間する場合 = localtime(time - 9*60*60); # (参考)timeには1970年からの秒数が入っています ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); # クッキーの消化設定 # 最終書き込みから 30日後 30*24*60*60 # 1日後 24*60*60 # 10時間後 10*60*60 $ENV{'TZ'} = "GMT"; # 国際標準時を取得する ($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg,$ydayg,$isdstg) = localtime(time + 30*24*60*60); # 入力形式の設定 標準入力:post その他:get # 投稿ボタンを押して Method not implemented.. というエラーが出る場合は get で試すこと $method = 'post'; ########################################################################################### # # ・記録ファイルには処理の都合上特殊コードが記録されますので、直接編集はできません。 # ・スクリプトの中身を書き替える場合は、perlやCGIやHTMLなどのそれなりの知識が必要です。 # ・設置に関する質問はチャレンジCGI専用掲示板をご利用ください。改造の質問は受けません。 # http://www2r.meshnet.or.jp/~rescue/webboard/ # ########################################################################################### # 上記のlocaltimeで取得した$monには0から11までの数字が入るので修正処理 $month = ($mon + 1); # 時刻を2桁に統一する処理(削除処理に関係するので書き替えないこと) if ($month < 10) { $month = "0$month"; } if ($mday < 10) { $mday = "0$mday"; } if ($sec < 10) { $sec = "0$sec"; } if ($min < 10) { $min = "0$min"; } if ($hour < 10) { $hour = "0$hour"; } # 曜日変換処理 # $wdayには0から6までの数字が入り曜日に対応している $y0="日"; $y1="月"; $y2="火"; $y3="水"; $y4="木"; $y5="金"; $y6="土"; $youbi = ($y0,$y1,$y2,$y3,$y4,$y5,$y6) [$wday]; # 時刻フォーマット(削除処理に関係するので書き替えないこと) $date_now = "$month月$mday日($youbi)$hour時$min分$sec秒"; # フォーム入力されたデータを$bufferに格納する(getかpostかによって取得方法が異なる) if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } # $bufferに格納されたFORM形式のデータを取り出す @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; # 処理の都合上の処理 $value =~ s/\n//g; # 改行文字はデータの記録に影響があるので消去する if ($tag) { # 掲示板に書き込まれたくないタグを設定する(タグが使える場合に有効) if ($value =~ //i) { &error(tag); } if ($value =~ //i) { &error(tag); } if ($value =~ //i) { &error(tag); } if ($value =~ / 削除処理して通常画面へ # action=remove --> 削除記事選択画面へ # action=regist --> 記事記録処理して通常画面へ # その他 --> 通常画面へ if ($FORM{'action'} eq 'remove' && $FORM{'pwd'} eq $password) { &remove2; &remove1; exit; } elsif ($FORM{'pwd'} eq $password) { &remove1; exit; } elsif ($FORM{'action'} eq 'regist') { ®ist; } &html; sub html { #--- クッキーの取得(独自方式)-----------------------# $cookies = $ENV{'HTTP_COOKIE'}; @pairs = split(/;/,$cookies); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $name =~ s/ //g; $DUMMY{$name} = $value; } @pairs = split(/,/,$DUMMY{$reload}); foreach $pair (@pairs) { ($name, $value) = split(/:/, $pair); $COOKIE{$name} = $value; } #--- 入力フォーム画面 --------------------------------# # CGIで出力されたデータをHTMLとして認識させるヘッダの出力 print "Content-type: text/html\n\n"; print "$title\n"; print "$body\n\n"; # TABLE始め print "
\n"; print "
$title

\n\n"; # フォーム画面出力 print "

\n"; print "\n"; print "\n"; print "
\n"; print "\n"; print "
\n"; print "\n"; print "
\n"; print "\n\n"; # FACE選択 print "

\n\n"; #--- 入力画面出力(つづき) -------------------------------------# print ""; print "

\n"; print "\n"; if (!$tag) { print ""; } print "

\n"; print "
\n"; print "

\n"; print "

\n\n"; #--- 記録記事の出力 ----------------------------------# # 記録ファイルを読み出しオープンして、配列<@lines>に格納する if (!open(DB,"$file")) { &error(0); } @lines = ; close(DB); if ($FORM{'page'} eq '') { $page = 0; } else { $page = $FORM{'page'}; } $accesses = @lines; $accesses--; $page_end = $page + $def - 1; if ($page_end > $accesses) { $page_end = $accesses; } foreach ($page .. $page_end) { # データを各変数に代入する ($date,$name,$email,$value,$subject,$hpage,$face) = split(/\,/,$lines[$_]); $value =~ s/\0/\,/g; # ヌルコードに変換記録した半角カンマを復帰させる chop($face) if $face =~ /\n/; # faceデータから場所とファイル情報を分割 ($align, $file) = split(/\-/, $face); if ($align eq '') { $align = 'n'; } print "

\n"; print "\n"; if ($align eq 'l'){ print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; } if ($align eq 'r'){ print "\n"; print "\n"; print "\n"; print "\n"; } if ($align eq 'n'){ print "\n"; print "\n"; print "\n"; print "\n"; } print "\n"; print "\n"; print "\n"; if ($align eq 'l'){ print "\n"; } if ($align eq 'r'){ print "\n"; } if ($align eq 'n'){ print "\n"; } print "\n"; print "\n"; print "
\n"; print "
\n"; print "\n"; print "$subject
\n"; # メールアドレスが記録されているデータにはリンクを付ける if ($email ne '') { print "投稿者:$name\n"; } else { print "投稿者:$name \n"; } print "
投稿日:$date

\n"; #改行コードを
タグに変換 $value =~ s/\r/
\r/g; print "

\n\n$value\n\n

"; # URLが記録されているデータにはリンクを付ける if ($hpage ne '') { print "$hpage

\n"; } print "

\n"; print "
"; print "\n"; print "

\n\n"; } #--- 改ページ処理 ------------------------------------# $page_next = $page_end + 1; $i = $page + 1; $j = $page_end + 1; if ($page_end ne $accesses) { print "

\n"; print "\n"; print "
\n"; } else { print "これ以下の記事はありません。\n"; } print "
\n\n"; print "

\n"; print "\n"; print "\n"; print "

\n\n"; # このスクリプトの著作権表示(かならず表示してください) print "

MiniBBS v7.5"; print "is Free.(Modified by T.Tajima)

\n"; # TABLE終わり print "
\n"; exit; } sub regist { # 別のページからこのCGIへの投稿を排除する処理 # ■注:このCGIからの投稿もできない場合は次の2行を削除してください $ref = $ENV{'HTTP_REFERER'}; if (!($ref =~ /$reload/i)) { &error(form); } # 入力されたデータのチェック if ($FORM{'name'} eq "") { &error(1); } if ($FORM{'value'} eq "") { &error(2); } if ($FORM{'email'} =~ /,/) { &error(4); } if ($FORM{'email'} ne "") { if (!($FORM{'email'} =~ /(.*)\@(.*)\.(.*)/)) { &error(3); }} if ($FORM{'subject'} eq "") { $FORM{'subject'} = '(無題)'; } if ($FORM{'page'} eq "" || $FORM{'page'} eq "http://") { $FORM{'page'} = ''; } $FORM{'name'} =~ s///g; $FORM{'subject'} =~ s//>/g; $FORM{'email'} =~ s///g; $FORM{'face'} =~ s///g; # クッキーの仕様通りに真面目にフォーマット(指定時刻はGMT) # クッキーの仕様書 http://www.netscape.com/newsref/std/cookie_spec.html if ($yearg < 10) { $yearg = "0$yearg"; } if ($secg < 10) { $secg = "0$secg"; } if ($ming < 10) { $ming = "0$ming"; } if ($hourg < 10) { $hourg = "0$hourg"; } if ($mdayg < 10) { $mdayg = "0$mdayg"; } $y0="Sunday"; $y1="Monday"; $y2="Tuesday"; $y3="Wednesday"; $y4="Thursday"; $y5="Friday"; $y6="Saturday"; $youbi = ($y0,$y1,$y2,$y3,$y4,$y5,$y6) [$wdayg]; $m0="Jan"; $m1="Feb"; $m2="Mar"; $m3="Apr"; $m4="May"; $m5="Jun"; $m6="Jul"; $m7="Aug"; $m8="Sep"; $m9="Oct"; $m10="Nov"; $m11="Dec"; $month = ($m0,$m1,$m2,$m3,$m4,$m5,$m6,$m7,$m8,$m9,$m10,$m11) [$mong]; $date_gmt = "$youbi, $mdayg\-$month\-$yearg $hourg:$ming:$secg GMT"; # 独自方式のクッキーフォーマット # # この簡易BBSでは名前とメールアドレスを保存の対象にしています。 # それぞれを独立したクッキーとしてブラウザに食べさせればとても簡単ですが、 # ブラウザがクッキーを格納できる数に制限があるため、できるだけ一つのクッキーに # 保存データをまとめて食べさせることが望まれます。そのためにここでは独自の方法で # 1つのクッキー内に複数のデータを詰め込み、クッキーの取得時にそれらを展開して利用しています。 #  # name:,email: という形式にまとめて、これを一つのクッキーとして # cookieという名前でブラウザに送信しています。 # # 独自フォーマット cookie=name:,email: $cook="name\:$FORM{'name'}\,email\:$FORM{'email'}"; print "Set-Cookie: $reload=$cook; expires=$date_gmt\n"; # 記入者のリモートホスト名を取得する(これは表示されずHTMLソースで閲覧できる) $host = $ENV{'REMOTE_HOST'}; $addr = $ENV{'REMOTE_ADDR'}; if ($host eq $addr) { $host = gethostbyaddr(pack('C4',split(/\./,$host)),2) || $addr; } # 記録ファイルを読み出しオープンして、配列<@lines>に格納する if (!open(DB,"$file")) { &error(0); } @lines = ; close(DB); # 最大保持記録数の処理 $i = 0; foreach $line (@lines) { $i++; if ($i == $max) { last; } push(@new,$line); } $value = "$date_now\,$FORM{'name'}\,$FORM{'email'}\,$FORM{'value'}\,$FORM{'subject'}\,$FORM{'page'}\,$FORM{'face'}\n"; unshift(@new,$value); # 記録ファイルを上書きオープンして、配列<@new>を書き出す if (!open(DB,">$file")) { &error(0); } print DB @new; close(DB); # 記録処理後、再読み込みする print "Location: $reload" . '?' . "\n\n"; exit; } sub error { # &error(xx); で呼び出されたルーチンは、()内の数字が $error に代入される。 $error = $_[0]; if ($error eq "0") { $error_msg = '記録ファイルの入出力にエラーが発生しました。'; } elsif ($error eq "1") { $error_msg = '投稿者名が記入されていません。'; } elsif ($error eq "2") { $error_msg = '内容が書かれていません。または記録禁止のタグが書かれています。'; } elsif ($error eq "3") { $error_msg = 'メールアドレスが正しく入力されていません。'; } elsif ($error eq "4") { $error_msg = 'メールアドレスは複数指定できません。'; } elsif ($error eq "tag") { $error_msg = '利用ができないタグが記述されていますので投稿できません。'; } elsif ($error eq "form") { $error_msg = "投稿画面のURLが
$reload
" . '以外からの投稿はできません。'; } print "Content-type: text/html\n\n"; print "$title\n"; print "$body\n"; print "
\n"; print "
\n"; print "

エラー:

\n"; print "

$error_msg

\n"; print "

[戻る]

\n"; print "\n"; exit; } sub remove1 { if (!open(DB,"$file")) { &error(0); } @lines = ; close(DB); print "Content-type: text/html\n\n"; print "$title\n"; print "$body\n"; print "
\n"; print "削除モード[戻る]

\n"; print "

\n"; print "\n"; print "
";

	print "   登録日                   投稿者     タイトル   内容
\n"; foreach $line (@lines) { ($date,$name,$email,$value,$subject) = split(/\,/,$line); $value =~ s/\0/\,/g; chop($subject) if $subject =~ /\n/; $value =~ s///ig; $value =~ s//>/ig; $value =~ s/\n/./g; $value =~ s/\r/./g; $i1 = length($subject); if ($i1 > 10) { $subject = substr($subject,0,8); $subject = $subject . '..'; } elsif ($i1 < 10) { $blank = ' ' x (10 - $i1); $subject = $subject . $blank; } $i2 = length($name); if ($i2 > 10) { $name = substr($name,0,8); $name = $name . '..'; } elsif ($i2 < 10) { $blank = ' ' x (10 - $i2); $name = $name . $blank; } if (length($value) > 28) { $value = substr($value,0,28); } print ""; print "$date $name $subject $value\n
"; } print "

\n"; print "

\n"; print "

\n"; print "\n"; } sub remove2 { if (!open(DB,"$file")) { &error(0); } @lines = ; close(DB); foreach $line (@lines) { ($date,$name,$email,$value,$subject) = split(/\,/,$line); $del = 0; foreach $target (@RM) { if ($target eq $date) { $del = 1; } } if ($del == 0) { push(@new,$line); } } if (!open(DB,">$file")) { &error(0); } print DB @new; close(DB); } #end_of_script