#!/usr/local/bin/perl #┌───────────────────────────────── #│ Message ENQ v1.43 (2001/09/16) #│ Copyright(C) Kent Web 2001 #│ webmaster@kent-web.com #│ http://www.kent-web.com/ #└───────────────────────────────── $ver = 'Message ENQ v1.43'; #┌───────────────────────────────── #│ [ 注意事項 ] #│ 1. このスクリプトはフリーソフトです。このスクリプトを使用した #│ いかなる損害に対して作者は一切の責任を負いません。 #│ 2. 設置に関する質問はサポートコーナにお願いいたします。直接 #│ メールによる質問は受け付けておりません。 #└───────────────────────────────── # # [ 設置例 ] # # ***.co.jp / index.html (トップページ) # | # +-----cgi-bin # | # +---- msgenq / msgenq.cgi # | msgenq.log # | msgenq.dat # | jcode.pl # | graph.gif # | # +---- lock / # # # # [ チェックモードの仕方 ] : mode=check という引数を付けて呼出す # # 例 http://www.***.co.jp/cgi-bin/msgenq/msgenq.cgi?mode=check #============# # 設定 # #============# # ●の個所の「***_co_jp」の部分をお客様用に修正してください。 # 「***.com」の場合は「***_com」となります。 # ●jcode.pl取り込み require 'D:\\users\\kusunokikai_com\\cgi-bin\\msgenq\\jcode.pl'; # タイトル名 $title = "給食メニューアンケート"; # タイトル文字の色 $t_color = "#006633"; # タイトル文字のタイプ $t_face = "MS Pゴシック"; # タイトル文字の大きさ (スタイルシートで反映) $t_size = '18pt'; # 本文の文字大きさ (スタイルシートで反映) $b_size = '10pt'; # スクリプト名 $script = 'msgenq.cgi'; # ●ログファイル $logfile = 'D:\\users\\kusunokikai_com\\cgi-bin\\msgenq\\msgenq.log'; # ●メッセージログファイル $msgfile = 'D:\\users\\kusunokikai_com\\cgi-bin\\msgenq\\msgenq.dat'; # 投稿メッセージファイル最大保持数 $max = 10; # 投稿メッセージの文字数制限(全角換算で指定) $msg_max = 35; # 管理用パスワード $pass = '0125'; # ユーザ項目追加機能 (0=no 1=yes) # → yes だとユーザが自由に項目を追加することが可能となります $FreeItem = 1; # IPアドレスの保持件数(二重投稿禁止) # → これを 0 にすると二重投稿のチェックを行ないません $ipmax = 5; # グラフ画像 (絶対パスだと http://から) $graph = "graph.gif"; # ●戻り先 (絶対パスだと http://から。***.co.jpの部分は自分のドメインに置き換えてください) $home = "http://www.kusunokikai.com/topics/news.htm"; # bodyタグ $body = ''; # method形式 (POST or GET) $method = 'POST'; # 記事の更新は「method=POST」限定 → セキュリティ強化 # 0 : 行なわない # 1 : 行なう $MethPost = 1; # ロックファイル機構 # 0 : 行なわない # 1 : 行なう(symlink関数) # 2 : 行なう(mkdir関数) $lockkey = 0; # ●ロックファイル名 $lockfile = 'D:\\users\\kusunokikai_com\\cgi-bin\\msgenq\\lock\\mesganq.lock'; # 戻るボタン (0=no 1=yes) # --> Javascriptによる戻るボタン表示機能 $BackButton = 1; # サブタイトル # --> タイトル下にサブタイトルを記述します(タグ使用可) $subtitle = <<'EOM'; EOM # タイトル画像を使う場合 (http://から画像を指定) $ImgT = "http://www.kusunokikai.com/img/enquete.png"; # タイトル画像を使う場合に「横幅」「縦幅」をそれぞれピクセル数で記述 $ImgW = "300"; $ImgH = "70"; # タグ広告挿入オプション (FreeWebなど) # → の代わりに「広告タグ」を挿入する。 # → 広告タグ以外に、MIDIタグ や LimeCounter等のタグにも使用可能です。 $banner1 = ''; # 上部に挿入 $banner2 = ''; # 下部に挿入 # アクセス制限(ホスト名を記述) @deny = ( "anonymizer.com", "cache*.*.interlog.com", "spaceproxy.com", "", "", "", "", "", "" ); #============# # 設定完了 # #============# # メイン処理 &decode; &axs_check; if ($mode eq 'regist') { ®ist; } elsif ($mode eq 'admin') { &admin; } elsif ($mode eq 'MakeItem' && $FreeItem) { &MakeItem('USER'); } elsif ($mode eq 'check') { ✓ } &html; #----------------# # アクセス制限 # #----------------# sub axs_check { # ホスト名を取得 &get_host; local($flag)=0; foreach (@deny) { next if (!$_); s/\*/\.\*/g; if ($host =~ /$_/i) { $flag=1; last; } } &error("アクセスを許可されていません") if ($flag); } #------------------# # 初期画面を表示 # #------------------# sub html { &header; if ($BackButton) { print "
\n"; } else { print "▲TOP\n"; } print "
\n"; print "$banner1

