#!/usr/local/bin/perl ############################################################################## # # 出席表 cgi version 0.9 for perl5(UNIX) # # Copyright(C) 2000 WAKI Toshihito (和気 愛仁) # mailto:HQL05475@nifty.ne.jp # ############################################################################## # # ◆概要 # # この cgi スクリプトは、web上で授業の出席管理を行うものです。このスクリプト # でできることは以下の通りです。 # # ・履修学生は、授業日の授業時間帯のみ、出席を申告できます。申告した時刻をデ # ータとして保存します。申告にあたっては、サーバのアカウント認証を行います # ので、本人確認がより確実にできます。また、登録した教室以外からの出席登録 # は受け付けられません。 # # ・履修学生は、いつでも自分の過去の出席状況を確認できます。出席状況の確認の # 場合も、サーバのアカウント認証を行いますので、他人の出席状況は見ることが # できません。 # # ・担当教官(cgi 管理者)は、すべての履修学生の出席状況をいつでも確認・編集 # できます(要パスワード)。一覧表形式だけでなく、csv 形式でも表示できます # ので、Excel などにコピー&ペーストして楽ができます:-)。 # # このスクリプトでは、受講者の本人確認を行うために、スクリプト内部で ftp サ # ーバ(localhost)にアクセスし、web ページから送られたユーザ名とパスワード # を使ってユーザ認証を行います。したがって、このスクリプトを利用するためには、 # web サーバと ftp サーバが同じ UNIX ホスト上で動いていて、かつ、そのホスト # に受講者のアカウントがあることが必要です。この条件を満たさない場合は、この # スクリプトを利用できません。 # # また、perl から ftp を行うために、Net::FTP という perl のモジュールを利用 # します。UNIX サーバにこのモジュールがインストールされていない場合も、この # スクリプトを利用できません。Net::FTP のインストールに関しては、システム管 # 理者にお問い合わせください。 # # # ◆重要な注意事項 # # web ページから localhost(= ftp サーバ)のアカウントの認証を行うという危な # いことをしていますので、セキュリティには十分注意してください。https(SSL対 # 応 web サーバ)の使用を **強く** 推奨します。 # # httpを使用した場合、パスワードが平文でネット上を流れてしまいます。これは、 # 悪意を持ったシステム管理者によって、パスワードが盗聴され、不正アクセスされ # る可能性があることを意味します。 # # https の使用が不可能な場合、最低でも、外部からアクセス制限されたネットワー # ク内での利用にとどめてください。くれぐれも、インターネットから直接接続可能 # な環境では使用しないでください。 # # また、ftp でアクセスに行くホストを localhost 以外のサーバに書き換えた場合、 # https でブラウザから web サーバまでの経路を暗号化しても、web サーバから # ftp サーバまでは結局平文でパスワードが流れますので、危険です。したがって、 # ftp でアクセスしに行く先のホスト名は、localhost 以外には書き換えないほうが # 賢明です。自己の責任において、両方のサーバ間の経路が安全であることを保証で # きる(か、どうなってもかまわないと割り切れる)のであれば、書き換えてご利用 # ください。書き換えの方法についてはあえて触れません。 # # # ◆著作権・免責 # # このスクリプトはフリーソフトウェアですが、著作権は作者である和気愛仁が所有 # します。改変は自由ですが、改変したバージョンのスクリプトを再配布することは # 禁止します。 # # 万が一このスクリプトを利用したために何らかの不都合が起こったとしても、作者 # は一切責任を負えませんのであしからずご了承ください。この条件に同意できる場 # 合のみ、このスクリプトをお使いいただけます。 # # # ◆更新履歴 # # version 0.1 (2000/10/12) # ・初期型 # version 0.2 (2000/10/14) # ・管理者のみ一覧表示可能(要パスワード)にした # ・学生は自分の分のみ出席状況を確認可能にした # ・管理者モードの URL をブラウザで直接指定した場合接続拒否するようにした # ・ドキュメントに「データファイル・パスワードファイルの保護」の項目を追加 # version 0.3 (2000/10/23) # ・ライブラリパスについての注意書きを更新 # version 0.4 (2000/10/31) # ・出席状況確認処理のバグつぶし # ・ファイルの配置方法を変更 # ・パスワードファイルの自動作成をやめて、あらかじめ用意するようにした # version 0.5 (2000/11/2) # ・管理者がデータを編集できるようにした # ・一般公開に向けてドキュメントを更新 # version 0.6 (2000/11/3) # ・学生の名前を入力させるのをやめた # ・学生が同じ時間に2回出席登録したときに、登録済みメッセージを出すように # 変更した # version 0.7 (2000/11/10) # ・遅刻処理を追加した # ・出席登録完了画面でのセル背景色の処理を修正 # version 0.8 (2000/11/16) # ・データの保存方法について、全員でひとつのファイルを使う方式からユーザご # とに別のファイルを使う方式に仕様を変更した # version 0.9 (2001/06/06) # ・教室の判定処理を追加した # ・管理用画面で出席人数の合計を表示するようにした # ・ユーザ認証に Net::FTP を使うように変更 # # ◆謝辞 # # 開発にあたって、以下の方々には大変お世話になりました。この場を借りて御礼申 # し上げます。ありがとうございました。 # # 衞藤 敦 様 etoh@koshigaya.bunkyo.ac.jp # # 遅刻処理を追加していただきました。また、仕様に関するさまざまなアドバイス # をいただきました。 # # ネットサーフレスキュー[Web裏技] 様 http://www.www.rescue.ne.jp # # パスワード暗号化ルーチンを利用させていただきました。 # # ############################################################################## # # # 0. ファイル一覧 # # presence.cgi : cgi スクリプト。ファイル名は任意(2.で後述)。 # data.csv : データファイル。ファイル名は任意(4.で後述)。 # passwd.pwd : 管理者用パスワードファイル。ファイル名は任意(4.で後 # 述)。空のテキストファイルを自分で用意してください。 # jcode.pl : perl のライブラリ。漢字コード変換に利用。 # # # 1. データファイルの書式 # # データファイルは、csv(カンマ区切り)形式で作成してください。実際の例はサ # ンプルファイル data.csv を参照してください。 # # 1行目に授業のデータ、2行目に日付のデータを書き、3行目以降に履修者のデー # タを並べます。書式は以下の通り。 # # ※1行目の書式: # ・科目名 # ・担当教員名 # ・曜日(漢字可。そのまま表示されます) # ・時限(漢字可。そのまま表示されます) # ・授業開始時刻(半角英数。時間、分、秒をコロンで区切る) # ・授業終了時刻(半角英数。時間、分、秒をコロンで区切る) # 以上を、カンマで区切って一行で書きます。一桁の時刻は一桁のままでかまいま # せん。 # 例: # 情報処理I-(2),山田金太郎,金曜日,3時限,13:00:00,14:30:00 # # ※2行目の書式: # 学期中の授業のある日付を、"0月0日"という形式で連ねます。数字は半角でなけ # ればなりません。一桁の日付は一桁のままでかまいません。 # 例: # 9月29日,10月6日,10月13日,10月20日,10月27日,11月10日,11月17日 # # ※3行目の書式: # 出席を受け付ける端末の IP アドレスを列挙します。一台ずつカンマで区切るか、 # アドレス範囲を - でつないで記述してください。192.168.1.1-20 のような書き方 # はできません。この場合は 192.168.1.1-192.168.1.20 と記述してください。 # 例: # 192.168.1.1,192.168.1.3-192.168.1.10,192.168.1.20 # # ※4行目以降の書式: # ・ユーザ名(ftp サーバの。半角英数。大文字でも小文字でもかまいませんが、 # 表示時に小文字に統一されます) # ・名前(漢字可。そのまま表示されます) # ・学年(漢字可。そのまま表示されます) # 以上を、カンマで区切って一行で書きます。学年の後ろにはカンマを入れません。 # これを、全履修者分並べます。 # 例: # A0L00000,山田太郎,1 # A0L00001,斎藤花子,1 # (以下続く) # # # 2. スクリプトの書き換え # # このスクリプト1行目の perl のパス、および「初期設定」の部分を必要に応じて # 書き換えます。それ以外の部分をいじってもかまいませんが、各自の責任でお願い # いたします。 # # # 3. ファイルの配置とパーミッション設定 # # 以下の図のようにファイル、ディレクトリを配置し、それぞれのパーミッションを # 変更します。データファイル・パスワードファイルは、dataという名前でサブディ # レクトリを作成し、その中に配置します。 # # ファイル(ディレクトリ)名 : モード値 # ------------------------------------- # |-- presence.cgi : 755 # |-- jcode.pl : 644 # +-- data/ : 777 # |-- passwd.pwd : 666 # +-- data.csv : 644 # # スクリプト配置ディレクトリは、当然 cgi の実行が許可されたディレクトリでな # ければなりません。 # # # 4. データファイル・パスワードファイルの保護 # # ここでいうパスワードファイルとは、スクリプト内部で利用する、管理者用のパス # ワードが書かれたファイル(ファイル名は変更可能)です。管理者用パスワードは、 # 一覧表示、csv 形式表示の際に必要になります。データファイルやパスワードファ # イルの URL をブラウザで直接指定されると中身が丸見えになってしまいますので、 # 保護しておいたほうがよいでしょう。これには web サーバの機能を使います。 # .htaccess という名前(ファイル名の先頭がピリオドであることに注意)でテキス # トファイルを作成し、その中に、 # # # order deny,allow # deny from all # # # order deny,allow # deny from all # # # と記述します。このファイルを、データディレクトリにおいてください。これで、 # そのディレクトリ内にある拡張子が .csv および .pwd のファイルは、ブラウザで # 参照できなくなります。データファイル・パスワードファイルの拡張子を変更した # 場合は、上の "csv" "pwd" の部分を、それぞれ変更した拡張子に書き換えてくだ # さい。 # # なお、以上の方法が使えるのは、web サーバが Apache 1.2 以降の場合です。それ # 以外の web サーバの場合は私にはわかりません。もしこの方法が使えない場合は、 # データファイル・パスワードファイルいずれも、拡張子を .cgi にしてしまえば、 # とりあえずブラウザで参照することはできなくなります。 # # データディレクトリ内のファイル名一覧さえも表示させたくないという場合は、ダ # ミーの index.html を作っておいておくのが簡単でしょう。その他サーバの機能を # 使う方法もありますが、ここでは触れません。 # # # 5. 起動方法 # # HTML の中に、以下のようにタグを記述します。"?file=" の後ろにデータファイル # 名を指定します。データディレクトリ名の指定は不要です。 # # 出席表 # # また、複数のデータファイルを別々に扱うこともできます。その場合は、 # # 3限目出席表
# 4限目出席表 # # のように記述してください。 # # なお、1回目の起動時のみ、管理者用のパスワードの設定画面になりますので、適 # 切なパスワードを設定してください。 # # # 6. 注意事項 # # ブラウザ上で表示される「学籍番号」とはすなわち、ftp サーバ(として稼働して # いる UNIX マシン)のユーザ名です。同様に「電子メールのパスワード」も、ftp # サーバのパスワードです。 # # 多人数が一度に書き込みにいった場合でも問題なく処理するようにしてあるはずで # すが、もしかしたらデータファイルが破損する場合もあるかもしれません。データ # ファイルは随時バックアップしておいてください。 # # 文字コードは Shift-JIS 専用です。 # # #----------------------- script start ----------------------- unshift (@INC, "."); require 'jcode.pl'; use Net::FTP; #------------------------- 初期設定 -------------------------- # このスクリプトのファイル名 $script = 'presence.cgi'; # cgi スクリプトの URL 表記(http:// または https:// から始まる完全表記) $ref_url = 'http://www2b.biglobe.ne.jp/~wakit/SOFTWARE/cgi/sample/presence.cgi'; # 管理者用パスワードファイルの名前(パスではなく名前のみ) $pwd_file = 'passwd.pwd'; # データディレクトリのパス(/で閉じないこと) $data_dir = './data'; # タイトル $title = '出席表\'; # バックグラウンド、文字色等の設定。HTML の タグ書式 $body = ''; # 出席表の項目見出しの背景色 $titleback = 'bgcolor="#7777ff"'; # 出席表の1行おきの背景色 $linebgcolor = 'bgcolor="#eeeeff"'; # 戻る先のURL $returnto = '../../'; # 出席を認めるリミット(分単位で指定) $delaylimit = 30; #------------------------- main ----------------------------- $servername = "localhost"; $sendvalue = " 登録する "; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $date_num = sprintf("%04d%02d%02d%02d%02d%02d",$year +1900,$mon +1,$mday,$hour,$min,$sec); $ps = $$; if ($ps eq '') { $ps = $date_num; } $tmp_file = "$ps\.tmp"; &decode; if (!-e "$data_dir\/$pwd_file") {&error('エラー', "管理者用パスワードファイルが見つかりません。");} if ($in{'file'} eq '') { &error('エラー', "データファイル名が指定されていません。"); } else { $studentDir = $in{'file'}; $studentDir =~ s/\.csv//i; if (!-e "$data_dir\/$studentDir"){ mkdir ("$data_dir\/$studentDir", 0755); chmod (0777, "$data_dir\/$studentDir"); } } if ($in{'action'} eq 'send') { &send;} elsif ($in{'action'} eq 'csv') { &viewcsv; } elsif ($in{'action'} eq 'viewall') { &viewall; } elsif ($in{'action'} eq 'edit') { &edit; } elsif ($in{'action'} eq 'rewrite') { &rewrite; } elsif ($in{'action'} eq 'setpwd') { &setpwd; &viewform; } elsif (-z "$data_dir\/$pwd_file" || $in{'action'} eq 'resetpwd') { &setpwd_form; } else { &viewform; } exit; #----------------------- sub routines ---------------------- sub viewform { open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print ""; print ""; print "
学籍番号:
電子メールのパスワード:
 
