#!/usr/local/bin/perl # ############################################################# ### ### CGI多数投票 Ver.1.0 ### [1/2] 本体 ### ### (C) 2001 Sentora Dori ### http://www.lowpower.iis.u-tokyo.ac.jp/~hat ### ############################################################# # #################### 変数設定 #################### # アンケートデータをおくディレクトリのパス $databasedir = "."; # HTMLファイルをおくディレクトリのパス $htmlbasedir = "."; # 入力フォームを挿入する場所を示すタグのベース $baseinputtag = 'INPUT'; # アンケート結果を挿入する場所を示すタグのベース $baseresulttag = 'RESULT'; # 新しく入力される項目の最大の長さ $maxlength = 80; # テーブルの枠線の太さ $tableborder = 1; # テーブルの背景色 $tablecolor = ''; # 1: ログをとる 0: ログをとらない $takelog = 1; # post: postメソッド get: getメソッド $method = 'post'; # 2: flockを使用する 1: ロックファイルでロックする 0: ロックしない (通常は変更必要なし) $uselock = 2; # 漢字コード(sjis or jis or euc) $kanjicode = 'sjis'; #################### 変数設定(ここまで) #################### # 漢字ライブラリのファイル名 $jcodelib ='./jcode.pl'; # 次のアンケートデータとの区切り記号 (変更必要なし) $delimiter = "---nextenq---\n"; # flockを使用しないロックのときのロックファイル名のベース (変更必要なし) $baselockfile = './SDlock'; # このファイル名 $thisurl = 'multivote.cgi'; #----- 漢字コード設定 ----- require "$jcodelib"; if ($kanjicode eq 'sjis') { $contenttype = ""; # $contenttype = ""; } elsif ($kanjicode eq 'euc') { $contenttype = ""; # $contenttype = ""; } elsif ($kanjicode eq 'jis') { $contenttype = ""; } ##### format ##### #----- ユーザからの情報取得 ----- &init_form($kanjicode); $hostaddr = $ENV{'REMOTE_ADDR'}; $hostname = $ENV{'REMOTE_HOST'}; if ($hostaddr eq $hostname || $hostname eq '') { $hostname = gethostbyaddr(pack("C4", split(/\./, $hostaddr)), 2); } #----- 変数入力 ----- $enqname = $form{'enqname'} if ($form{'enqname'}); $datafile = "$databasedir/$enqname.txt"; $logfile = "$databasedir/$enqname.log"; $htmlname = $form{'htmlname'} if ($form{'htmlname'}); $htmlfile = "$databasedir/$htmlname"; $command = $form{'command'} if ($form{'command'}); $enqtitle = $form{'enqtitle'} if ($form{'enqtitle'}); $enqid = $form{'enqid'} if ($form{'enqid'}); $itemid = $form{'itemid'} if ($form{'itemid'}); $newitem = $form{'newitem'} if ($form{'newitem'}); $enqbegin = $form{'enqbegin'} if ($form{'enqbegin'}); $enqend = $form{'enqend'} if ($form{'enqend'}); $newitem = &norm_input($newitem); ##### branch(入力されたコマンドによる分岐) ##### if ($command eq 'read') { &do_read; } elsif ($command eq 'add') { &do_add; } elsif ($command eq 'vote') { &do_vote; } else { &do_read; } exit(0); ###################### ##### subroutine ##### ###################### ###### do(コマンド実行) ##### #----- アンケート結果を読む(設問と結果の表示) ----- sub do_read { &show_result; } #----- 新しい項目を加える(ファイルに書いてページを表示する) ----- sub do_add { if (length($newitem) > $maxlength) { &print_error("入力された項目名が長すぎます。"); } elsif ($newitem eq $delimiter) { &print_error("入力された名前はデータファイルで特殊記号として使用されているため、受け付けられません。"); } # data file open &open_file(TXT, "+<$datafile", "No data file"); &lock_file(TXT); @txt = ; # get title and txt $title = shift(@txt); $txtlist = join('', @txt); @result = split(/$delimiter/, $txtlist); @item = split(/\n/, $result[$enqid-1]); for ($i = 0; $i < @item; $i++) { ($name , $value) = split(/,/, $item[$i]); if ($newitem eq $name) { &print_error("あなたの入力した項目はすでにあります。"); } } $value = 1; @bakitem = ($newitem, $value); $item[@item] = join(',', @bakitem); $result[$enqid-1] = join("\n", @item)."\n"; $txtlist = $title.join("$delimiter", @result); seek(TXT, 0, 0); print TXT $txtlist; &unlock_file(TXT); &close_file(TXT); if ($takelog) { &take_log($enqid, $newitem, $value); } &show_result; } #----- 投票する ----- sub do_vote { # data file open &open_file(TXT, "+<$datafile", "No data file"); &lock_file(TXT); @txt = ; # get title and txt $title = shift(@txt); $txtlist = join('', @txt); @result = split(/$delimiter/, $txtlist); @item = split(/\n/, $result[$enqid-1]); ($name , $newvalue) = split(/,/, $item[$itemid]); $newvalue++; $bakname = $name; @bakitem = ($name, $newvalue); $item[$itemid] = join(',', @bakitem); # swap for ($i = $itemid; $i > 0; $i--) { ($name , $value) = split(/,/, $item[$i-1]); if ($newvalue > $value) { $bak = $item[$i-1]; $item[$i-1] = $item[$i]; $item[$i] = $bak; } else { last; } } $result[$enqid-1] = join("\n", @item)."\n"; $txtlist = $title.join("$delimiter", @result); seek(TXT, 0, 0); print TXT $txtlist; &unlock_file(TXT); &close_file(TXT); if ($takelog) { &take_log($enqid, $bakname, $newvalue); } &show_result; } ##### show(HTML表示) ##### #----- HTMLファイルと結果を表示する ----- sub show_result { # data file open &open_file(TXT, "$datafile", "No data file"); @txt = ; &close_file(TXT); # get title and txt $title = shift(@txt); chomp($title); $txtlist = join('',@txt); @result = split(/$delimiter/, $txtlist); $enqend = $#result+1 if ($enqend == 0); print "Content-type: text/html\n\n"; for ($i = $enqbegin; $i < $enqend + 1; $i++) { # make inputform $maxlength_zenkaku = int($maxlength / 2); $print_input[$i] = <<"END_INPUTFORM";
END_INPUTFORM # make result table @item = split(/\n/, $result[$i-1]); $print_result[$i] .= "
"; for ($j = 0; $j < @item; $j++) { ($name , $value) = split(/,/, $item[$j]); $print_result[$i] .= ""; } $print_result[$i] .= "
内容票数
$name$value投票
"; } # html file open &open_file(HTML, "$htmlfile", "No html file"); @html = ; &close_file(HTML); for ($i = 0; $i < @html; $i++) { for ($j = $enqbegin; $j < $enqend + 1; $j++) { $inputtag = "<$baseinputtag$j>"; $resulttag = "<$baseresulttag$j>"; if ($html[$i] =~ /$inputtag/i) { $html[$i] =~ s/$inputtag/$print_input[$j]/gi; } elsif ($html[$i] =~ /$resulttag/i) { $html[$i] =~ s/$resulttag/$print_result[$j]/gi; } } print $html[$i]; } } ##### ログ処理 ##### sub take_log { local($id, $name, $value) = @_; local($sec, $min, $hour, $day, $mon, $year); local($timelog); # log file open &open_file(LOGF, "+<$logfile", "log file error!"); &lock_file(LOGF); @logf = ; ($sec, $min, $hour, $day, $mon, $year) = localtime(time); $mon++; $year += 1900; if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } if ($sec < 10) { $sec = "0$sec"; } $timelog ="$year-$mon-$day $hour:$min:$sec"; @bakline = ($id, $name, $value, $timelog, $hostaddr, $hostname); $writeline = join(',', @bakline); $writeline .= "\n"; unshift(@logf, $writeline); seek(LOGF, 0, 0); print LOGF @logf; &unlock_file(LOGF); &close_file(LOGF); } ##### 入出力処理 ###### #----- ブラウザへの入力データの取得 ----- sub init_form { local($query, @dataarray, $data, $property, $value, $charcode, $method); $charcode = $_[0]; $method = $ENV{'REQUEST_METHOD'}; $method =~ tr/A-Z/a-z/; if ($method eq 'post') { read(STDIN, $query, $ENV{'CONTENT_LENGTH'}); } else { $query = $ENV{'QUERY_STRING'}; } @dataarray = split(/&/, $query); if ($dataarray[0] !~ /=/) { $enqname = $dataarray[0]; $htmlname = $dataarray[1]; $enqbegin = ($dataarray[2] =~ /^\d+$/) ? $dataarray[2] : 1; $enqend = ($dataarray[3] =~ /^\d+$/) ? $dataarray[3] : 0; } else { foreach $data (@dataarray) { ($property, $value) = split(/=/, $data); $value =~ tr/+/ /; $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg; &jcode'convert(*value, $charcode); $form{$property} = $value; } } } #----- 入力データからのタグ、メタ文字の消去 ----- sub norm_input { local($string) = @_; $string =~ s/&/&/g; $string =~ s/"/"/g; $string =~ s//>/g; $string =~ s/,/,/g; $string =~ s/:/:/g; $string =~ s/;/;/g; $string =~ s/\r\n/\n/g; $string =~ s/\r/\n/g; $string =~ s/\n\n/