\n" if ($banner1 ne ""); # タイトル if ($ImgT) { print "\"$title\"

\n"; } else { print "
\n"; print "
\n"; print "$title\n"; print "
\n"; print "
\n"; } print "
\n$subtitle\n
\n"; open(IN,"$logfile") || &error("Open Error : $logfile"); $top = ; $total=0; @NO=(); @ITEM=(); while () { ($no,$item,$count) = split(/<>/); push(@NO,$no); push(@ITEM,$item); $no{$no} = $no; $item{$no} = $item; $count{$no} = $count; $total += $count; } close(IN); $all = &filler($total); print "

\n"; print "\n"; print "有効回答:$all

\n"; print "
\n"; print "\n"; print "\n"; # 回答がすべて 0 のとき if ($total == 0) { open(IN,"$logfile") || &error("Open Error : $logfile"); $top = ; while () { ($no,$item,$count,$addr) = split(/<>/); print ""; print ""; print "\n"; } close(IN); } # ソート処理 else { # ランク用中間ファイル $rank1 = 0; $rank2 = 1; $count_tmp = 0; # ソート処理 foreach (sort { ($count{$b} <=> $count{$a}) || ($a cmp $b) } keys(%count)) { ($count{$_} == $count_tmp) || ($rank1 = $rank2); $per = int(($count{$_}*1000 / $total)+0.5) / 10; $per = sprintf("%.1f", $per); $width = int($per * 3); if ($width < 1) { $width = 1; } # 桁区切り $cnt = &filler($count{$_}); print ""; print ""; print "\n"; $count_tmp = $count{$_}; $rank2++; } } print "
順位項目得票数割合
1$item$count "; print "0.0\%
$rank1$item{$_}$cnt "; print "$per\%
\n"; # 回答フォーム print "

\n"; print "\n"; print "
項目選択
コメント (全角$msg_max文字以内)
\n"; print "
 
\n

\n"; # 項目追加 if ($FreeItem) { print "
\n"; print "
\n"; print "\n"; print "投票する項目が上記にない場合は以下のフォームから追加して下さい

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

\n"; } # コメントを表示 print "
直近のコメント一覧
\n"; open(IN,"$msgfile"); while () { ($date,$item,$comment) = split(/<>/); print "日付 : $date
\n"; print "投票 : $item
\n"; print "コメント : $comment
\n"; } close(IN); # 管理用フォーム print "
\n"; print "
\n"; print "\n"; print ""; print " \n"; print "
\n"; # 著作権表示(削除不可) print "
$banner2

\n"; print "- Message Enq -\n"; print "