\n"; print "
\n"; print "
\n"; print "
\n"; print "※学籍番号と電子メールのパスワードを入力して、ボタンを押してください。ボタンは一回だけ押して、画面の反応があるまで待ってください。
\n"; print "※授業日以外、授業時間帯以外に送信しても出席は認められません。また、教室外からの登録も認められません。
\n"; print "※出席状況の確認はいつでも可能\です。
\n"; print "

\n"; print "[ 戻る ]\n"; print "
\n"; print "
\n"; print "
\n"; print "\n"; print "\n"; print "\n"; print "
\n"; print "\n"; } sub viewline { open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); ($hr, $mn, $sc) = split(/:/, $starttime); $endtime2 = $delaylimit * 60 + $hr * 3600 + $mn * 60 + $sc; $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; $flag = 0; for ($i=3; $i<=$#lines; $i++){ $lines[$i] =~ s/\n//g; ($studentID, $name, $grade) = split(/,/, $lines[$i]); if ($in{'studentID'} =~ /^$studentID$/i) { $studentFile = "$studentID.csv"; if (!-e "$data_dir\/$studentDir\/$studentFile") { open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile を作成できません。"); print OUT "$studentID,$name,$grade\n"; close (OUT); chmod 0666, "$data_dir\/$studentDir\/$studentFile"; } my $ftp = Net::FTP->new($servername); if (!$ftp) { &error('システムエラー','サーバへの接続に失敗しました。'); } $result = $ftp->login($in{'studentID'}, $in{'password'}); $ftp->quit; if ($result) { #パスワードあたり $flag = 2; } else { #パスワード違い $flag = 1; } last; } else { #ユーザ名不一致 } } if ($flag == 0) { &error('エラー', '一致する学籍番号がありません。半角文字と全角文字は区別されますので注意してください。'); } elsif ($flag == 1) { &error('エラー', 'パスワードが一致しません。小文字と大文字、半角文字と全角文字は区別されますので注意してください。キーボードの CapsLock も確認してください。'); } if ($flag != 2) { &error('エラー', 'エラーです。戻って再度実行してください。'); } open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #ユーザ名(学籍番号)を小文字で表示 $data[0] =~ tr/A-Z/a-z/; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "$data[1] さん(学籍番号:$data[0])の出席状況
\n"; print "
\n"; print "\n"; print ""; foreach (@classes){ print ""; } print "\n"; print "\n"; print ""; for ($j=3 ; $j<=$#data; $j++){ if ($data[$j] eq '') { print ""; } elsif ($data[$j] =~ /[0-9]+:[0-9]+:[0-9]+/) { ($hr, $mn, $sc) = split(/:/, $data[$j]); $timetemp3 = $hr * 3600 + $mn * 60 + $sc; if ($timetemp3>$endtime2) { print ""; } else { print ""; } } else { print ""; } } print "\n"; print "
学籍番号氏名学年$_
$data[0]$data[1]$data[2]$data[$j]
\n"; print "
\n"; print "
\n"; print "
\n"; print "[ 戻る ]
\n"; print "\n"; } sub viewall { &checkadmin; open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); ($hr, $mn, $sc) = split(/:/, $starttime); $endtime2 = $delaylimit * 60 + $hr * 3600 + $mn * 60 + $sc; $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
\n"; print "\n"; print ""; foreach (@classes){ print ""; } print "\n"; for ($i=3; $i<=$#lines; $i++){ $border++; if (($border % 2) != 0) { $bgcolor = $linebgcolor; } else { $bgcolor = ""; } $lines[$i] =~ s/\n//g; ($studentID, $name, $grade) = split(/,/, $lines[$i]); $studentFile = "$studentID.csv"; if (!-e "$data_dir\/$studentDir\/$studentFile") { open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile を作成できません。"); print OUT "$studentID,$name,$grade\n"; close (OUT); chmod 0666, "$data_dir\/$studentDir\/$studentFile"; } open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #ユーザ名(学籍番号)を小文字で表示 $data[0] =~ tr/A-Z/a-z/; print ""; print ""; for ($j=3 ; $j<=$#data; $j++){ if ($data[$j] eq '') { print ""; } elsif ($data[$j] =~ /[0-9]+:[0-9]+:[0-9]+/) { ($hr, $mn, $sc) = split(/:/, $data[$j]); $timetemp3 = $hr * 3600 + $mn * 60 + $sc; if ($timetemp3>$endtime2) { print ""; } else { print ""; } $counts[$j-3]++; } else { print ""; $counts[$j-3]++; } } print "\n"; } print ""; for ($j=3 ; $j<=$#data; $j++){ if ($counts[$j-3]==0) { $countbyday = " "; } else { $countbyday = $counts[$j-3]; } print ""; } print ""; print "
 学籍番号氏名学年$_
