#!/usr/local/bin/perl #--------------------------------------# # スケジュール帳 # 2006/05/30 #--------------------------------------# #------------------------------------------# # 設定項目 #------------------------------------------# #このCGI $THIS_URL = "./schedule.cgi"; #ログファイル $LOG_FILE = "./schedule.txt"; #管理者用パスワード $MASTER_KEY = 'aaaa'; #モード設定(誰でも書ける=0,自分しか書かない=1) $ACT_MODE = 1; #ホームURL $HOME_URL = "../../"; #タイトル $TITLE_STR = "スケジュール帳"; #TOPページのタイトル $TOP_PAGE_STR = "スケジュール帳"; #最大登録件数(最大数を越えると古い日付のものから削除されます) $MAX_DATA_SIZE = 4096; #何か月分表示するか $DISP_MONTH_NUM = 10; #最近の日数を何日分にするか $NEAR_DATE = 50; #祝日登録(年月日) 上下ペアになっています。 @HOLIDAY = ( '20060101', '20060109', '20060211', '20060321', '20060429', '20060503', '20060504', '20060505', '20060717', '20060918', '20060923', '20061010', '20061103', '20061123', '20061223'); @HOLIDAY_WHAT = ( '元旦', '成人の日', '建国記念の日', '春分の日', 'みどりの日', '憲法記念日', '国民の休日', 'こどもの日', '海の日', '敬老の日', '秋分の日', '体育の日', '文化の日', '勤労感謝の日', '天皇誕生日'); #ロック用ディレクトリ $LOCKDIR = './lock/'; #クッキーの名前 $COOKIE_NAME = 'schedule'; #クッキーの期限 $COOKIE_LIMIT = 'Thu, 1-Jan-2030 00:00:00 GMT;'; #スタイルシート $STYLEFILE = '../../style.css'; #------------------------------------------# # 設定は以上まで #------------------------------------------# #ver1.0 2006/05/30 公開。 &Main; #------------------------------------------# # メイン #------------------------------------------# sub Main{ #初期化 &Initialize; #ヘッダ &Head; #タイトル print "

$TOP_PAGE_STR

\n"; #各ページへ分岐 if( $in{"page"} eq "schedule" ){ #ナビゲーション &CalNavi; #スケジュールページ &DispCalen( $in{"year"}, $in{"month"} ); } #登録ページ elsif( $in{"page"} eq "regist_page" ){ &RegistPage; } #登録NEXT elsif( $in{"page"} eq "done_regist" ){ &DoneRegistPage; } #記事表示ページ elsif( $in{"page"} eq "look" ){ &LookData( $in{id} ); } #記事削除 elsif( $in{"page"} eq "delete" ){ &DeleteData( $in{id}, $in{password} ); } else{ #ナビゲーション &CalNavi; #スケジュールページ(最近$NEAR_DATE日) &DispCalen( $gl_year, $gl_month, $gl_day, $NEAR_DATE ); } #フッタ &Foot; } #------------------------------------------# # 初期化 #------------------------------------------# sub Initialize{ #フォームデータ取得 &GetFormData; #現在の日時取得 &GetNowDate; #クッキーをセット if( $in{"page"} eq "done_regist" ){ print "Set-Cookie: $COOKIE_NAME=name:$in{name},password:$in{password}; expires=$COOKIE_LIMIT\n"; } #クッキーを取得 &GetCookie; } #------------------------------------------# # ヘッダ #------------------------------------------# sub Head{ print "Content-type: text/html\n"; print "\n"; print "\n\n"; print "$TITLE_STR\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "Home
\n"; } #------------------------------------------# # フッタ #------------------------------------------# sub Foot{ print "\n"; print "\n"; } #------------------------------------------# # 登録ページ #------------------------------------------# sub RegistPage{ print "

登録ページ