\n\n\n"; exit; } #----------------# # 投票受付処理 # #----------------# sub regist { # POST限定 if ($MethPost && !$post_flag) { &error("不正なアクセスです"); } if ($in{'item'} eq "") { &error("項目の選択がありません"); } if (length($in{'comment'}) > $msg_max*2) { &error("コメント文が長すぎます。全角$msg_max文字以内で記述して下さい"); } # ロック処理 if ($lockkey) { &lock; } @new=(); open(IN,"$logfile") || &error("Open Error : $logfile"); $top = ; while () { chop; local($no,$item,$count,$host) = split(/<>/); if ($in{'item'} == $no) { $AnsItem = $item; $count++; $_="$no<>$item<>$count<>$host<>"; } push(@new,"$_\n"); } close(IN); if ($ipmax) { $top =~ s/\n//; @ip = split(/\s+/, $top); $match=0; $ip=""; $i=0; foreach (@ip) { $i++; if ($addr eq "$_") { $match=1; last; } if ($i < $ipmax) { $ip .= "$_ "; } } if ($match) { &error("連続投票はできません"); } $ip = "$addr $ip\n"; } else { $ip = "\n"; } # 更新 unshift(@new,$ip); open(OUT,">$logfile") || &error("Write Error : $logfile"); print OUT @new; close(OUT); # コメント文記録 if ($in{'comment'}) { # 記事読込 open(IN,"$msgfile") || &error("Open Error : $logfile"); @lines = ; close(IN); # 更新 while ($max <= @lines) { pop(@lines); } &get_time; unshift(@lines,"$date<>$AnsItem<>$in{'comment'}<>$host<>\n"); open(OUT,">$msgfile") || &error("Write Error : $logfile"); print OUT @lines; close(OUT); } # ロック解除 if ($lockkey) { &unlock; } # 完了メッセージ &header; print <<"EOM";

ご回答ありがとうございました

EOM exit; } #--------------# # 管理モード # #--------------# sub admin { if ($in{'pass'} ne $pass) { &error("パスワードが違います"); } # 項目追加処理 if ($in{'item'}) { &MakeItem; } # 削除処理 if ($DEL[0]) { # ロック処理 if ($lockkey) { &lock; } open(IN,"$logfile") || &error("Open Error : $logfile"); @lines = ; close(IN); $top = shift(@lines); @new=(); foreach (@lines) { $flag=0; ($no,$item) = split(/<>/); foreach $x (@DEL) { if ($no eq "$x") { $flag=1; last; } } if ($flag == 0) { push(@new,$_); } } # 更新 unshift(@new,$top); open(OUT,">$logfile") || &error("Write Error : $logfile"); print OUT @new; close(OUT); # ロック解除 if ($lockkey) { &unlock; } } &header; print <<"EOM"; [初期画面に戻る]
管理モード

1. 項目の追加

項目


2. 項目の削除

