2013年2月15日金曜日

PHPでカレンダー

現在、ウチの課にプログラマー歴0年の新人君が入ってきていて、とりあえずPHPで勉強をさせている。
画像掲示板を作ってもらい、一通り理解出来たようなので、次のお題として出したのがカレンダー。

プログラマーならカレンダーを作った事は誰でもあると思う。


で、カレンダーが完成したら、掲示板と連携させて、投稿があった日と連動して、カレンダーにその日の投稿一覧へ飛べるようなものを作ってみっててってお題を出している。

で、新人君が一生懸命作っている間、自分もサンプルで書いてみたので載せておく。


sample.php
1:  <?php  
2:  ## 入力チェック  
3:   $in_get_m     = empty($_GET['m'])?'now':$_GET['m'];  
4:  # とりあえずタイムスタンプ、ここにGETパラメータ経由で日付フォーマットが入ってくる  
5:   $imp_target    = strtotime( $in_get_m );  
6:  # 対象の年取得  
7:   $imp_year     = date('Y', $imp_target);  
8:  # 対象の月取得  
9:   $imp_month     = date('n', $imp_target);  
10:  # その月の末日取得  
11:   $imp_last     = date('t', $imp_target);  
12:  # 対象の1日が何曜日かを取得(=前に空白TDがいくつあるかに等しくなるって事に見てたら気付いたので)  
13:   $imp_prep     = date('w', mktime(0,0,0,$imp_month,1,$imp_year));  
14:  # 1日の前に作るTDタグの数+日数  
15:   $tmp_prep_and_last = $imp_prep + $imp_last;  
16:  # テーブル用TDをいくつ作るのかを算出  
17:   $imp_cells     = ( $tmp_prep_and_last ) + ( 7 - ( $tmp_prep_and_last ) % 7 );  
18:  # 今日の年月日  
19:   $tmp_today     = date('Y-m-d');  
20:  #### 出力用変数の初期化  
21:  # 表示用(年)  
22:   $out_year     = $imp_year;  
23:  # 表示用(月)  
24:   $out_month     = date('m',$imp_target);  
25:  # テーブルを出力する為の情報を格納する変数  
26:   $out_td_data    = array();  
27:  # 次の月の1日  
28:   $out_ymd_next   = date('Ym', strtotime('+1 month', $imp_target) ).'01';  
29:  # 前の月の1日  
30:   $out_ymd_prev   = date('Ym', strtotime('-1 month', $imp_target) ).'01';  
31:  ## ↓ここでは仮にSQLから投稿があった日付を引っ張ってきたと仮定して、こんな感じの配列に整えたものとする  
32:  # $DB = NewAdoConnection( 'postgres' );  
33:  # $DB->Connect(......);  
34:  # $DB->Execute("SET CLIENT_ENCODING TO 'UTF8'");  
35:  # $_RES = $DB->Execute("SELECT DISTINCT ON( reg_date ) reg_date FROM bbs");  
36:  # $arr = $_RES->GetRows();  
37:  # ........ みたいな事をやって整形したものがこれ↓  
38:  # キーが投稿内容がある日付で、値はどのリンクに飛ばすのか  
39:  $list = array(  
40:    '20130211' => 'list.php?d=20130211',  
41:    '20130212' => 'list.php?d=20130212'  
42:  );  
43:  # カレンダー用データ作成  
44:  for( $i=0; $i<$imp_cells; $i++ ){  
45:    # 計算結果がマイナスの間1日の前の状態  
46:     $tmp_j   = $i - $imp_prep;  
47:     $tmp_class = array();  
48:    # データ作成用一時変数を初期化する  
49:     $tmp_data = array(  
50:      'label' => '&nbsp;',  
51:      'class' => $tmp_class  
52:     );  
53:    # 1日から末日までの間行う処理  
54:     if( $tmp_j>=0 && $tmp_j+1<=$imp_last ){  
55:      # 作成中の日付情報のタイムスタンプで初期化しておく  
56:       $tmp_date = mktime(0,0,0,$imp_month,$tmp_j+1,$imp_year);  
57:      # <a href>要素用の変数を初期化する(リンクを張る必要がある時、リンク用のパラメータを代入する)  
58:       $tmp_link = '';  
59:      # 日曜日なら赤  
60:       if( date('w', $tmp_date) == 0 ){  
61:        $tmp_class[] = 'red';  
62:       }  
63:      # 土曜日なら青  
64:       if( date('w', $tmp_date) == 6 ){  
65:        $tmp_class[] = 'blue';  
66:       }  
67:      # 本日に色づけ  
68:       if( date('Y-m-d', $tmp_date) == $tmp_today ){  
69:        $tmp_class[] = 'today';  
70:       }  
71:      # リンクを張るかどうかの判定  
72:       if( in_array( date('Ymd', $tmp_date ), array_keys( $list ) ) ){  
73:        $tmp_link = $list[date('Ymd', $tmp_date)];  
74:       }  
75:      # 日ごとの配列データを一時的に保持する配列型変数  
76:      $tmp_data = array(  
77:        # 日  
78:         'label' => $tmp_j + 1,  
79:        # リンクを張るか。(リンクを張らない場合は空)  
80:         'link' => $tmp_link,  
81:        # クラス属性名  
82:         'class' => $tmp_class  
83:      );  
84:    }  
85:    # 出力用データを貯める  
86:     $out_td_data[] = $tmp_data;  
87:  }  
88:  # テンプレート  
89:   require_once('./calender.html');  
90:  ?>  
きたねえ花火だぜ。。
カレンダーの書き方は人によって違うと思うし、どの方法が正しいかについては言及するつもりもないです。
今回、書いていて気付いたのはdate('w')の戻り値が日曜日を週の始めとしたカレンダーの場合、1日の前に必要な空白のセルに等しいって事。
2013年2月の場合、date('w')の戻り値は5となる。
今回出来るだけシンプルに書こうと思った結果、7で割り切れる数だけ配列データを作成し、それぞれにラベル(何日か)、何曜日なのかなどの情報を含ませるようにし、TDで書き出す形式になった。
これがシンプルかどうかはともかく、分かりやすいと思ったので。
で、実際の計算箇所が16行目の( 5日+28日 ) + ( 7 - ( 5日+28日 ) % 7 )=33日+(7-5)日=33日+2日=35日と言う部分。

