[PHP]カレンダーの作り方
カレンダー表示は、ブログの更新状況から営業・休業スケジュールの表示、予約受付フォームの表示など用途は多く、広く使われています。今回はPHPで、実務でも必要になることが多いカレンダーを作成してみます。
目次
PHPでカレンダーを作る方法
Webプログラムでカレンダーを表示するには、どのような機能が必要となるか洗い出してみます。まずカレンダーは、年と月が特定されて初めて表示できるものです。そこで年と月をブラウザから指定できる構成にします。
またカレンダー上には、第一週や最終週に前月や翌月の日付も表示されるものがあります。今回は、この機能も実装してみます。
1.データ「年、月」を受け取る ・GETリクエストで受け取る 2.データ「年、月」を表示データ「日付リスト」に変換する ・表示データは、曜日ごとのカレンダー形式で表示する ・表示データには、前月の日付、翌月の日付も含める 3.表示データを表示する ・カレンダーは、日曜から表示する ・土曜、日曜、祝祭日で色を変えて表示する
PHPで月の日付の配列を作成する
カレンダー表示で必要となるデータは、カレンダーに表示する「日付リスト」です。これは指定した月については、月の日数が分かれば、求めることが出来ます。また第一週に含まれる前月分の日付リストは、月初1日の曜日から算出できそうです。同様に最終週に含まれる翌月分の日付リストも、月末の曜日から算出できそうです。
<?php
/* タイムゾーンの設定 */
date_default_timezone_set('Asia/Tokyo');
/* GETリクエストから取得 */
function gGET($key,$def=''){ return isset($_GET[$key]) ? $_GET[$key]: $def; }
/* 年の指定 初期値を当年に */
$y = gGET('year',date('Y'));
/* 月の指定 初期値を当月に */
$m = gGET('month',date('m'));
/* 指定年月の月の日数 */
$t1 = date('t',mktime(0,0,0,$m,1,$y));
/* 指定年月の月初曜日 */
$w1 = date('w',mktime(0,0,0,$m,1,$y));
/* 指定年月の前月の日数 */
$t0 = date('t',mktime(0,0,0,$m-1,1,$y));
/* 指定年月の月末曜日 */
$w2 = date('w',mktime(0,0,0,$m,$t1,$y));
PHPでは、date('t')で該当する月の日数を、date('w')で曜日を取得することが出来ます。またdate('フォーマット',Unixタイムスタンプ)で指定した時刻のデータを取得できます。タイムスタンプは、mktime(時間,分,秒,月,日,年)で生成できます。
曜日は0-6の数値になっていて、0が日曜で6が土曜になります。週は7日あり、月初1日の曜日が土曜(6)の時、第一週の前月分の日付は、日曜スタートのカレンダーでは6日あります。日曜(0)の場合は、0日になります。
また前月の月末日が31日だった場合、6日分のリストは、26,27,28,29,30,31になりますが、開始日を求める算出式としては 31-6 +1=26 で1足せば求めることが出来ます。
/* 月の第一週に含まれる前月の開始日を算出 */
$st = $t0-$w1 +1;
/* 前月の第一週分の日付を生成 */
$days = $t0<$st ? array(): range($st,$t0);
/* 指定年月の日付を生成 */
$d1 = range(1,$t1);
/* 月の最終週に含まれる翌月の最終日を算出 */
$end = 7 -($w2+1);
/* 翌月の最終週分の日付を生成 */
$d2 = 0<$end ? range(1,$end): array();
/* 生成した日付を一つの配列に統合 */
$days = array_merge($days,$d1,$d2);
PHPでは、range()で指定した範囲の値の配列を作成できます。最終週に含まれる翌月の日付は、月末の曜日が土曜(6)の時、0日で、日曜(0)の時、6日あります。よって、7 - (曜日+1) で求めることが出来ます。
/* 週7日毎に配列を分ける */
$days = array_chunk($days,7);
日付リストはカレンダー表示の場合、7日毎に分けてあれば表示する際に処理しやすいです。PHPでは、array_chunk()で配列を指定した数に分割できます。
PHPで休日を設定する
祝祭日を算出するアルゴリズムを構築する方法もありますが、今回は休業日などに対応するため、配列に設定するかたちで実装します。
/* 休日を判定する関数 */
function is_holiday($date){
/* 2019年分 */
$set = array(
/* 祝祭日 */
'20190101',
'20190114',
'20190211',
'20190321',
'20190429',
'20190503',
'20190504',
'20190505',
'20190506',
'20190715',
'20190811',
'20190812',
'20190916',
'20190923',
'20191014',
'20191103',
'20191104',
'20191123',
'20191223',
/* 休業日 */
'20190102',
'20191230',
'20191231',
);
return in_array($date,$set);
}
PHPで日付リストをjsonデータとして返す
javascriptで動的に表示を切り替えたい場合は、jsonデータで渡すことになります。PHPでは、json_encode()で配列や連想配列をjson形式に変換することが出来ます。
/* jsonデータを出力する */
header('Content-Type: application/json; charset=utf-8');
echo json_encode($days);
今回は、ブラウザで年月の指定も行いたいため、jsonデータをtextarea内に出力する構成で作成します。土曜は青色、日曜は赤色の文字色にし、前月、翌月の日付は灰色で表示する予定としてcssも作成しています。
/* htmlデータで出力 */
if (gGET('type')=='html') {
/* jsonデータで出力 */
} else {
$html = '<textarea>'. json_encode($days) .'</textarea>';
$r1 = ' checked';
$r2 = '';
}
?>
<title>[PHP]カレンダーを表示</title>
<form>
<input type="number" name="year" min="0" max="3000" value="<?php echo $y; ?>">年
<input type="number" name="month" min="1" max="12" value="<?php echo $m; ?>">月
<label>
<input type="radio" name="type" value="json"<?php echo $r1; ?>>JSONデータ
</label>
<label>
<input type="radio" name="type" value="html"<?php echo $r2; ?>>HTMLデータ
</label>
<input type="submit" value="送信">
</form>
<?php echo $html; ?>
<style>
form,textarea,table {
display: block;
margin: 30px auto;
width: 70%;
}
input {
margin-right: 5px;
padding: 5px;
}
th,td {
text-align: center;
}
.gray {
color: #aaa;
}
.red {
color: #f00;
}
.blue {
color: #00f;
}
</style>
PHPで日付リストをHTMLデータとして返す
最後にHTMLの状態で表示できるようにしてみます。日付リストは、週ごとの配列になっているので、第一週の時に出現した1日を基準として、前月分の日付を判定できます。また最終週に含まれる翌月の日付も1日を基準にして判定可能です。
日付リストの曜日は、週ごとの配列の1番目が日曜で、配列の添字0、最後が土曜で配列の添字は6です。下記のコードでは、foreach()のas $j=>$vで$jが配列の添字、$vが配列の値になっています。
/* htmlデータで出力 */
if (gGET('type')=='html') {
$html = '<table>
<tr>
<th class="red">日</th>
<th>月</th>
<th>火</th>
<th>水</th>
<th>木</th>
<th>金</th>
<th class="blue">土</th>
</tr>';
/* 文字色の初期値を灰色に */
$class = 'gray';
foreach($days as $i=>$week){
$html .= '<tr>';
foreach($week as $j=>$v){
/* 第一週の時 */
if ($i==0) {
/* 日付が1日 */
if ($v==1) {
$class = '';
}
} else {
/* 第二週以降で日付が1日 */
if ($v==1) {
$class = 'gray';
}
}
/* 初期色以外の時 */
if ($class!='gray') {
if ($j==0) {
$class = 'red';
} elseif($j==6) {
$class = 'blue';
} else {
$class = '';
}
}
$html .= '<td'.($class==''?'':' class="'.$class.'"').'>'.$v.'</td>';
}
$html .= '</tr>';
}
$html .= '</table>';
$r1 = '';
$r2 = ' checked';
さらに作成した休日判定の関数を利用すれば、休業日だけ色を変えることも出来ます。注意点として、休日は年月日の8文字で設定したので、利用する場合は、sprintf()などで日付を整形してから引数として渡す必要があります。