#!/usr/bin/perl
#
#強化型ゆいぼーど(log.cgi)を改造したアンケート箱(軽量版)
require './jcodeLE.pl';
require './prei.cgi';
$| = 1;
&winit;&noaxschk;
&init;
&decode;&jikan;
&readlog;
($title,$chkkey,$ddata,$oname,$ochat,$ohost,$odate) = split(/:#/,$set);
if($odate eq ''){
$title='Broken Box';
$ochat='No data in file.';
}else{
$counter = int($counter);
}
if ($referer =~ /$cgichk/i ){
&write if($vote || $voten);
&edit if ($erase);
}
&html;exit;
##################################################
sub init{ #初期設定など
$rootpwd = 'master777'; #総合管理者のパスワード(重要!)
$pagemax = 15; #1ページに表示する件数
$vmax = 500; #保存する件数
$brmax = 10; #コメントの最大行数
$chatmax = 1024; #コメントの最大バイト数
$seritime = 1800; #連続投票の制限時間&項目作成制限の目安時間(秒数)
$votencount = 5; #連続項目作成の制限個数
}#init END
##################################################
sub html {
my($roomtotal,$count,$i,$line,$voten,$name,$wchat,$cdate,$host,$ps,$times,$invalid,$color,$page3,$time2);
print "Content-type: text/html\n\n";
print <<"_HTML_";
$title
$metacode
$bodys
_HTML_
if( $detail ){ #投票一覧の処理
&makedetail();
print $original;#この行だけは消さないでっ!!
return;
} #if END
&makevotes;
&sortvotes;
print <<"_HTML_";
[リストに戻る]
$title
$titimg
$acou
$ochat
_HTML_
if( $pass eq $rootpwd ){
print "$oname($odate $ohost)
";
}
else{
print "$oname($odate)
";
}
print "
";
print "${date}現在の集計状況
";
&printtable;
print "全発言\表\示 /\n";
print "全投票\表\示
\n";
if( $pass ne $rootpwd ){
print <<"_VOTE_";
一人連続投票制限があります。
_CMNT_
} #if END
if( $voteall ){ #全投票一覧の処理。重い
foreach $detail (@sortedvotes){
print "";
&makedetail;
}
print $original;#この行だけは消さないでっ!!
return;
} #if END
print "最近の投票 Page:";
$roomtotal = @lines;
$count = int(($roomtotal-1)/$pagemax);
for($i=0;$i<=$count;$i++){ #ページ番号を書く
if($i eq $page){
print "[$i] \n";
}else{
print "[$i] \n";
}
}
print "
";
if(@lines >= $pagemax){ #1ページ分の発言を取り出す
$page3 = $page2+$pagemax-1;
$page3 = @lines-1 if($page3 > @lines-1);
@lines = @lines[$page2 .. $page3];
}
foreach $line(@lines){
($voten,$name,$vote,$wchat,$cdate,$host,$times,$invalid,$time2) = split(/:#/,$line);
if($invalid){
$color = '#0000FF';
}else{
$color = '#000000';
}
print "$vote\n";
print "$wchat
\n";
if( $pass eq $rootpwd ){
print "($cdate $host $time2)\n";
}else{
print "($cdate)\n";
}
print "
\n";
}
if( $pass eq $rootpwd ){ #削除機能
print <<"_HTML_";
_HTML_
} #if END
$pass='';
print $original;#この行だけは消さないでっ!!
}#html END
##################################################
sub write {
my($line,$dmy1,$dmy2,$dmy3,$dmy4,$wchata,$wchatb,$filedata);
my($hs,$t1,$t2,$dt,$vtn,$vt,$iv,$vc);
$t1 = time;
$vc = 0;
foreach $line(@lines){ #一人連続投票をチェック
($vtn,$dmy1,$vt,$dmy2,$dmy3,$hs,$dmy4,$iv,$t2) = split(/:#/,$line);
$dt = $t1-$t2;
last if($dt >= $seritime);
if($hs eq $host){
$dt = int(($seritime-$dt)/60);
&err("一人連続投票制限にかかりました
(再び投票できるのは$dt分後)") if(($vt eq $vote) && ($iv eq $invalid));
if(($voten ne '') && ($vtn ne '')){
$vc++;
$dt = int($seritime/60);
&err("一人連続項目作成制限にかかりました
($votencount項目/$dt分)") if($vc >= $votencount);
}
}
}
($line)=@lines;
($dmy1,$dmy2,$wchatb) = split(/:#/,$line);
$wchata = $chat;
$wchata =~ s/ //g;$wchata =~ s/ //g;$wchata =~ s/
//ig;$wchata =~ s/>//ig;
$wchatb =~ s/ //g;$wchatb =~ s/ //g;$wchatb =~ s/
//ig;$wchatb =~ s/>//ig;
if(($wchata ne $wchatb) || $wchata==''){ #同内容の連続書き込みを禁止する機能らしい
if( $ddata <= $daylimit ){ #コメント無しの新規項目を許すようにした
$filedata = -M "$chat_file";
if( $filedata < $ddata/2 ){
$ddata += $aday;
}else{
$ddata /= 2;
}
}
$ddata = $hday if($ddata < $hday);
$ddata = $daylimit if($ddata > $daylimit);
$value = "$voten:#$name:#$vote:#$chat:#$date:#$host:#$times:#$invalid:#$t1:#\n";
#比較が面倒くさいので投票時刻の他にtimeで得た経過秒数も記録しておく
&writelog;
}
$chat = '';
}#write END
##################################################
sub decode{ #一般的なデコード&変数への代入
my($cou_file,$brnum,$i);
if($ENV{'REQUEST_METHOD'} eq "POST"){
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
}else{
$buffer = $ENV{'QUERY_STRING'};
}
&decodearg($buffer,$cgi_log);
$name = 'N';
$voten = $FORM{'voten'};&err("項目名が長すぎます。") if(length($voten) > ($votenmax*2));
$chat = $FORM{'chat'};
$room = $FORM{'room'};
$erase = $FORM{'erase'};
$room = '000' if($room eq '');
$chat_file = "./$logdir/log.$room.cgi";
$cou_file = "./$coudir/cou.$room.dat";
$pass = $FORM{'pass'};$pass = $$ unless($pass);
$page = $FORM{'page'};$page = 0 if($page < 0);$page = int($page);
$pagemax = $COOKIE{'pm'} if($COOKIE{'pm'} > 0);
$pagemax = $FORM{'pm'} if($FORM{'pm'} > 0); $pagemax = int($pagemax);
$page2 = $page*$pagemax;
$_ = $chat;$brnum = s/
//ig;
if($brnum > $brmax){
$i = $brnum - $brmax;
&err("コメントの行数が多すぎます。$i行減らして下さい。");
}
$len = length($chat);
if($len > $chatmax){
$i = $len - $chatmax;
&err("コメントの文字数が多すぎます。$iバイト減らして下さい。");
}
$vote = $FORM{'vote'}; #既存項目への投票
$voten = $FORM{'voten'}; #項目の新規作成
&err("項目名が長すぎます。") if(length($voten) > ($votemax*2));
$invalid = $FORM{'invalid'}; #無効票オプション
&newvote;
$detail = $FORM{'detail'}; #投票一覧の要求
$voteall = $FORM{'vall'}; #全投票の要求
#カウンタ制御
if(!$detail){
open(DB,"+<$cou_file")|| &err("カウンタファイルが開けません。");
$acou = 1 + ;
$acou = 0 if($acou > 99999);
seek(DB,0,0); print DB "$acou\n";
close(DB);
}
}#decode END
##################################################
sub readlog{ #配列@linesにログを読み込む
open(DB,"$chat_file") || &err("ログファイルが読めません。");
seek(DB,0,0); @lines = ;
close(DB);
$set=shift(@lines);
}#readlog END
##################################################
sub writelog{ #$valueを@linesに加えたのち、書き込む
(@lines < $vmax-1) || (@lines = @lines[0 .. $vmax - 2]);
unshift( @lines,$value);
$set = "$title:#$vkey:#$ddata:#$oname:#$ochat:#$ohost:#$odate:#\n";
open(DB,">$chat_file") || &err("ログファイルに書き込めません");
eval 'flock(DB,2);';
seek(DB,0,0); print DB $set; print DB @lines;
eval 'flock(DB,8);';
close(DB);
}#writelog END
##################################################
sub edit{
my($linenum1,$linenum2);
$linenum1 = @lines;
@lines=grep(!/$erase/,@lines);
$linenum2 = @lines;
if( $linenum1 ne $linenum2 ){
$value='';&writelog;&readlog;
}
}#edit END
##################################################
#新規項目(指定されていれば)を作成する
#既存項目と同じ名前だとその項目に投票される
sub newvote{
if($voten){
&err("項目への投票と新規項目作成が同時に行われました。") if($vote);
$vote = $voten;
}
}
##################################################
#@linesから項目リストを抽出する($voteだけを見ている)
sub makevotes{
my($line,$dmy1,$dmy2,$dmy3,$dmy4,$dmy5,$voten,$vote,$invalid);
foreach $line(@lines){
($voten,$dmy1,$vote,$dmy2,$dmy3,$dmy4,$dmy5,$invalid) = split(/:#/,$line);
foreach $v(keys(%votes)){
if($vote eq $v){
$votes{$vote}++;
$invalids{$vote}++ if($invalid);
$vote = '';
last;
}
}
if($vote){
$votes{$vote} = 1; #重複が無いように項目のリストを作る
$invalids{$vote} = 1 if($invalid);
}
}
}
##################################################
#項目リスト(%votes、%invalid)から投票状況のテーブルを作成
sub printtable{
my($vc,$ac,$per,$v,$vt,$link); #,$iw,$bar,$i);
$vc = 0;
$ac = 0;
foreach $vote(keys(%votes)){
$vc += $votes{$vote}-$invalids{$vote};
$ac += $votes{$vote};
}
print "";
print "選択項目 | 有効票数(投票数) | 割合 | グラフ |
\n";
foreach $vote (@sortedvotes){
$v = $votes{$vote}-$invalids{$vote};
if($vc != 0){
$per = int($v*100/$vc);
}
else{
$per = 0;
}
$iw = $per;
$iw = 1 if($iw == 0);
# $i = $per/5;
# $bar = '+';
# for(;$i>1;$i--){
# $bar = "$bar+";
# }
$vt = $vote;
$vt =~ s/([^0-9A-Za-z_ ])/'%'.unpack('H2',$1)/ge; #英数字でない所をエンコードする
$vt =~ s/\s/+/g;
if($voteall){
$link = "#$vote";
}else{
$link = "$cgi_log?detail=$vt&room=$room";
}
print "$vote | $v($votes{$vote}) | $per% | |
\n";
# print "$vote | $v($votes{$vote}) | $per% | $bar |
\n";
}
print"
\n";
print"有効投票総数$vc票(投票総数$ac票)\n";
}
##################################################
#投票項目の一覧を作成
sub makedetail{
my($dmy1,$dmy2,$dmy3,$dmy4,$dmy5,$vt,$cm,$dt,$iv,$cl);
print "\[$detailについてのコメント一覧\]
";
foreach $line(@lines){
($dmy1,$dmy2,$vt,$cm,$dt,$dmy4,$dmy5,$iv) = split(/:#/,$line);
if($iv){
$cl = '#0000FF';
}else{
$cl = '#000000';
}
if($detail eq $vt){
print "$cm\
($dt)
\n";
}
}
#print"
\n";
}
##################################################
#投票項目をソート
sub sortvotes{
@sortedvotes = sort{$votes{$b}*1000-$invalids{$b}*999<=>$votes{$a}*1000-$invalids{$a}*999}keys(%votes);
}
__END__