[ 修正 ]$data[0]$data[1]$data[2]$data[$j]
 出席人数$countbyday
\n"; print "
\n"; print "
\n"; print "
\n"; print "[ 更新 ] \n"; print "[ csv 形式で表\示 ]

\n"; print "[ 管理パスワード変更 ]

\n"; print "[ 戻る ]
\n"; print "\n"; } sub viewcsv { &checkadmin; open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
\n"; print "
";
	print "学籍番号,氏名,学年";
	foreach (@classes){
		print ",$_";
	}
	print "\n";

	for ($i=3; $i<=$#lines; $i++){
		$lines[$i] =~ s/\n//g;
		($studentID, $name, $grade) = split(/,/, $lines[$i]);
		$studentFile = "$studentID.csv";

		if (!-e "$data_dir\/$studentDir\/$studentFile") {
			open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile を作成できません。");
			print OUT "$studentID,$name,$grade\n";
			close (OUT);
			chmod 0666, "$data_dir\/$studentDir\/$studentFile";
		}

		open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。");
		$line = ;
		close(IN);

		@data = ();

		$line =~ s/\n//g;
		@data = split(/,/, $line);
		$#data = 2 + $classcount;

		#ユーザ名(学籍番号)を小文字で表示
		$data[0] =~ tr/A-Z/a-z/;
		$line = join (',', @data);
		print "$line\n";
	}
	print "
