#!/usr/local/bin/perl # ############################################################# ### ### CGI多数投票 Ver.1.0 ### [2/2] 管理用 ### ### (C) 2001 Sentora Dori ### http://www.lowpower.iis.u-tokyo.ac.jp/~hat ### ############################################################# ##### プログラム名(変更禁止) ##### $programname = 'enquete'; #################### 変数設定(ここから) #################### # アンケートデータをおくディレクトリのパス $databasedir = '.'; # 新しく入力される項目の最大の長さ $maxlength = 80; # パスワードファイルのあるディレクトリのパス $passfiledir = '../../../cgidata/SD'; # パスワードファイル名 $passfile = 'SDpass.txt'; # 管理用パスワード (省略するとパスワードファイルからパスワードを探す) $pass = ''; # テーブルの枠線の太さ $tableborder = 1; # テーブルの背景色 $tablecolor = ''; # post: postメソッド get: getメソッド $method = 'post'; # 2: flockを使用する 1: ロックファイルでロックする 0: ロックしない (通常は変更必要なし) $uselock = 2; # 漢字コード(sjis or jis or euc) $kanjicode = 'sjis'; #################### 変数設定(ここまで) #################### # このプログラムのタイトル $title = 'enquete manager'; # パスワードファイルであることを示すサイン $passsign = 'SDpassfile'; # 漢字ライブラリのファイル名 $jcodelib ='./jcode.pl'; # 次のアンケートデータとの区切り記号 (変更必要なし) $delimiter = "---nextenq---\n"; # flockを使用しないロックのときのロックファイル名のベース (変更必要なし) $baselockfile = './SDlock'; # このファイル名 $thisurl = 'multivman.cgi'; #----- 漢字コード設定 ----- require "$jcodelib"; if ($kanjicode eq 'sjis') { $contenttype = ""; # $contenttype = ""; } elsif ($kanjicode eq 'euc') { $contenttype = ""; # $contenttype = ""; } elsif ($kanjicode eq 'jis') { $contenttype = ""; } ##### format ##### $passfile = "$passfiledir/$passfile"; print $passfile; &init_form($kanjicode); #----- 変数入力 ----- if ($form{'enqname'}) { $enqname = $form{'enqname'}; $datafile = "$databasedir/$enqname.txt"; $logfile = "$databasedir/$enqname.log"; $showresult = 1; } else { $showresult = 0; } $command = $form{'command'}; $enqtitle = $form{'enqtitle'}; $enqid = $form{'enqid'}; $itemid = $form{'itemid'}; $newitem = $form{'newitem'}; $modifyitem = $form{'modifyitem'}; $modifyvalue = $form{'modifyvalue'}; $inputpass = $form{'inputpass'}; $newitem = &norm_input($newitem); ##### branch(入力されたコマンドによる分岐) ##### if ($command eq 'read') { &do_checkpass; &do_read; } elsif ($command eq 'make') { &do_checkpass; &do_make; } elsif ($command eq 'add') { &do_checkpass; &do_add; } elsif ($command eq 'delete') { &do_checkpass; &do_delete; } elsif ($command eq 'modify') { &do_checkpass; &do_modify; } elsif ($command eq 'checkpass') { &do_checkpass; &do_read; } else { &show_inputpass; } exit(0); ###################### ##### subroutine ##### ###################### ###### do(コマンド実行) ##### #----- アンケート結果表示 ----- sub do_read { &show_result; } #----- 新規アンケート作成 ----- sub do_make { &print_error("アンケート名に使用できる文字は英数字とアンダースコアのみです。") if ($enqname !~ /^\w+$/); &print_error("アンケートのタイトルが入力されていません。") if (!$enqtitle); @file_info = stat($datafile); if (-f "$datafile") { open(TXT, "+<$datafile"); @txt = ; $txt[0] = "$enqtitle\n"; seek(TXT, 0, 0); print TXT @txt; close(TXT); $print_titlechange ="指定したアンケートはすでに存在しましたので、タイトルのみ変更しました。" if ($file_info[7]); } else { open(TXT, ">$datafile"); print TXT "$enqtitle\n"; close(TXT); open(LOGF, ">$logfile"); close(LOGF); chmod (0666, $datafile); chmod (0666, $logfile); } &show_result; } #----- 新しい項目を加える ----- sub do_add { if (length($newitem) > $maxlength) { &print_error("入力された項目名が長すぎます。"); } elsif ($newitem eq $delimiter) { &print_error("入力された名前はデータファイルで特殊記号として使用されているため、受け付けられません。"); } &print_error("アンケート番号が入力されていません。") if ($enqid !~ /^\d+$/); &open_file(TXT, "+<$datafile", "No data file"); &lock_file(TXT); @txt = ; $enqtitle = 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 = $enqtitle.join("$delimiter", @result); seek(TXT, 0, 0); print TXT $txtlist; &unlock_file(TXT); &close_file(TXT); &show_result; } #----- 削除する ----- sub do_delete { $msg = ''; $msg .= "アンケート番号が入力されていません。
" if ($enqid !~ /^\d+$/); $msg .= "項目番号が入力されていません。
" if ($itemid !~ /^\d+$/); &print_error($msg) if ($msg); open_file(TXT, "+<$datafile", "No data file"); &lock_file(TXT); @txt = ; $enqtitle = shift(@txt); $txtlist = join('', @txt); @result = split(/$delimiter/, $txtlist); @item = split(/\n/, $result[$enqid-1]); if ($enqid < 1 || $enqid > @result) { &print_error("入力されたアンケート番号はありません。
"); } if ($itemid < 0 || $itemid > @item) { &print_error("入力された項目番号はありません。
"); } splice(@item, $itemid-1, 1); $result[$enqid-1] = join("\n", @item)."\n"; $txtlist = $enqtitle.join("$delimiter", @result); seek(TXT, 0, 0); print TXT $txtlist; truncate(TXT, tell(TXT)); &unlock_file(TXT); &close_file(TXT); &show_result; } #----- 修正する ----- sub do_modify { $msg = ''; $msg .= "アンケート番号が入力されていません。
" if ($enqid !~ /^\d+$/); $msg .= "項目番号が入力されていません。
" if ($itemid !~ /^\d+$/); &print_error($msg) if ($msg); if (length($modifyitem) > $maxlength) { &print_error("入力された項目名が長すぎます。"); } elsif ($modifyitem eq $delimiter) { &print_error("入力された名前はデータファイルで特殊記号として使用されているため、受け付けられません。"); } &open_file(TXT, "+<$datafile", "No data file"); &lock_file(TXT); @txt = ; $enqtitle = shift(@txt); $txtlist = join('', @txt); @result = split(/$delimiter/, $txtlist); @item = split(/\n/, $result[$enqid-1]); if ($enqid < 1 || $enqid > @result) { &print_error("入力されたアンケート番号はありません。
"); } if ($itemid < 1 || $itemid > @item) { &print_error("入力された項目番号はありません。
"); } ($name , $value) = split(/,/, $item[$itemid-1]); if ($modifyitem) { $newitem = $modifyitem; } else { $newitem = $name; } if ($modifyvalue =~ /^\d+$/) { $newvalue = $modifyvalue; } else { $newvalue = $value; } @bakitem = ($newitem, $newvalue); $item[$itemid-1] = join(',', @bakitem); # sort if ($modifyvalue =~ /^\d+$/) { for ($k = 0; $k < @item - 1; $k++) { for ($l = $k + 1; $l < @item; $l++) { ($name1 , $value1) = split(/,/, $item[$k]); ($name2 , $value2) = split(/,/, $item[$l]); if ($value1 < $value2) { $bak = $item[$k]; $item[$k] = $item[$l]; $item[$l] = $bak; } } } } $result[$enqid-1] = join("\n", @item)."\n"; $txtlist = $enqtitle.join("$delimiter", @result); seek(TXT, 0, 0); print TXT $txtlist; &unlock_file(TXT); &close_file(TXT); &show_result; } #----- パスワードチェック ----- sub do_checkpass { local($i); if ($pass) { return if ($pass eq $inputpass); &print_error("[password mismatch]"); } open(TXT, "$passfile") || die &print_error('[no password file]'); @txt = ; close(TXT); ($sign, $pass) = splice(@txt, 0, 2); chomp($sign); chomp($pass); if ($sign ne $passsign) { &print_error("[not password file]"); } $passmatch = 0; for ($i = 0; $i < @txt; $i++) { ($name, $pass) = split(/,/, $txt[$i]); chomp($pass); if ($name eq $programname) { if ($pass ne crypt($inputpass, $pass)) { &print_error("[password mismatch!]"); } else { $passmatch = 1; last; } } } &print_error("[no adequate password in password file]") if (!$passmatch); return; } ##### show(HTML表示) ##### #----- HTMLファイルと結果を表示する ----- sub show_result { if ($showresult == 1) { &open_file(TXT, "$datafile", "No data file"); @txt = ; &close_file(TXT); $enqtitle = shift(@txt); $txtlist = join('', @txt); @result = split(/$delimiter/, $txtlist); } $zenkaku_maxlength = int($maxlength / 2); print "Content-type: text/html\n\n"; print <<"END_HEADER"; $title
$title


