#!/usr/local/bin/perl
#┌─────────────────────────────────
#│ E-PAD v2.12 (2005/08/12)
#│ Copyright (c) KentWeb
#│ webmaster@kent-web.com
#│ http://www.kent-web.com/
#│
#│ E-PAD utn Edition v1.01 (2006/04/25)
#│ 端末情報記録機能追加 (2005/11/17)
#│ 端末情報アクセス制限追加(2006/04/25)
#│ 英語SPAMブロック追加(2006/04/25 By かず)
#│ Copyright (c) Bancho
#│ info@bancho.saikyou.biz
#│ http://bancho.saikyou.biz/archives/2006/01/epad_utn.html
#└─────────────────────────────────
$ver = 'E-PAD v2.12';
#┌─────────────────────────────────
#│ [注意事項]
#│ 1. このスクリプトはフリーソフトです。このスクリプトを使用した
#│ いかなる損害に対して作者は一切の責任を負いません。
#│ 2. 設置に関する質問はサポート掲示板にお願いいたします。
#│ 直接メールによる質問は一切お受けいたしておりません。
#└─────────────────────────────────
#
# 【ファイル構成例】
#
# public_html (ホームディレクトリ)
# |
# +-- epad / epad.cgi [705]
# | elog.cgi [606]
# | num.dat [606]
# |
# +-- lib / jcode.pl [604]
# | admin.pl [604]
# | ptel.pl [604]
# | pcom.pl [604]
# |
# +-- data / i2e.dat [604]
# | i2j.dat [604]
# | j2e.dat [604]
# |
# +-- img / *.gif
# |
# +-- i / *.gif *.png
# |
# +-- j / *.gif
# |
# +-- e / *.gif *.png
# |
# +-- lock [707] /
#
#-------------------------------------------------
# ▽基本設定
#-------------------------------------------------
# 外部ファイル取り込み
$jcode = './lib/jcode.pl';
$ptel = './lib/ptel.pl';
$pcom = './lib/pcom.pl';
$admin = './lib/admin.pl';
# 掲示板タイプ
# 1 : 標準タイプ(レス機能なし)
# 2 : 返信レス式(レス記事はクリック後に表示)
# 3 : 返信レス式(レス記事は初期画面から表示)
$bbstype = 3;
# 自動ソート
# → 返信時に親記事をトップへ自動ソートする
# 0 : しない
# 1 : する
$topsort = 0;
# タイトル名
$title = "BLUEFOREST BBS";
# タイトル文字の色
$t_color = "#ff1111";
# タイトル文字サイズ
$t_size = '24px';
# 本文文字サイズ
$b_size = '13px';
# 本文文字のタイプ
$b_face = "MS UI Gothic, MS Pゴシック, Osaka";
# 記事題名の色
$sub_col = "#DD0000";
# 記事下地の色 (PCモード時)
$tbl_col = "#ffffff";
# 記事番号の色 (PCモード時)
$num_col = "#008000";
# CGI本体スクリプト (URL)
$script = './bbs.cgi';
# ログファイル (サーバパス)
$logfile = './elog.cgi';
# データ番号ファイル (サーバパス)
$numfile = './num.dat';
# 管理用パスワード
$pass = 'smsm5858';
# 最大記事数
# → 親記事単位
# → これを超える記事は古い順に削除
$max = 1000;
# 戻り先 (URL)
$home = "http://www.blueforest-kumagaya.com/";
# bodyタグ (PCモードの場合)
$body = '
';
# URLの自動リンク (0=no 1=yes)
$autolink = 1;
# 1ページ当り記事表示件数
$pageLog = 10; # PCモード
$pageLog2 = 5; # 携帯モード
# ファイルロック形式
# → 0=no 1=symlink関数 2=mkdir関数
$lockkey = 0;
# ロックファイル名
$lockfile = './lock/epad.lock';
# メール通知機能
# 0 : 通知しない
# 1 : 通知する → 自分の投稿記事も通知する
# 2 : 通知する → 自分の投稿記事は通知しない
$mailing = 0;
# メールソフトのパス(メール通知する場合)
$sendmail = '/usr/lib/sendmail';
# メール通知先アドレス(メール通知する場合)
$mailto = 'xxx@xxx.xxx';
# アクセス制限(半角スペースで区切る)
# → 拒否するホスト名又はIPアドレスをスペースで区切る
# → 記述例 $deny = '.anonymizer.com 211.154.120.';
$denyhost = '220.226.63.254 83.151.156.148 211.143.37.188 206.51.229.115';
# ホスト取得方法
# 0 : gethostbyaddr関数を使わない
# 1 : gethostbyaddr関数を使う
$gethostbyaddr = 0;
# 同一IPアドレスからの連続投稿時間(秒数)
# → 連続投稿などの荒らし対策
# → 値を 0 にするとこの機能は無効
$wait = 30;
# Docomo 及び VodaPhoneで端末情報を送信しない場合
# 0 : 投稿を許可する(端末情報の代わりにIPアドレスを保存)
# 1 : 投稿を禁止する
$selchk = 0;
# 一般画像ディレクトリURL
$imgurl = './img';
# i-mode画像ディレクトリURL
$img_i = './i';
# vodafone画像ディレクトリURL
$img_j = './j';
# EZweb画像ディレクトリURL
$img_e = './e';
# コメント部投稿データ制限(バイト)
$maxdata = 10000;
# ヘッダのContent-Lengthを表示する
# → 0=no 1=yes
# → 無料HPサービス等で広告バナーが自動表示される場合にはNOとする
$cont_len = 1;
# 絵文字変換データディレクトリ
$emodir = './data';
#-------------------------------------------------
# △設定完了
#-------------------------------------------------
&agent;
&decode;
&axscheck;
if ($mode eq 'regist') { ®ist; }
elsif ($mode eq 'find') { &find; }
elsif ($mode eq 'howto') { &howto; }
elsif ($mode eq 'admin') { require $admin; &admin; }
elsif ($mode eq 'usrdel') { &usrdel; }
elsif ($mode eq 'popup') { &popup; }
elsif ($mode eq 'check') { ✓ }
&html;
#-------------------------------------------------
# 機種チェック
#-------------------------------------------------
sub agent {
# 機種情報
local($agent) = $ENV{'HTTP_USER_AGENT'};
# jcode.pl使用フラグ
$jflag=0;
# FOMA
if ($agent =~ /DoCoMo\/2/i) {
#Docomo(FOMA)のutnを取り出し
@item = split(/\;/, $ENV{'HTTP_USER_AGENT'});
if (length($item[3]) == 0) {
$errflg = 1;
} else {
$utn = $item[3];
}
$type = 'f';
$method = 'POST';
$button = 'accesskey';
$emo1 = '驪';
$emo2 = '麗';
$emo3 = '黎';
$emo4 = '力';
$emo5 = '曆';
$meta = '';
require $ptel;
# Mova
} elsif ($agent =~ /DoCoMo\/1/i) {
#DoCoMo(Mova)のutnを取り出し
@item = split(/\//, $ENV{'HTTP_USER_AGENT'});
if (length($item[6]) == 0) {
$errflg = 1;
} else {
$utn = $item[6];
}
$type = 'i';
$method = 'post';
$button = 'accesskey';
$emo1 = '驪';
$emo2 = '麗';
$emo3 = '黎';
$emo4 = '力';
$emo5 = '曆';
$meta = '';
require $ptel;
# vodafone
} elsif ($agent =~ m|J-PHONE/[^\/]+/([^\/]+)|i || $agent =~ /Vodafone/|i || $agent =~ /^MOT\-/|i) {
$type = 'j';
#VodaPhoneのシリアルNo.を取り出し
@item = split(/\//, $ENV{'HTTP_USER_AGENT'});
if (length($item[4]) == 0) {
$errflg = 1;
} else {
$ser = $item[4];
}
# $model = $1; # 機種
# if ($model =~ /51/) { $model=51; } else { $model=0; }
$method = 'get';
$button = 'DIRECTKEY';
$emo1 = pack('H2H2','1B','24') . 'F' . pack('H2','3c') . pack('H2','0F');
$emo2 = pack('H2H2','1B','24') . 'F' . pack('H2','3d') . pack('H2','0F');
$emo3 = pack('H2H2','1B','24') . 'F' . pack('H2','3e') . pack('H2','0F');
$emo4 = pack('H2H2','1B','24') . 'F' . pack('H2','3f') . pack('H2','0F');
$emo5 = pack('H2H2','1B','24') . 'F' . pack('H2','40') . pack('H2','0F');
$meta = '';
require $ptel;
# EZweb
} elsif ($agent =~ /UP\.Browser/i) {
# auのサブスクライバIDを取得 By Bancho
$au = $ENV{'HTTP_X_UP_SUBNO'};
$type = 'e';
$method = 'get';
$button = 'accesskey';
$emo1 = '
';
$emo2 = '
';
$emo3 = '
';
$emo4 = '
';
$emo5 = '
';
$meta = '';
require $ptel;
# PC
} else {
$type = 'p';
$method = 'post';
$meta = '';
$meta .= "\n\n";
require $pcom;
require $jcode;
$jflag++;
}
}
#-------------------------------------------------
# アクセス制限
#-------------------------------------------------
sub axscheck {
# IP&ホスト取得
$host = $ENV{'REMOTE_HOST'};
$addr = $ENV{'REMOTE_ADDR'};
if ($gethostbyaddr && ($host eq "" || $host eq $addr)) {
$host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2);
}
if ($host eq "") { $host = $addr; }
local($flag);
foreach ( split(/\s/, $denyhost) ) {
if (index($host,$_) >= 0) { $flag=1; last; }
elsif (index($utn,$_) >= 0) { $flag=1; last; }
elsif (index($au,$_) >= 0) { $flag=1; last; }
elsif (index($ser,$_) >= 0) { $flag=1; last; }
}
if ($flag) { &error("アクセスを許可されていません"); }
}
#-------------------------------------------------
# 投稿受付
#-------------------------------------------------
sub regist {
local($limit, $pwd, $time, @file, @w);
# データ制限
$limit = $maxdata / 2;
if (length($in{'comment'}) > $maxdata) {
&error("コメントは全角$limit字以内にしてください");
}
# フォーム内容チェック
local($err);
if ($in{'name'} eq "") { $err .= "名前が未入力です
\n"; }
if ($in{'comment'} eq "") { $err .= "コメントが未入力です
\n"; }
if ($err) { &error($err); }
if ($in{'url'} eq "http://") { $in{'url'} = ""; }
if ($in{'sub'} eq "") { $in{'sub'} = "無題"; }
# スパム拒否 By かず
$c = $in{'comment'};
if ($in{'url'} && $c =~ /\Q$in{'url'}\E/i) { &error("参照先のアドレスと同一アドレスがコメント中に含まれています"); }
if ($c !~ /[\x80-\xff]/) { &error("コメント中に日本語が含まれていません"); }
$urlnum = ($c =~ s/http/http/g);
if ($urlnum > 3) { &error("コメント中のアドレスが4個を越えています"); }
# ロック開始
&lock if ($lockkey);
# データ読み込み
open(IN,"$logfile") || &error("Open Error: $logfile");
@file = ;
close(IN);
open(IN,"$numfile") || &error("Open Error: $numfile");
$num = ;
close(IN);
($no,$tim,$hos) = split(/<>/, $num);
$no++;
# 重複投稿チェック
$time = time;
# 同一ホスト連続投稿チェック
if ($host eq $hos && $wait > $time - $tim) {
&error("連続投稿はもうしばらく時間をおいて下さい");
}
# 端末情報拒否チェック By Bancho
if ($selchk eq 1 ) {
if ($errflg eq 1 ) {
&error("端末情報を送信しないと投稿出来ません");
}
}
# 削除キー暗号化
if ($in{'pwd'} ne "") { $pwd = &encrypt($in{'pwd'}); }
# 日時取得
$date = &get_time($time, 'p');
# 絵文字処理
$in{'sub'} = &emoji($in{'sub'});
$in{'name'} = &emoji($in{'name'});
$in{'comment'} = &emoji($in{'comment'});
# xxxx; を復元
$in{'sub'} =~ s/\&(#\d{5};)/\&$1/ig;
$in{'name'} =~ s/\&(#\d{5};)/\&$1/ig;
$in{'comment'} =~ s/\&(#\d{5};)/\&$1/ig;
#携帯の場合にIPアドレスを固体識別情報に変換
if ($type eq 'i') { #Movaの場合
if ($errflg eq 1 ) { #端末情報が空で
if ($host eq "") { #リモートホストも空なら
$host = $addr; #リモートアドレスを入れる
} else {
$host = $host; #リモートホスト情報があればリモートホストを入れる
}
} else { #端末情報があれば端末情報を入れる
$host = $utn;
}
} elsif ($type eq 'f') { #FOMAの場合
if ($errflg eq 1 ) {
if ($host eq "") {
$host = $addr;
} else {
$host = $host;
}
} else {
$host = $utn;
}
} elsif ($type eq 'e') { #auの場合
$host = $au;
} elsif ($type eq 'j') { #VodaPhoneの場合
if ($errflg eq 1 ) {
if ($host eq "") {
$host = $addr;
} else {
$host = $host;
}
} else {
$host = $ser;
}
} else { #その他(PCなど)
if ($host eq "") {
$host = $addr;
} else {
$host = $host;
}
}
# 親記事の場合
if ($in{'res'} eq "") {
$i=0;
$stop=0;
foreach (@file) {
($no2,$reno2) = split(/<>/);
$i++;
if ($i > $max-1 && $reno2 eq "") { $stop=1; }
if (!$stop) { push(@data,$_); }
}
unshift(@data,"$no<><>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>$type<>0<>\n");
# レス記事の場合:トップソートあり
} elsif ($in{'res'} && $topsort) {
$f=0;
$oyaChk=0;
$match=0;
@data=();
@tmp=();
foreach (@file) {
($no2,$reno2,$dat,$nam,$eml,$sub,$com,$url,$hos,$pw,$tim,$typ,$res) = split(/<>/);
if ($in{'res'} == $no2) {
if ($reno2) { $f++; last; }
$res++;
$oyaChk++;
$match=1;
push(@data,"$no2<>$reno2<>$dat<>$nam<>$eml<>$sub<>$com<>$url<>$hos<>$pw<>$tim<>$typ<>$res<>\n");
} elsif ($in{'res'} == $reno2) {
push(@data,$_);
} elsif ($match == 1 && $in{'res'} != $reno2) {
$match=2;
push(@data,"$no<>$in{'res'}<>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>$type<><>\n");
push(@tmp,$_);
} else { push(@tmp,$_); }
}
if ($f) { &error("不正な返信要求です"); }
if (!$oyaChk) { &error("親記事が存在しません"); }
if ($match == 1) {
push(@data,"$no<>$in{'res'}<>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>$type<><>\n");
}
push(@data,@tmp);
# レス記事の場合:トップソートなし
} else {
$f=0;
$oyaChk=0;
$match=0;
@data=();
foreach (@file) {
($no2,$reno2,$dat,$nam,$eml,$sub,$com,$url,$hos,$pw,$tim,$typ,$res) = split(/<>/);
if ($in{'res'} == $no2) {
$oyaChk++;
$res++;
$_ = "$no2<>$reno2<>$dat<>$nam<>$eml<>$sub<>$com<>$url<>$hos<>$pw<>$tim<>$typ<>$res<>\n";
}
if ($match == 0 && $in{'res'} == $no2) {
if ($reno2) { $f++; last; }
$match=1;
} elsif ($match == 1 && $in{'res'} != $reno2) {
$match=2;
push(@data,"$no<>$in{'res'}<>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>$type<><>\n");
}
push(@data,$_);
}
if ($f) { &error("不正な返信要求です"); }
if (!$oyaChk) { &error("親記事が存在しません"); }
if ($match == 1) {
push(@data,"$no<>$in{'res'}<>$date<>$in{'name'}<>$in{'email'}<>$in{'sub'}<>$in{'comment'}<>$in{'url'}<>$host<>$pwd<>$time<>$type<><>\n");
}
}
# 更新
open(OUT,">$logfile") || &error("Write Error: $logfile");
print OUT @data;
close(OUT);
open(OUT,">$numfile") || &error("Write Error: $numfile");
print OUT "$no<>$time<>$host";
close(OUT);
# ロック解除
&unlock if ($lockkey);
# メール通知
if ($mailing == 1 || ($mailing == 2 && $in{'email'} ne $mailto)) { &mail_to; }
# 投稿後メッセージ
if ($type eq 'p') {
# クッキー記憶
&set_cookie($in{'cook'},$in{'name'},$in{'email'},$in{'url'},$in{'pwd'});
&header;
print "
\n";
print "投稿は正常に処理されました
\n";
print "\n";
print "
\n";
} else {
&header;
print "投稿完了
戻る\n";
}
print "