/g; $string =~ s/\n/
/g; return $string; } ##### ファイル処理 ##### #----- ファイルオープン ----- sub open_file { local(*FILE, $name, $msg) = @_; if (!open(FILE, $name)) { &print_error("$msg"); } seek(FILE, 0, 0); } #----- ファイルクローズ ----- sub close_file { local(*FILE) = @_; close(FILE); } #----- ファイルロック ----- sub lock_file { local($FILE) = @_; local($LOCK) = "LOCK$FILE"; local($lockfile) = "$baselockfile$FILE"; local($retry) = 10; if ($uselock == 2) { eval(flock($FILE, 2)); if ($@) { return 0; } else { return 1; } } elsif ($uselock == 1) { while (-f $lockfile) { sleep(0.3); return 0 if (--$retry <= 0); } open($LOCK, ">$lockfile") || return 0; close($LOCK); return 1; } else { return 1; } } #----- ファイルアンロック ----- sub unlock_file { local($FILE) = @_; local($lockfile) = "$baselockfile$FILE"; if ($uselock == 2) { flock($FILE, 8); } elsif ($uselock == 1) { unlink($lockfile); } } ##### エラー処理 ##### #----- エラー文を出力し終了 ----- sub print_error { local($msg) = @_; print "Content-type: text/html\n\n"; print <<"END_PRINT_ERROR"; $contenttype $msg

$msg


END_PRINT_ERROR exit(0); }