#! /usr/local/bin/perl # ↑この値は設置するサーバに合わせて設定してください。 ######################################################################################################### # # 簡易予約システム YoYacker Vers.1.11 {FREESOFT} "yoyaku.cgi" # Copyright(c)2020 by CGI-RESCUE http://www.rescue.ne.jp/ # # フリーソフトですが利用規定を守ってご利用ください → http://www.rescue.ne.jp/cgi/kitei.shtml # # {履歴} # 2002.06.27 v1.00 リリース # 2002.07.29 v1.01 時間が重なっているのにエラー処理が出来ていなかったバグの修正 # 2019.12.21 v1.10 セキュリティ上の問題を修正 # 2020.10.01 v1.11 バグの修正 他 # ######################################################################################################### #------------------------------------------ # 配置例 < >内はパーミッション値の参考値 # # yoyaku/ # |--DATA/ <777> # |- yoyaku.cgi <755> # |- jcode.pl <644> #------------------------------------------ #配置したアドレス $address = 'http://設置した場所/yoyaku/yoyaku.cgi'; #データ記録用フォルダ (このフォルダのパーミッションを777相当値に設定してください) $DATA = './DATA/'; #タイトル $title = '簡易予約システム'; #会議室のIDを設定 (任意の半角文字列で自由に指定してください) @HEYA = ("1F-A","1F-B","2F-A","2F-B","2F-C","2F-D"); #会議室のIDに対応する名称を設定 @HEYA_NAME = ("応接室","会議室","映写室1","映写室2","映写室3","映写室4"); #日本語コード変換ライブラリを読み込む require './jcode.pl'; #--------------------------------------------------------------------------------------------------------- $ext = '.cgi'; #入力 read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); #if ($ENV{'QUERY_STRING'} ne '') { $buffer .= "\&$ENV{'QUERY_STRING'}"; } #入力の解析 @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($key,$val) = split(/=/,$pair); $val =~ tr/+/ /; $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; #シフトJIS変換 &jcode'convert(*val,'sjis'); $val =~ s///g; $val =~ s/\.\.//g; $val =~ s/\///g; $val =~ s/\n//g; $val =~ s/\t//g; #連想配列へ格納 $in{$key} .= "\0" if (defined($in{$key})); $in{$key} .= $val; } #時刻取得 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); #初期設定 @wday_array = ('日','月','火','水','木','金','土'); $days[4] = $days[6] = $days[9] = $days[11] = 30; $days[1] = $days[3] = $days[5] = $days[7] = $days[8] = $days[10] = $days[12] = 31; #削除処理 if ($in{'action'} eq "delete") { if ($in{'DEL'} eq "") { &error2("何もチェックされていません。"); } foreach $target (split("\0",$in{'DEL'})) { #予約ファイルを読み出す $target =~ s/,/\//g; if (! open(FILE,"$DATA$target$ext") ) { &error("$!"); } while () { s/\n//g; ($key,$val) = split(/\t/,$_,2); if ($key eq "pwd") { $PWD = $val; last; } } close(FILE); if ($in{'pwd'} eq $PWD) { push(@UNLINK,"$DATA$target$ext"); } else { push(@NG,1); } } $ok = unlink @UNLINK; $ng = @NG; if ($ng) { $error = "$ng件の削除に失敗しました。"; } &error("$ok件の予\約削除に成功しました。$error"); } #予約記録処理 elsif ($in{'action'} eq "yoyaku") { &c($in{'yyear'},1970,9999); &c($in{'ymonth'},1,12); &c($in{'yday'},1,31); if ($in{'yheya'} =~ /^(\.\.)/) { &error2("不正な文字列があります($in{'yheya'})"); } #うるう年の判定 $days[2] = 28; unless ($in{'yyear'} % 4) { $days[2] = 29; } unless ($in{'yyear'} % 100) { $days[2] = 28; } unless ($in{'yyear'} % 400) { $days[2] = 29; } #日数判定 if ($in{'yday'} > $days[$in{'ymonth'}]) { &error2("$in{'yyear'}年の$in{'ymonth'}月は$days[$in{'ymonth'}]日までです。"); } if ($in{'uname'} eq "") { &error2("名前を書いてください。"); } if ($in{'pwd'} =~ /^$|\W/) { &error2("パスワードは半角英数字で。"); } #時分から4桁の数字を形成 $FROM = $in{'from_hour'} . $in{'from_min'}; $TO = $in{'to_hour'} . $in{'to_min'}; if ($FROM >= $TO) { &error2("開始時刻と終了時刻が逆か同じです。"); } #--------------------------------------------------------------------------------------------------------- #予約データ(予約開始時刻)の取得 opendir(DIR,"$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/"); @BASE3 = readdir(DIR); close(DIR); foreach $file (@BASE3) { $END = ""; if ($file !~ /^(\d\d\d\d)/) { next; } ($FILE,$v) = split(/\./,$file,2); #予約ファイルを読み出す open(FILE,"$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/$file"); while () { s/\n//g; ($key,$val) = split(/\t/,$_,2); if ($key eq "end") { $END = $val; last; } } close(FILE); #予約単位である10分毎に使用中時刻をマークする foreach $a ($FILE .. $END) { if ($a % 10) { next; } if (substr($a,-2,2) >= 60 && substr($a,-2,2) <= 90) { next; } # 60進数なので… $a = sprintf("%04d",$a); # 4桁形成 $RESV{$a} = 1; # 時間が埋まっているというマークつける } } #予約しようとする時間域のマークをチェックする for ($a = $FROM; $a <= $TO; $a = $a + 10) { $a = sprintf("%04d",$a); if ($RESV{$a}) { &error2("予\約時間に重なっています。"); } } #--------------------------------------------------------------------------------------------------------- if (!-e "$DATA") { &error("データフォルダがありません。"); } #マスク値 umask(000); #予約する部屋のデータ域を作成 if (!-e "$DATA$in{'yheya'}/") { if (! mkdir("$DATA$in{'yheya'}/",777)) { &error("$in{'yheya'}が作成できませんでした。"); } chmod(0777,"$DATA$in{'yheya'}/"); } #部屋のデータ域の中に予約する日のデータ域を作成 if (!-e "$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/") { if (! mkdir("$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/",777)) { &error("$in{'yyear'}$in{'ymonth'}$in{'yday'}が作成できませんでした。"); } chmod(0777,"$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/"); } #予約開始時間を名前とした予約データの作成 if (! open(OUT,"> $DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/$FROM$ext")) { &error("$FROMが作成できません。"); } print OUT "end\t$TO\n"; print OUT "admin\t$in{'uname'}\n"; print OUT "pwd\t$in{'pwd'}\n"; print OUT "rem\t$in{'rem'}\n"; close(OUT); chmod(0666,"$DATA$in{'yheya'}/$in{'yyear'}$in{'ymonth'}$in{'yday'}/$FROM$ext"); # &error("$in{'yyear'}年$in{'ymonth'}月$in{'yday'}日に$in{'yheya'}を # $FROM〜$TOまで予\約しました。[確認する]"); $jump = $in{'yday'} + 0; print "Location: $address#$jump\n\n"; exit; } elsif ($in{'year'} ne "" && $in{'month'} ne "") { # 指定のカレンダー年月指定 $lyear = $in{'year'}; $lmonth = $in{'month'}; } else { # デフォルトのカレンダー年月指定(今月) ($lsec,$lmin,$lhour,$lmday,$lmon,$lyear,$lwday,$lyday,$lisdst) = localtime(time); $lyear += 1900; $lmonth = $lmon + 1; } #カレンダー表示へ &LIST($lyear,$lmonth); sub LIST { local ($nyear,$nmonth) = @_; if ($nyear == 0 || $nmonth == 0) { &error("ERROR"); } ($wday) = &getwday($nyear,$nmonth,1); # 曜日判定 #桁数形成 if ($nmonth < 10) { $nmonth = "0$nmonth"; } #予約データ(部屋)の取得 if (!opendir(DIR,"$DATA")) { &error("ERROR $!"); } @BASE1 = readdir(DIR); close(DIR); foreach $dir (@BASE1) { if ($dir =~/\./) { next; } #予約データ(日付)の取得 opendir(DIR,"$DATA$dir/"); @BASE2 = readdir(DIR); close(DIR); foreach $dir2 (@BASE2) { if ($dir2 =~ /^($nyear$nmonth\d\d)$/) { #予約データ(予約開始時刻)の取得 opendir(DIR,"$DATA$dir/$dir2/"); @BASE3 = readdir(DIR); close(DIR); foreach $file (@BASE3) { if ($file !~/^\d\d\d\d$ext$/) { next; } ($file,$d) = split(/$ext/,$file,2); #その日のその会議室の全予約開始時刻の取得 $YS{$dir}{$dir2} .= "\0" if (defined($YS{$dir}{$dir2})); $YS{$dir}{$dir2} .= $file; } } } } print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "

$title

\n"; # タイトル表示 $now_year = $year + 1900; $next_year = $now_year + 1; print <<"EOF";
予\約する日

分から 分まで
会議室名

予\約者
パスワード
備考

※ 開始時刻と終了時刻は重なることは出来ません.

EOF $time = time; print "
[最新の状態]
\n"; print "
\n"; $next_y = $lyear; $next_m = $lmonth + 1; if ($next_m > 12) { $next_y++; $next_m = 1; } print <<"EOF";
予\約カンレンダー $nyear年$nmonth月
EOF print "\n"; print "\n"; print "\n"; foreach $n (0 .. $#HEYA) { print "\n"; } print "\n"; #カレンダー表示 foreach $nday (1 .. $days[$lmonth]) { if ($nyear == $year + 1900 && $nmonth == $mon + 1 && $nday == $mday) { $COLOR = "#ffffdd"; } # 今日の色 elsif ($wday == 0) { $COLOR = "#ffdddd"; } # 日曜日の色 elsif ($wday == 6) { $COLOR = "#ddddff"; } # 土曜日の色 else { $COLOR = "#dddddd"; } # その他 print "\n"; print "\n"; foreach $n (0 .. $#HEYA) { print "\n"; } print "\n"; #次の日 $wday++; if ($wday > 6) { $wday = 0; } } print "
 $HEYA_NAME[$n]
$nday日($wday_array[$wday])"; $jikan = sprintf("%04d%02d%02d",$nyear,$nmonth,$nday); foreach $file (sort split("\0",$YS{$HEYA[$n]}{$jikan})) { #予約ファイルを読み出す open(FILE,"$DATA$HEYA[$n]/$jikan/$file$ext"); undef %FILE; while () { s/\n//g; ($key,$val) = split(/\t/,$_,2); $FILE{$key} = $val; } close(FILE); $file2 = $file; $end2 = $FILE{'end'}; 1 while $file2 =~ s/(\d\d)(\d\d)/$1:$2/g; 1 while $end2 =~ s/(\d\d)(\d\d)/$1:$2/g; if ($FILE{'rem'} ne "") { $rem = "\n
[備考] $FILE{'rem'}"; } else { $rem = ""; } print "$file2〜$end2
\n[予\約者] $FILE{'admin'}$rem

\n"; } print " 

\n"; print <<"EOF"; 削除する予\約にチェックしパスワードを指定してボタンを押してください。
パスワード EOF # ↓ この著作表示とリンクを削除すると利用規定違反です。 print <<"EOF";

YoYacker
EOF } exit; sub getwday { # 曜日判定 local ($year,$month,$day) = @_; &c($year,1970,9999); &c($month,1,12); &c($day,1,31); local ($base,$i,$wday); #うるう年の判定 $days[2] = 28; unless ($year % 4) { $days[2] = 29; } unless ($year % 100) { $days[2] = 28; } unless ($year % 400) { $days[2] = 29; } #基本年からの通算日数(該当前年まで) $base = (($year - 1) * 365) + int(($year - 1) / 4) - int(($year - 1) / 100) + int(($year - 1) / 400); #そこへ該当年の日数を加算 $i = $month; while ( --$i ) { $base += $days[$i]; } #1週間7日で除算した余りが曜日 $wday = ($base + $day) % 7; return $wday; } sub c { local ($n,$s,$e) = @_; $n = int($n); if ($n < $s) { &error2("不正な値があります($n)"); } elsif ($n > $e) { &error2("不正な値があります($n)"); } } sub error { local($msg) = @_; print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "\n"; print "

$msg

\n"; print "[再表\示] してください。\n"; print "\n"; exit; } sub error2 { local($msg) = @_; print "Content-type: text/html\n\n"; print "\n"; print "\n"; print "\n"; print "

$msg

\n"; print "前のページに戻ってください。\n"; print "\n"; exit; }