"; print "
\n"; print "
\n"; print "[ 更新 ] \n"; print "[ 一覧表\形式で表\示 ]

\n"; print "[ 管理パスワード変更 ]

\n"; print "[ 戻る ]
\n"; print "\n"; } sub send { if ($in{'studentID'} eq '') { &error('エラー', '学籍番号が入力されていません。'); } if ($in{'password'} eq '') { &error('エラー', 'パスワードが入力されていません。'); } if ($in{'send'} ne $sendvalue) { &viewline; exit; } open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); ($hr, $mn, $sc) = split(/:/, $starttime); $starttime = sprintf("%02d%02d%02d", $hr, $mn, $sc); $endtime2 = $delaylimit * 60 + $hr * 3600 + $mn * 60 + $sc; ($hr, $mn, $sc) = split(/:/, $endtime); $endtime = sprintf("%02d%02d%02d", $hr, $mn, $sc); $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; # 端末のIPアドレスチェック @clientdata = split(/,/, $lines[2]); @clientlist = (); foreach (@clientdata) { if ($_ =~ /-/) { ($addrfrom, $addrto) = split(/-/); if ($addrfrom =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/){ $addrhead = "$1.$2.$3"; $from = $4; } if ($addrto =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/){ $to = $4; } for ($i = $from; $i <= $to; $i++){ push(@clientlist, "$addrhead.$i"); } } else { push(@clientlist, $_); } } $clientaddr = $ENV{'REMOTE_ADDR'}; if (!grep(/$clientaddr/, @clientlist)) { &error('エラー', '教室外からの出席登録は受け付けられません。'); } $flag = 0; for ($i=3; $i<=$#lines; $i++){ $lines[$i] =~ s/\n//g; ($studentID, $name, $grade) = split(/,/, $lines[$i]); if ($in{'studentID'} =~ /^$studentID$/i) { $studentFile = "$studentID.csv"; my $ftp = Net::FTP->new($servername); if (!$ftp) { &error('システムエラー','サーバへの接続に失敗しました。'); } $result = $ftp->login($in{'studentID'}, $in{'password'}); $ftp->quit; if (!$result) { #パスワード違い $flag = 1; } else { #パスワードあたり $datetemp = sprintf("%02d%02d", $mon + 1, $mday); $timetemp = sprintf("%02d%02d%02d", $hour, $min, $sec); $timetemp2 = sprintf("%02d:%02d:%02d", $hour, $min, $sec); $timetemp3 = $hour * 3600 + $min * 60 + $sec; if (!-e "$data_dir\/$studentDir\/$studentFile") { open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile を作成できません。"); print OUT "$studentID,$name,$grade\n"; close (OUT); chmod 0666, "$data_dir\/$studentDir\/$studentFile"; } open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #授業日以外ならこれが残る $flag = 4; for ($j=0; $j<=$classcount; $j++){ #日付を取得 $classtemp = $classes[$j]; $classtemp =~ s/日//; ($m, $d) = split('月', $classtemp); #もし$classtempが今日の日付なら if (sprintf("%02d%02d", $m, $d) eq $datetemp) { #もし$timetemp が 授業時間中なら if ($timetemp>=$starttime && $timetemp<=$endtime) { #まだ何もデータがなければ if ($data[$j+3] eq '') { #出席 $flag = 2; #$data[$j+3]を現在時刻に書き換え $data[$j+3] = $timetemp2; } else { &error('出席登録済み', 'すでに出席登録されています。'); } } else { # 授業時間外 $flag = 3; } last; } } #書き出し open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile に書き込めません。"); print OUT join(",", @data) . "\n"; close (OUT); } } else { #ユーザ名不一致 } } if ($flag == 0) { &error('エラー', '一致する学籍番号がありません。半角文字と全角文字は区別されますので注意してください。'); } elsif ($flag == 1) { &error('エラー', 'パスワードが一致しません。小文字と大文字、半角文字と全角文字は区別されますので注意してください。キーボードの CapsLock も確認してください。'); } elsif ($flag == 3) { &error('エラー', '授業時間外です。'); } elsif ($flag == 4) { &error('エラー', '授業日ではありません。'); } if ($flag != 2) { &error('エラー', 'エラーです。戻って再度送信してください。'); } open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #ユーザ名(学籍番号)を小文字で表示 $data[0] =~ tr/A-Z/a-z/; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
\n"; print "出席を受理しました。
\n"; if ($timetemp3>$endtime2) { print "ただし、遅刻です。
\n"; } print "
\n"; print "
\n"; print "$data[1] さん(学籍番号:$data[0])の出席状況
\n"; print "
\n"; print "\n"; print ""; foreach (@classes){ print ""; } print "\n"; print ""; print ""; for ($j=3 ; $j<=$#data; $j++){ if ($data[$j] eq '') { print ""; } elsif ($data[$j] =~ /[0-9]+:[0-9]+:[0-9]+/) { $classtemp = $classes[$j-3]; $classtemp =~ s/日//; ($m, $d) = split('月', $classtemp); #もし$classtempが今日の日付なら if (sprintf("%02d%02d", $m, $d) eq $datetemp) { $bgcolor_send = "bgcolor=\"#ffaaaa\""; } else { $bgcolor_send = ""; } ($hr, $mn, $sc) = split(/:/, $data[$j]); $timetemp3 = $hr * 3600 + $mn * 60 + $sc; if ($timetemp3>$endtime2) { print ""; } else { print ""; } } else { print ""; } } print "\n"; print "
学籍番号氏名学年$_
$data[0]$data[1]$data[2]$data[$j]
\n"; print "
\n"; print "
\n"; print "
\n"; print "[ 戻る ]
\n"; print "\n"; } sub edit { open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; $studentFile = "$in{'studentID'}.csv"; open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #ユーザ名(学籍番号)を小文字で表示 $data[0] =~ tr/A-Z/a-z/; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
"; print "\n"; print ""; foreach (@classes){ print ""; } print "\n"; print ""; print ""; print ""; print ""; print ""; for ($j=3 ; $j<=$#data; $j++){ print ""; } print "\n"; print "
学籍番号氏名学年$_
$data[0]$data[1]$data[2]
\n"; print "
\n"; print "※授業時間内にデータを修正すると、最悪の場合、履修者側の申\告と重なって、データの矛盾を生じる可能\性があります。注意してください。