\n"; #投稿者情報の入力 &FormUserInfo; } #------------------------------------------# # 投稿者情報の入力 #------------------------------------------# sub FormUserInfo{ #日付情報分解 my $year = substr( $in{date}, 0, 4 ); my $month = substr( $in{date}, 4, 2 ); my $date = substr( $in{date}, 6, 2 ); print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
投稿者:
パスワード:
日時: $year年$month月$date日 "; print "時〜時"; print "
任意コメント:
\n"; #隠し属性 print "\n"; print "\n"; print "\n"; print "

\n"; } #------------------------------------------# # 登録完了ページ #------------------------------------------# sub DoneRegistPage{ $ErrorFlag = 0; #項目チェック if( !$in{name} ){ &RegistError("名前を入力して下さい。"); } if( !$in{password} ){ &RegistError("パスワードを入力して下さい。"); } #自分しか書かない場合 if( $ACT_MODE == 1 ){ #パスワード照合 if( $MASTER_KEY ne $in{password} ){ &RegistError("パスワードが違います。"); } } #エラーがなければログ書き込み開始 if( !$ErrorFlag ){ &WriteLogData; print "登録完了\n"; print "更新\n"; }else{ print "戻って記入し直して下さい。\n"; } } #------------------------------------------# # 登録エラー #------------------------------------------# sub RegistError{ print "$_[0]
\n"; $ErrorFlag = 1; } #------------------------------------------# # ログデータ書き込み #------------------------------------------# sub WriteLogData{ #まずはログファイル読み込み &ReadLogData; #新規ID取得(一番数の大きいもの) my $max = 0; foreach( @LogData ){ my( $id ) = split( /<>/, $_ ); if( $id > $max ){ $max = $id; } } $max++; $myid = $max; #パスワード暗号化 $enckey = &GetEnckey( $in{password} ); #追加ログフォーマット my $push_log = "$myid<>$in{date}<>$in{name}<>$enckey<>$in{open_hour}<>$in{close_hour}<>$in{msg}\n"; $find_flag = 0; #日付でソートされてるので、挿入箇所を探す for( $i = 0; $i < scalar( @LogData ); $i++ ){ #ログ分割 my( $id, $date_str, $name, $password, $mail, $homeurl, $time, $etc2, $etc3, $msg ) = split( /<>/, $LogData[ $i ] ); #$date_strは数値として見れるので、それの大小で判別 #もし大きくなればその手前に挿入 if( $in{date} > $date_str ){ splice( @LogData, $i, 0, $push_log ); $find_flag = 1; last; } } #見つからなかった場合は、最後尾に追加 if( !$find_flag ){ push( @LogData, $push_log ); } #ログ書き込み #ロック my $lflag=0; for( $i = 0; $ i < 10; $i++ ){ #ロック用ディレクトリ作成 if( mkdir( $LOCKDIR, 0755 ) ){ $lflag = 1; last; }else{ #1秒待つ sleep(1); } } if( !$lflag ){ &Error("ロックに失敗。しばらく待ってから再び投稿して下さい。\n
しばらく待っても改善されない時は管理者へ連絡して下さい。"); } #記事数が一定以上を越えると過去ログに。 if( scalar( @LogData ) > $MAX_DATA_SIZE ){ pop( @LogData ); } open( OUT, ">$LOG_FILE" ); print OUT @LogData; close( OUT ); #アンロック rmdir( $LOCKDIR ); } #------------------------------------------# # キーを暗号化して取得 #------------------------------------------# sub GetEnckey{ my $key = $_[0]; #キーを暗号化 my $xx = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./"; my $salt = substr( $xx, int(rand(64)), 1 ); $salt .= substr( $xx, int(rand(64)), 1 ); return crypt( $key, $salt ); } #------------------------------------------# # カレンダーナビゲーション #------------------------------------------# sub CalNavi{ my $month; my $year; my $year_str; #カレンダーナビゲーション printf( "最近%s日\n", $NEAR_DATE ); $year = $gl_year; $pre_year = $year; #前回保持 $month = $gl_month; for( $i = 0; $i < $DISP_MONTH_NUM; $i++){ #年が切り替わった時 if( $pre_year != $year ){ $year_str = "$year年"; }else{ $year_str = ""; } printf(" %s%s月\n", $year, $month, $year_str, $month ); $pre_year = $year; #前回保持 #次の月へ $month++; if( $month > 12 ){ $month = 1; $year++; } } } #------------------------------------------# # フォームデータの受け取り #------------------------------------------# sub GetFormData{ my( $buffer,@pairs ); if( $ENV{REQUEST_METHOD} eq 'POST' ){ read( STDIN, $buffer, $ENV{CONTENT_LENGTH} ); }else{ $buffer = $ENV{QUERY_STRING}; } @pairs = split( /&/, $buffer ); foreach( @pairs ){ my( $name, $value ) = split( /=/, $_ ); #変換 $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; $value =~ s/&/&/g; $value =~ s/"/"/g; $value =~ s//>/g; $value =~ s/\r\n/\n/g; $value =~ s/\n/
/g; #ハッシュに $in{$name} = $value; } } #-----------------------------------------------------# # 現在の日時取得 #-----------------------------------------------------# sub GetNowDate{ #グローバル変数 ( $gl_sec, $gl_min, $gl_hour, $gl_day, $gl_month, $gl_year ) = localtime( time ); $gl_year += 1900; $gl_month++; } #-----------------------------------------------------# # その年と月のカレンダー表示 # @par 2 年 月 #-----------------------------------------------------# sub DispCalen{ my $year = $_[0]; my $month = $_[1]; my $start_date = $_[2]; #表示開始日 my $disp_date_num = $_[3]; #表示日数 my $date; #日 my ( $i, $k, $dates, $day_str, $next_flag ); my @days = ( '日', '月', '火', '水', '木', '金', '土' );#曜日表記 my $day; #曜日 printf( "