あとは出力用のデータを作成し、デザインに流し込んで終了。


calender.html
1:  <html>  
2:  <head>  
3:   <style type="text/css" media="screen">  
4:    .today { background-color : #9999ff; }  
5:    .blue { color : #0000ff; }  
6:    .red  { color : #ff0000; }  
7:    td   { text-align : right; }  
8:   </style>  
9:  </head>  
10:  <body>  
11:   <table border="1">  
12:    <tr>  
13:     <th><a href="?m=<?php echo $out_ymd_prev; ?>">&lt;&lt;</a></th>  
14:     <th colspan="5">  
15:  <?php echo $out_year; ?>年<?php echo $out_month; ?>月  
16:     </th>  
17:     <th><a href="?m=<?php echo $out_ymd_next; ?>">&gt;&gt;</a></th>  
18:    </tr>  
19:    <tr>  
20:     <th class="red">日</th>  
21:     <th>月</th>  
22:     <th>火</th>  
23:     <th>水</th>  
24:     <th>木</th>  
25:     <th>金</th>  
26:     <th class="blue">土</th>  
27:    </tr>  
28:  <?php foreach( $out_td_data as $k => $v ): ?>  
29:  <?php if( $k % 7 == 0 ):     # 7で割り切れる時TR要素 ?>  
30:      <tr>  
31:  <?php endif;           #/7で割り切れる時TR要素 ?>  
32:        <td class="<?php echo implode(' ', $v['class']);?>">  
33:  <?php if( !empty( $v['link'] ) ): # リンクを作成するか ?>  
34:          <a href="<?php echo $v['link']; ?>">  
35:  <?php endif;           #/リンクを作成するか ?>  
36:  <?php echo $v['label']; ?>  
37:  <?php if( !empty( $v['link'] ) ): # リンクを作成するか(閉じタグ) ?>  
38:          </a>  
39:  <?php endif;           #/リンクを作成するか(閉じタグ) ?>  
40:        </td>  
41:  <?php if( ($k+1)%7 == 0 ):    # 7+1で割り切れる時、/TR要素 ?>  
42:      </tr>  
43:  <?php endif;           #/7+1で割り切れる時、/TR要素 ?>  
44:  <?php endforeach; # $out_td_data ?>  
45:   </table>  
46:  </body>  
47:  </html>  

0 件のコメント:

コメントを投稿