\n"; print "\n"; print "
\n"; print "
\n"; print "
\n"; print "
\n"; print "
\n"; print "[ 戻る ]
\n"; print "\n"; } sub rewrite { open (IN, "$data_dir\/$in{'file'}") || &error('エラー', "データファイル $in{'file'} が開けません。"); @lines = ; close(IN); $lines[0] =~ s/\n//g; ($classname, $teacher, $day, $period, $starttime, $endtime) = split(/,/, $lines[0]); ($hr, $mn, $sc) = split(/:/, $starttime); $endtime2 = $delaylimit * 60 + $hr * 3600 + $mn * 60 + $sc; $lines[1] =~ s/\n//g; @classes = split(/,/, $lines[1]); $classcount = @classes; $studentFile = "$in{'studentID'}.csv"; open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; for ($j=0; $j<=$classcount; $j++){ $classcol = $j + 3; $data[$j+3] = $in{$classcol}; } open (OUT, ">$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile に書き込めません。"); print OUT join(",", @data) . "\n"; close (OUT); open (IN, "$data_dir\/$studentDir\/$studentFile") || &error('エラー', "学生データファイル $studentFile が開けません。"); $line = ; close(IN); @data = (); $line =~ s/\n//g; @data = split(/,/, $line); $#data = 2 + $classcount; #ユーザ名(学籍番号)を小文字で表示 $data[0] =~ tr/A-Z/a-z/; print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