EOM open(IN,"$logfile") || &error("Open Error : $logfile"); $top = ; while () { chop; ($no,$item,$count,$host) = split(/<>/); if (!$host) { $host = '
'; }; print "
\n"; } close(IN); print "
削除項目得票数ホスト
"; print "$item$count$host

 \n


\n"; # ロック開始 if ($in{'action'} eq "mesg_del" && $lockkey) { &lock; } open(IN,"$msgfile") || &error("Open Error : $msgfile"); @lines = ; close(IN); # 削除処理 if ($in{'action'} eq "mesg_del") { if ($DEL[0] eq "") { &error("削除項目がありません"); } @new=(); foreach (@lines) { $flag=0; ($date,$mesg) = split(/<>/); foreach $i (@DEL) { if ($i eq $date) { $flag=1; last; } } if ($flag == 0) { push(@new,$_); } } # 更新 open(OUT,">$msgfile") || &error("Write Error : $msgfile"); print OUT @new; close(OUT); # ロック解除 if ($lockkey) { &unlock; } @lines = @new; } print "

3. コメントの削除

\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "
\n"; foreach (@lines) { ($date,$item,$comment,$host) = split(/<>/); if (length($comment) > 30) { $comment = substr($comment,0,28); $comment .= "..."; } print "
"; print "$item $comment - $date ($host)\n"; } print "
\n"; print " 
\n"; print "\n\n"; exit; } #------------------# # ユーザ項目追加 # #------------------# sub MakeItem { # POST限定 if ($_[0] eq 'USER' && $MethPost && !$post_flag) { &error("不正なアクセスです"); } $item =~ s/\s//g; if ($item eq '') { &error("追加する項目名がありません"); } # ロック処理 if ($lockkey) { &lock; } $flag=0; open(IN,"$logfile") || &error("Open Error : $logfile"); $top = ; while() { ($no,$item2) = split(/<>/); if ($item eq $item2) { $flag=1; last; } } close(IN); if ($flag) { &error("この項目は既に存在するため追加できません"); } $no++; open(OUT,">>$logfile") || &error("Write Error : $logfile"); print OUT "$no<>$item<>0<>$host<>\n"; close(OUT); # ロック解除 if ($lockkey) { &unlock; } } #----------------# # デコード処理 # #----------------# sub decode { local($buffer, @pairs, $name, $value); $post_flag=0; if ($ENV{'REQUEST_METHOD'} eq "POST") { $post_flag=1; 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; # シフトJIS変換 &jcode'convert(*value, "sjis", "", "z"); # タグ禁止 $value =~ s//>/g; # 改行コード削除 $value =~ s/\r//g; $value =~ s/\n//g; # 削除情報 if ($name eq 'del') { push(@DEL,$value); } $in{$name} = $value; } $mode = $in{'mode'}; $item = $in{'item'}; } #--------------# # HTMLヘッダ # #--------------# sub header { $head_flag = 1; print "Content-type: text/html\n\n"; print <<"EOM"; $title $body EOM } #--------------# # エラー処理 # #--------------# sub error { &unlock if ($lockflag); &header if (!$head_flag); print "

ERROR !

\n"; print "$_[0]\n"; print "

\n\n\n"; exit; } #--------------# # ロック処理 # #--------------# sub lock { # 1分以上古いロックは削除する if (-e $lockfile) { local($mtime) = (stat($lockfile))[9]; if ($mtime < time - 60) { &unlock; } } local($retry) = 5; # symlink関数式ロック if ($lockkey == 1) { while (!symlink(".", $lockfile)) { if (--$retry <= 0) { &error('LOCK is BUSY'); } sleep(1); } # mkdir関数式ロック } elsif ($lockkey == 2) { while (!mkdir($lockfile, 0755)) { if (--$retry <= 0) { &error('LOCK is BUSY'); } sleep(1); } } $lockflag=1; } #--------------# # ロック解除 # #--------------# sub unlock { if ($lockkey == 1) { unlink($lockfile); } elsif ($lockkey == 2) { rmdir($lockfile); } $lockflag=0; } #------------# # 桁区切り # #------------# sub filler { local($_) = $_[0]; 1 while s/(.*\d)(\d\d\d)/$1,$2/; return $_; } #----------------# # ホスト名取得 # #----------------# sub get_host { $host = $ENV{'REMOTE_HOST'}; $addr = $ENV{'REMOTE_ADDR'}; if ($host eq "" || $host eq $addr) { $host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2) || $addr; } } #--------------# # 時間の取得 # #--------------# sub get_time { # 日時の取得 $ENV{'TZ'} = "JST-9"; ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time); # 日時のフォーマット @week = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); $date = sprintf("%04d/%02d/%02d(%s) %02d:%02d:%02d", $year+1900,$mon+1,$mday,$week[$wday],$hour,$min,$sec); } #------------------# # チェックモード # #------------------# sub check { &header; print "

Check Mode

\n"; print "
    \n"; # 項目ファイルパス if (-e $logfile) { print "
  • ログファイルのパス:OK\n"; } else { print "
  • ログファイルのパス:NG → $logfile\n"; } # 項目ファイルパーミッション if (-r $logfile && -w $logfile) { print "
  • ログファイルのパーミッション:OK\n"; } else { print "
  • ログファイルのパーミッション:NG\n"; } # メッセージファイルパス if (-e $msgfile) { print "
  • メッセージファイルのパス:OK\n"; } else { print "
  • メッセージファイルのパス:NG → $msgfile\n"; } # メッセージファイルパスパーミッション if (-r $msgfile && -w $msgfile) { print "
  • メッセージファイルのパーミッション:OK\n"; } else { print "
  • メッセージファイルのパーミッション:NG\n"; } # ロックディレクトリ print "
  • ロック形式:"; if ($lockkey == 0) { print "ロック設定なし\n"; } else { if ($lockkey == 1) { print "symlink\n"; } else { print "mkdir\n"; } ($lockdir) = $lockfile =~ /(.*)[\\\/].*$/; print "
  • ロックディレクトリ:$lockdir\n"; if (-d $lockdir) { print "
  • ロックディレクトリのパス:OK\n"; } else { print "
  • ロックディレクトリのパス:NG → $lockdir\n"; } if (-r $lockdir && -w $lockdir && -x $lockdir) { print "
  • ロックディレクトリのパーミッション:OK\n"; } else { print "
  • ロックディレクトリのパーミッション:NG → $lockdir\n"; } } print "
\n\n\n"; exit; }