%d年%d月

\n", $year, $month ); $day = &GetDayOfWeek( $year, $month, 1 ); #その月の最初の日の曜日 $dates = &GetDaysOfMonth( $year, $month ); #その月の日数 $next_flag = 0; #最近表示の場合 if( $start_date ){ $end_date = $start_date + ($disp_date_num-1); if( $end_date > $dates ){ $end_date = $dates; #繰り越しフラグ $next_flag = 1; } }else{ $start_date = 1; $end_date = $dates; } #ログファイルからデータ取得 &ReadLogData; $day = &GetDayOfWeek( $year, $month, $start_date ); #最初の日の曜日 for ($i = $start_date; $i <= $end_date; $i++) { #月の最終日まで表示 $date = $i; #日にち文字列 $date_str = sprintf( "%04d%02d%02d", $year, $month, $i ); #曜日の色 $day_str = ''; $HOLIDAY_str = ''; #祝日かどうか for( $j = 0; $j < scalar( @HOLIDAY ); $j++ ){ if( $date_str eq $HOLIDAY[ $j ] ){ $day_str = "$days[$day]"; $HOLIDAY_str = "$HOLIDAY_WHAT[ $j ]"; last; } } #祝日でない場合 if( $day_str eq '' ){ if( $day == 0 ){ $day_str = "$days[$day]"; }elsif( $day == 6 ){ $day_str = "$days[$day]"; }else{ $day_str = "$days[$day]"; } } printf("%02d日(%s) %s\n", $date, $day_str, $HOLIDAY_str ); #その日はスケジュール登録あるかチェック &CheckRegist( $date_str ); print "
\n"; #曜日加算 $day = ($day + 1) % 7; } #繰り越しフラグがある場合 if( $next_flag ){ #来月を求める $month++; if( $month > 12 ){ $year++; $month = 1; } #日数を求める $day_num = $disp_date_num - ($dates - $start_date + 1); #サブルーチン呼び出し &DispCalen( $year, $month, 1, $day_num ); } } #-----------------------------------------------------# # ログファイルからデータ取得 #-----------------------------------------------------# sub ReadLogData{ #ログファイルオープン open( IN, $LOG_FILE) or &Error("$LOG_FILEが開けません。\n"); @LogData = ; close( IN ); } #-----------------------------------------------------# # スケジュール登録あるか? # @par 2 年 月 #-----------------------------------------------------# sub CheckRegist{ $in_date = $_[0]; foreach( @LogData ){ my( $id, $date_str, $name, $password, $open_time, $close_time, $msg ) = split(/<>/,$_); #HIT if( $date_str eq $in_date ){ #日時を分解 $year = substr( $date_str, 0, 4 ); $month = substr( $date_str, 4, 2 ); $date = substr( $date_str, 6, 2 ); printf( "
\n %s %s時〜%s時 $msg", $name, $open_time, $close_time ); } } } #-----------------------------------------------------# # 記事表示 # @par 1 ID #-----------------------------------------------------# sub LookData{ $lookId = $_[0]; #ログファイルからデータ取得 &ReadLogData; #ID検索 foreach( @LogData ){ my( $id, $date_str, $name, $password, $open_time, $close_time, $etc2, $etc3, $msg ) = split(/<>/,$_); #HIT if( $id eq $lookId ){ #日時を分解 $year = substr( $date_str, 0, 4 ); $month = substr( $date_str, 4, 2 ); $date = substr( $date_str, 6, 2 ); printf( "%s %s時〜%s時
\n", $name, $open_time, $close_time ); print "
\n"; print "削除キー:\n"; print "\n"; print "\n"; print "\n"; print "
\n"; last; } } } #-----------------------------------------------------# # 記事削除 # @par 2 ID Pass #-----------------------------------------------------# sub DeleteData{ my $myid = $_[0]; my $mypass = $_[1]; #ログファイルからデータ取得 &ReadLogData; #ID検索 for( $i = 0; $i < scalar( @LogData ); $i++ ){ my( $id, $date_str, $name, $password ) = split( /<>/, $LogData[ $i ] ); #HIT if( $id eq $myid ){ #パスワードが正しいかどうか if( $password eq crypt( $mypass, $password ) ){ #削除 splice( @LogData, $i, 1 ); }else{ &Error("パスワードが正しくありません。"); } last; } } #書き込み #ロック my $lflag=0; for( $i = 0; $ i < 10; $i++ ){ #ロック用ディレクトリ作成 if( mkdir( $LOCKDIR, 0755 ) ){ $lflag = 1; last; }else{ #1秒待つ sleep(1); } } if( !$lflag ){ &Error("ロックに失敗。しばらく待ってから再び投稿して下さい。\n
しばらく待っても改善されない時は管理者へ連絡して下さい。"); } open( OUT, ">$LOG_FILE" ); print OUT @LogData; close( OUT ); #アンロック rmdir( $LOCKDIR ); print "削除完了\n"; print "更新\n"; } #-----------------------------------------------------# # エラーを出力して強制終了 # @par 1 出力文字列 #-----------------------------------------------------# sub Error{ print @_; &Foot; exit; } #-----------------------------------------------------# # 西暦年月日からその曜日を算出する # @par 3 年月日 #-----------------------------------------------------# sub GetDayOfWeek{ my( $year, $month, $day ) = @_; if( $month == 1 || $month == 2 ){ $year--; $month += 12; } return( $year + int($year/4) - int($year/100) + int($year/400) + int((13*$month+8)/5) + $day ) % 7; } #-----------------------------------------------------# # 西暦年号と月からその月の日数を算出する # @par 2 年月 #-----------------------------------------------------# sub GetDaysOfMonth{ my( $year, $month ) = @_; my( @days ); @days = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); if ($month < 1 || $month > 12){ $month = 1; } #閏年かどうか if ($month == 2){ return $days[1] + ($year % 4 == 0 && $year % 100 != 0 || $year % 400 == 0); } else{ return $days[$month-1]; } } #-----------------------------------------------------# # クッキーの取得 #-----------------------------------------------------# sub GetCookie{ local( $key, $val ); my @cookies = split( /; /, $ENV{HTTP_COOKIE} ); foreach( @cookies ){ ($key,$val) = split( /=/, $_ ); if( $key eq $COOKIE_NAME ){ @cookies = split(/,/,$val); foreach(@cookies){ ($key,$val) = split(/:/,$_); $val =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("C", hex($1))/eg; $cookie{$key} = $val; } last; } } }