PHPセキュリティ対策:定義域エラー

(1/3)
PHP を使い、次の日曜日を求めるというカレンダー計算プログラムを作ってみることにする。
まず、組み込み関数  mktime  や  mktime  を使って作るのだが、数十年以上昔の日付や数十年以上未来の日付を入力すると、必ずエラーが発生する。これは日付関数の定義域エラーによるものだが、このようなエラーはセキュリティ・ホールに繋がる恐れがあるので、何らかの対策を施す必要がある。

サンプル・プログラム:UNIX TIME版

年月日に「2008/08/25」などと入力して、「計算」ボタンをクリックしてみてほしい。
カレンダーと比較して正しい答えが計算されたろうか。

プログラムを実行する

ダウンロード(PHP4/5共用)

サンプル・プログラムの解説:次の日曜日を計算する

ユーザー関数 getNextSunday は、年月日を渡すと、その日から数えて次の日曜日を計算する関数である。
space
仕組みは簡単。
入力された年月日を関数  mktime  で UNIX TIME $thisday に変換する。
mktime は計算に失敗した場合は負数を返すので、$thisday が負数だったらエラーを返す。
space
次に、関数  getdate  を使い、その日の曜日番号を求める。曜日番号は 0=日曜日、1=月曜日‥‥6=土曜日なので、7 から曜日番号を減じた結果を秒数に換算し、$thisday に加えれば、次の日曜日の UNIX TIME を計算することができる。

0013: /**
0014:  * 次の日曜日を求める(UNIX TIMEで計算)
0015:  * @param int $year, $month, $day 基点年月日
0016:  * @return int 次の日曜日(UNIT TIME)/FALSE:定義域エラー
0017: */
0018: function getNextSunday($year$month$day) {
0019:     $thisday = @mktime(0, 0, 0, $month$day$year);
0020:     if ($thisday < 0)   return FALSE;
0021:     $arr = getdate($thisday);
0022:     $ww = $arr['wday'];      //指定日の曜日番号
0023: 
0024:     return $thisday + (7 - $ww) * 24 * 60 * 60;
0025: }

サンプル・プログラムの解説:入力エラーチェック

HTML フォームに入力された年月日を、関数  split  を使って年、月、日に分解する。
ここで分解できなかったり、3 つの数字にならないケースはエラーとして、変数 $msg にエラー・メッセージを設定する。
space
次に、うまく分解できたとしても、2008 年 2 月 31 日のような異常な入力があるかもしれない。そこで、関数  checkdate  を使って年月日の整合性をチェックする。
space
以上のエラーチェックを通過した場合のみ、ユーザー関数 getNextSunday を適用する。
space

0029:     $yyyymmdd = $_GET['yyyymmdd'];
0030:     //年月日に分解
0031:     if (($arr = split('\/', $yyyymmdd)) == FALSE) {
0032:         $msg = 'Error > 入力は 年/月/日 と指定してください';
0033:     } else if (count($arr) != 3) {
0034:         $msg = 'Error > 年、月、日のいずれかが入力されていません';
0035:     } else if (checkdate($arr[1]$arr[2]$arr[0]) == FALSE) {
0036:         $msg = 'Error > 入力した年月日は存在しません';
0037:     //次の日曜日を求める
0038:     } else {
0039:         $sunday = getNextSunday($arr[0]$arr[1]$arr[2]);
0040:         if ($sunday == FALSE) {
0041:             $msg = 'Error > この環境では入力した年月日を計算できません';
0042:         } else {
0043:             $msg = '次の日曜日は ' . date('Y/m/d', $sunday) . ' です';
0044:         }
0045:     }

(この項おわり)
header