#!/usr/bin/perl # 日付を調べてメッセージを出力 # date_msg.cgi?西暦[0-]&月[1-12]&日[1-31]&期間[1-]&文字コード[sjis|euc]&改行するかどうか[0=no|1=yes]&HTML[html|xhtml]&表示するメッセージ # 指定した年月日とサーバのローカルタイムを比較し, # 等しければメッセージを表示する. # またその年月日 + 期間の間も表示される. # その日だけ表示したいなら期間は1にする. # 年や,月に0が指定されたときは年や月を評価しない. # すなわち年に0が指定された場合,全ての年が該当することになる. # 期間の判定には西暦0年から何日かを調べて比較している. # e.g.(1) date_msg.cgi?2005&1&1&1&sjis&1&html&ほげほげ # ならばサーバの時間が2005年1月1日のときだけ Shift-JIS でほげほげ
と出力される. # e.g.(2) date_msg.cgi?0&12&25&7&euc&1&xhtml&ふがふが # ならばサーバの時間が12月25日〜12月31日の間だけ EUC-JP でふがふが
と出力される. # jcode.pl を使う require 'jcode.pl'; &main; # メイン関数 sub main { # 引数取得 $buf = $ENV{'QUERY_STRING'}; # 引数分解 ($year, $month, $day, $term, $charset, $br, $html, $msg) = split (/&/, $buf); # ヘッダ出力 &print_http_header($charset); # 年が数字であるかチェック # 年が0〜かチェック &check_year ($year); # 月が数字であるかチェック # 月が1〜12かチェック &check_month ($month); # 日が数字であるかチェック # 日が1〜31かチェック &check_day ($day); # ローカルの年月日を取得 &get_localtime (\$local_sec, \$local_min, \$local_hour, \$local_mday, \$local_mon, \$local_year, \$local_wday, \$local_yday, \$local_isdst); # 年が0のときに総日数が正しく計算できるようにするための処理 if ($year == 0) { $year = $local_year; $year_flag = 1; } # 月が0のときに総日数が正しく計算できるようにするための処理 if ($month == 0) { $month = $local_mon; $month_flag = 1; } # 西暦0年から何日目か調べる &get_yday ($year, $month, $day, \$yday, $local_year, \$local_yday); # 年を0に戻す if ($year_flag == 1) { $year = 0; } # 月を0に戻す if ($month_flag == 1) { $month = 0; } # 期間が数字であるかチェック # 数字でなければ0にする &check_term (\$term); # メッセージのチェック # 文字のアンエスケープ,タグ除去処理 &process_msg (\$msg); # 文字コードの変換 &convert_charset ($charset, \$msg); # メッセージの表示 &output_msg ($year, $month, $yday, $term, $local_year, $local_mon, $local_yday, $msg, $html); } # HTTP ヘッダ出力 sub print_http_header { print "Content-type: text/html; "; # EUC が指定されたとき if ($charset eq euc) { print "charset=euc-jp\n\n"; } # Shift-JIS が指定されたとき elsif ($charset eq sjis) { print "charset=shift_jis\n\n"; } # デフォルトは Shift-JIS else { print "charset=shift_jis\n\n"; } } # 年をチェック sub check_year { my ($year) = @_; # 数字ではないか,0より小さいとき if (($year !~ /^\d+$/) || ($year < 0)) { print "Year is invalid."; exit (-1); } } # 月をチェック sub check_month { my ($month) = @_; # 数字ではない or 0より小さい or 12より大きい if (($month !~ /^\d+$/) || ($month < 0) || ($month > 12)) { print "Month is invalid."; exit(-1); } } # 日をチェック sub check_day { my ($day) = @_; # 数字ではない or 1より小さい or 31より大きい if (($day !~ /^\d+$/) || ($day < 1) || ($day > 31)) { print "Day is invalid."; exit(-1); } } # ローカルの時間を取得 sub get_localtime { my ($local_sec, $local_min, $local_hour, $local_mday, $local_mon, $local_year, $local_wday, $local_yday, $local_isdst) = @_; ($$local_sec, $$local_min, $$local_hour, $$local_mday, $$local_mon, $$local_year, $$local_wday, $$local_yday, $$local_isdst) = localtime (time); # 年,月を補正する $$local_year += 1900; $$local_mon++; # $$local_yday に 1 を足す(当日も経過した日として加算する) $$local_yday++; } # 西暦0年からの日数を取得 sub get_yday { my ($year, $month, $day, $yday, $local_year, $local_yday) = @_; my ($i); # $$yday を初期化 $$yday = 0; # $$yday に西暦0年からの年数分の日を加算 for ($i = 1; $i < $year; $i++) { # 閏年を考慮 if ((($i % 4) == 0) && ((($i % 100) != 0) || (($i % 400) == 0))) { $$yday += 366; } else { $$yday += 365; } } # $$yday に月数分の日を加算 for ($i = 1; $i < $month; $i++) { # 1,3,5,7,8,10,12は31日 if (($i == 1) || ($i == 3) || ($i == 5) || ($i == 7) || ($i == 8) || ($i == 10) || ($i ==12)) { $$yday += 31; } # 4,6,9.11は30日 elsif (($i == 4) || ($i == 6) || ($i == 9) || ($i == 11)) { $$yday += 30; } # 2月は閏年チェック elsif ($i == 2) { if ((($year % 4) == 0) && ((($year % 100) != 0) || (($year % 400) == 0))) { $$yday += 29; } else { $$yday += 28; } } } # $$yday に日を加算 $$yday += $day; # $$local_yday は既にその年の分の日は加算されているので # 西暦0年からの日数を加算するだけでよい for ($i = 1; $i < $local_year; $i++) { if ((($i % 4) == 0) && ((($i % 100) != 0) || (($i % 400) == 0))) { $$local_yday += 366; } else { $$local_yday += 365; } } } # 期間をチェック sub check_term { my ($term) = @_; # 数字ではない or 1より小さいとき,期間 $$term は1とする if (($$term !~ /^\d+$/) || ($$term < 1)) { $$term = 1; } } # メッセージの処理 sub process_msg { my ($msg) = @_; my ($text_regrex); my ($msg_output); my ($tag_tmp); my ($text_tmp); # 文字をアンエスケープする $$msg =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg; # ダグ除去処理のために EUC-JP に変換 &jcode::convert (\$$msg, 'euc'); # タグ除去処理 $text_regex = q{[^<]*}; $msg_output = ''; while ($$msg =~ /($text_regex)($tag_regex)?/gso) { last if $1 eq '' and $2 eq ''; $msg_output .= $1; $tag_tmp = $2; if ($tag_tmp =~ /^<(XMP|PLAINTEXT|SCRIPT)(?![0-9A-Za-z])/i) { $$msg =~ /(.*?)(?:<\/$1(?![0-9A-Za-z])$tag_regex_|$)/gsi; ($text_tmp = $1) =~ s//>/g; $msg_output .= $text_tmp; } } $$msg = $msg_output; } # 呼び出し側 HTML の文字コードによって変える sub convert_charset { my ($charset, $msg) = @_; # $msg を EUC-JP に変換する if ($charset eq euc) { &jcode::convert(\$$msg, 'euc'); } # $msg を Shift-JIS に変換する elsif ($charset eq sjis) { &jcode::convert (\$$msg, 'sjis'); } # デフォルトは Shift-JIS else { &jcode::convert (\$$msg, 'sjis'); } } # メッセージの出力 sub output_msg { my ($year, $month, $yday, $term, $local_year, $local_mon, $local_yday, $msg, $html) = @_; # 年が一致するか or 年が0 if (($year == $local_year) || ($year == 0)) { #月が一致するか or 月が0 if (($month == $local_mon) || ($month == 0)) { # 日が期間内に入っているかどうか if (($local_yday >= $yday) && ($local_yday < ($yday + $term))) { print "$msg"; # 改行するかどうか if ($br == 1) { &print_br($html); } } } } } # HTML の改行を出力 sub print_br { my ($html) = @_; # HTML は
if ($html eq html) { print "
"; } # XHTML は
elsif ($html eq xhtml) { print "
"; } # デフォルトは
else { print "
"; } }