$print_titlechange
アンケート結果表\示
アンケート名
新規アンケート作成 (英数字と_のみ)
アンケート名
タイトル

以下の操作は、上でアンケート名を入力し、結果を表\示させてから行ってください。
項目は全角$zenkaku_maxlength文字以内です。
新規項目追加
アンケート番号
新しい項目
項目の削除
アンケート番号 項目番号
項目の修正 (内容、票数は省略すると変更しません。)
アンケート番号 項目番号
内容の修正
票数

タイトル: $enqtitle
END_HEADER for ($i = 0; $i < @result; $i++) { @item = split(/\n/, $result[$i]); $bakenqid = $i+1; print "アンケート番号 $bakenqid"; print "
"; for ($j = 0; $j < @item; $j++) { ($name , $value) = split(/,/, $item[$j]); $bakitemid = $j+1; print ""; } print "
項目番号内容票数
$bakitemid$name$value

"; } print ""; } #----- マスターパスワード入力画面表示 ----- sub show_inputpass { print "Content-type: text/plain\n\n"; print <<"END_SHOW_INPUTPASS"; $title
$title
管理用パスワード入力


パスワード
END_SHOW_INPUTPASS } ##### 入出力処理 ###### #----- ブラウザへの入力データの取得 ----- 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); 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); }