$title

\n"; print "$classname $day $period
\n"; print "
担当:$teacher
\n"; print "
\n"; print "
\n"; print "\n"; print ""; foreach (@classes){ print ""; } print "\n"; print ""; print ""; for ($j=3 ; $j<=$#data; $j++){ if ($data[$j] eq '') { print ""; } elsif ($data[$j] =~ /[0-9]+:[0-9]+:[0-9]+/) { ($hr, $mn, $sc) = split(/:/, $data[$j]); $timetemp3 = $hr * 3600 + $mn * 60 + $sc; if ($timetemp3>$endtime2) { print ""; } else { print ""; } } else { print ""; } } print "\n"; print "
学籍番号氏名学年$_
$data[0]$data[1]$data[2]$data[$j]
\n"; print "
\n"; print "
\n"; print "
\n"; print "[ 前の画面へ戻る ]
\n"; print "
\n"; print "[ 一覧へ戻る ]
\n"; print "\n"; } sub checkadmin { # 管理者モードの[更新]の場合 if ($in{'admin'} eq 'admin' ) { # このスクリプト以外から呼ばれた場合(ブラウザに URL を直接打ち込んでアクセスした場合など)は拒否する $ref = $ENV{'HTTP_REFERER'}; $ref =~ tr/+/ /; $ref =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; if (!($ref =~ /$ref_url/i)) { &referror; } } else { if ($in{'password'} eq '') { &error('エラー', 'パスワードが入力されていません。'); } if (!-z "$data_dir\/$pwd_file") { open (READ, "$data_dir\/$pwd_file") || &error('エラー', "管理者用パスワードファイルが開けません。"); $master = ; close(READ); chop($master) if $master =~ /\n/; if ($master =~ /^\$1\$/) { $salt = 3; } else { $salt = 0; } if (crypt($in{'password'},substr($master,$salt,2)) ne $master) { &error('エラー', "パスワードが一致しません。"); } } } } sub setpwd_form { print "Content-type: text/html\n\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; print "$body\n"; print "

管理者パスワードの設定

\n"; print "
\n"; print "\n"; print "\n"; if (!-z "$data_dir\/$pwd_file") { print "現在のパスワード
\n"; } print "新しいパスワード
\n"; print "新しいパスワード (確認のため再度入力)

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


\n"; if (!-z "$data_dir\/$pwd_file") { print "[戻る]

\n"; } print "\n"; } sub setpwd { if (!-z "$data_dir\/$pwd_file") { open (READ, "$data_dir\/$pwd_file") || &error('エラー', "管理者用パスワードファイルが開けません。"); $master = ; close(READ); chop($master) if $master =~ /\n/; if ($master =~ /^\$1\$/) { $salt = 3; } else { $salt = 0; } if (crypt($in{'old_password'},substr($master,$salt,2)) ne $master) { &error('エラー', "パスワードが一致しません。"); } } if (length($in{'new_password'}) < 6 || $in{'new_password'} eq '') { &error('エラー', "6文字以上のパスワードを指定してください。"); } if ($in{'new_password'} ne $in{'retype_password'}) { &error('エラー', "パスワードが一致しません。"); } ($pwd) = &MakeCrypt($in{'new_password'}); open (WRITE,"> $data_dir\/$pwd_file") || &error('エラー', "管理者用パスワードファイルに書き込めません。"); print WRITE $pwd; close(WRITE); } sub MakeCrypt { local($plain) = @_; local(@char,$f,$now,@saltset,$pert1,$pert2,$nsalt,$salt); @saltset = ('a'..'z','A'..'Z','0'..'9','.','/'); $now = time; srand(time|$$); $f = splice(@saltset,rand(@saltset),1) . splice(@saltset,rand(@saltset),1); ($pert1,$pert2) = unpack("C2",$f); $week = $now / (60*60*24*7) + $pert1 + $pert2 - length($plain); $nsalt = $saltset[$week % 64] . $saltset[$now % 64]; $result = crypt($plain,$nsalt); if ($result =~ /^\$1\$/) { $salt = 3; } else { $salt = 0; } if (crypt($plain,substr($result,$salt,2)) ne $result) { &error('エラー', "パスワードの暗号化に失敗しました。戻って再度実行してください。"); } return ($result,$salt); } sub decode { if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/, $buffer); foreach (@pairs) { ($name,$value) = split(/=/); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; &jcode'convert(*value, "sjis", "", "z"); if ($tagkey) { $value =~ s/<>/<>/g; } else { $value =~ s//>/g; } $value =~ s/\r//g; $value =~ s/\n//g; $in{$name} = $value; } } sub error { if (-e "$data_dir\/$tmp_file") { unlink("$data_dir\/$tmp_file"); } print "Content-type: text/html\n\n"; print "$title\n"; print "$body\n"; print "

$_[0]

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



\n"; print "[ 戻る ]

\n"; print "\n"; exit; } sub referror { print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "403 Forbidden\n"; print "\n"; print "

Forbidden

\n"; print "You don't have permission to access the file on this server.

\n"; print "


\n"; print "\n"; exit; }