PHPで地図で指定した場所の週間カレンダーを表示

(1/1)
PHPで地図で指定した場所の天気予報を求める」でつくったプログラムをベースに、「PHPで祝日を求める」「PHPで二十四節気一覧を作成」「PHPで日出没・月出没・月齢を計算」「PHPで3ヶ月カレンダーを作る」「PHPで月の満ち欠けを描画」を加え、地図で指定した地点の週間カレンダーを表示するPHPプログラムをつくる。

(2022年5月28日)雑節(彼岸,社日,八十八夜,入梅,二百十日,二百二十日)を追加,2033年(令和15年)問題解決案を追加
(2022年3月19日)Leafletでマップ移動時に緯度・経度を拾わない不具合を修正した。
(2022年3月12日)気象庁防災情報XMLのhttps化に対応。クラスファイル "pahooWeather.php" のみ入れ換え必要。キャッシュディレクトリ(定数 DIR_CACHE で指定するもの)は、ディレクトリごと消去してから新しプログラムを起動すること。また、予報地点ファイル(定数 FILE_JMASPOTS で指定するもの)を更新したので差し替えてほしい。

サンプル・プログラムの実行例

PHPで地図で指定した場所の週間カレンダーを表示
Googleマップ表示

目次

サンプル・プログラム

圧縮ファイルの内容
weeklyCalendar.phpサンプル・プログラム本体
pahooGeoCode.php住所・緯度・経度に関わるクラス pahooGeoCode。
使い方は「PHPで住所・ランドマークから最寄り駅を求める」などを参照。include_path が通ったディレクトリに配置すること。
pahooWeather.php気象情報に関わるクラス pahooWeather。
気象情報に関わるクラスの使い方は「PHPで天気予報を求める」を参照。include_path が通ったディレクトリに配置すること。
pahooCalendar.php暦計算クラス pahooCalendar。
暦計算クラスの使い方は「PHPで日出没・月出没・月齢・潮を計算」を参照。include_path が通ったディレクトリに配置すること。
pahooCache.phpキャッシュ処理に関わるクラス pahooCache。
キャッシュ処理に関わるクラスの使い方は「PHPで天気予報を求める」を参照。include_path が通ったディレクトリに配置すること。
jmaweatherspots.xml予報地点情報ファイル。「PHPで天気予報を求める」参照。
jmaWeatherInit.php予報地点情報ファイル作成プログラム。「PHPで天気予報を求める」参照。

準備:pahooGeoCode クラス

0037: class pahooGeoCode {
0038:     var $items;      //検索結果格納用
0039:     var $error;      //エラーフラグ
0040:     var $hits;       //検索ヒット件数
0041:     var $webapi; //直前に呼び出したWebAPI URL
0042: 
0043:     //Google Cloud Platform APIキー
0044:     //https://cloud.google.com/maps-platform/
0045:     //※Google Maps APIを利用しないのなら登録不要
0046:     var $GOOGLE_API_KEY_1 = '**************************';   //HTTPリファラ用
0047:     var $GOOGLE_API_KEY_2 = '**************************';   //IP制限用
0048: 
0049:     //Yahoo! JAPAN Webサービス アプリケーションID
0050:     //https://e.developer.yahoo.co.jp/register
0051:     //※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
0052:     var $YAHOO_APPLICATION_ID = '*****************************';

地図サービスを利用するために、クラスファイル "pahooGeoCode.php" を使用する。組み込み関数  require_once  を使って読めるディレクトリに配置する。ディレクトリは、設定ファイル php.ini に記述されているオプション設定 include_path に設定しておく。
クラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。

地図や住所検索として Google を利用するのであれば、Google Cloud Platform APIキー が必要で、その入手方法は「Google Cloud Platform - WebAPIの登録方法」を、Yahoo!JAPAN を利用するのであれば、Yahoo! JAPAN Webサービス アプリケーションIDが必要で、その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を、それぞれ参照されたい。

準備:地図サービスの選択

0048: //地図描画サービスの選択
0049: //    0:Google
0050: //    2:地理院地図・OSM
0051: define('MAPSERVICE', 2);
0052: 
0053: //住所検索サービスの選択
0054: //    0:Google
0055: //    1:Yahoo!JAPAN
0056: //   11:HeartRails Geo API
0057: //   12:OSM Nominatim Search API
0058: define('GEOSERVICE', 1);
0059: 
0060: //逆ジオコーディングサービスの選択
0061: //    0:Google
0062: //    1:Yahoo!JAPAN
0063: //   11:HeartRails Geo API
0064: //   21:簡易ジオコーディングサービス
0065: define('REVGEOSERVICE', 21);

表示する地図は、Googleマップ地理院地図・オープンストリートマップ(OSM)から選べる。あらかじめ、定数 MAPSERVIC に値を設定すること。
住所検索サービスは、GoogleYahoo!JAPANHeartRails Geo APIOSM Nominatim Search API から選べる。あらかじめ、定数 GEOSERVICE に値を設定すること。
逆ジオコーディングサービスは、GoogleYahoo!JAPANHeartRails Geo API簡易ジオコーディングサービスから選べる。あらかじめ、定数 REVGEOSERVICE に値を設定すること。
PHPで地図で指定した場所の天気予報を求める
地理院地図表示
PHPで地図で指定した場所の天気予報を求める
オープンストリートマップ表示

準備:キャッシュ・システム

0083: //キャッシュ保持時間(分) 0:キャッシュしない
0084: //気象庁へのアクセス負荷軽減のため,60分以上のキャッシュ保持をお勧めします.
0085: define('LIFE_CACHE', 120);
0086: 
0087: //キャッシュ・ディレクトリ
0088: //書き込み可能で,外部からアクセスされないディレクトリを指定してください.
0089: //最大150Mバイトを消費します.天気予報系プログラムは同じディレクトリで構わない.
0090: define('DIR_CACHE', './pcache/');

気象庁サイトへ負荷をかけないよう、キャッシュ・クラス pahooCache を導入した。使用方法については、「PHPで天気予報を求める - キャッシュ・システム」を参照いただきたい。
キャッシュ保持時間、キャッシュ・ディレクトリともに、自サイトの環境に応じて変更してほしい。天気予報系プログラム(「PHPで天気予報を求める」「PHPで地図で指定した場所の天気予報を求める」「PHPで地図で指定した場所の週間カレンダーを表示」)は全て同じディレクトリを指定することで、気象庁サイトへのアクセス回数がさらに減少する。

解説:カレンダー作成

0287: /**
0288:  * カレンダー情報を追加する
0289:  * @param   object $pcl   pahooCalendarオブジェクト
0290:  * @param   array  $spot  場所情報
0291:  * @param   array  $items カレンダー情報配列
0292:  * @return  なし
0293: */
0294: function addWeeklyCalendar($pcl$spot, &$items) {
0295:     //雑節テーブル
0296:     $table_za = array('春社', '秋社', '八十八夜', '入梅', '二百十日', '二百二十日');
0297: 
0298:     $longitude = $spot['longitude'];
0299:     $latitude  = $spot['latitude'];
0300:     $height    = $spot['height'];
0301:     $year  = date('Y');
0302:     $month = 0;
0303:     $yy = ($items[0]['month'] <= 2) ? $year - 1 : $year;
0304: 
0305:     //彼岸
0306:     $higan = $pcl->getHigan($year);
0307:     //雑節
0308:     $zassetsu = $pcl->getZassetsu($year);
0309:     ////旧暦計算用テーブル準備
0310:     $pcl->makeLunarCalendar($yyRESOLVE2033);
0311: 
0312:     foreach ($items as $i=>$item) {
0313:         if (is_numeric($i)) {
0314:             //翌年
0315:             if ($month > $items[$i]['month']) {
0316:                 $year++;
0317:                 $month = $items[$i]['month'];
0318:                 //彼岸
0319:                 $higan = $pcl->getHigan($year);
0320:                 //雑節
0321:                 $zassetsu = $pcl->getZassetsu($year);
0322:             } else if ($month < $items[$i]['month']) {
0323:                 $month = $items[$i]['month'];
0324:             }
0325:             $day = $items[$i]['day'];
0326:             $items[$i]['year'] = $year;
0327: 
0328:             //日出没・月出没・月齢・距離
0329:             $sunrise = $pcl->sun_time(0, $longitude$latitude$height$year$month$day);
0330:             $items[$i]['sunrise'] = $pcl->day2hhmm($sunrise);
0331:             $sunset = $pcl->sun_time(1, $longitude$latitude$height$year$month$day);
0332:             $items[$i]['sunset'] = $pcl->day2hhmm($sunset);
0333:             $moonrise = $pcl->moon_time(0, $longitude$latitude$height$year$month$day);
0334:             $items[$i]['moonrise'] = ($moonrise == FALSE) ? '---' : $pcl->day2hhmm($moonrise);
0335:             $moonset = $pcl->moon_time(1, $longitude$latitude$height$year$month$day);
0336:             $items[$i]['moonset'] = ($moonset == FALSE) ? '---' : $pcl->day2hhmm($moonset);
0337:             $items[$i]['moonage'] = $pcl->moon_age($year$month$day, 21 - UTCDIFF, 0, 0);
0338:             $items[$i]['moondist'] = sprintf('%4.3f', $pcl->distance_moon($year$month$day, 12, 0, 0));
0339: 
0340:             //潮
0341:             $moonmeridian = $pcl->moon_time(2, $longitude$latitude$height$year$month$day);
0342:             $moonmeridian = ($moonmeridian == FALSE) ? '---' : $pcl->day2hhmm($moonmeridian);
0343:             $items[$i]['tide'] = (preg_match('/([0-9]+)\:([0-9]+)/', $moonmeridian$arr) > 0) ? $pcl->tide($year$month$day$arr[1]$arr[2], 0)  : '';
0344: 
0345:             //二十四節気
0346:             $items[$i]['solarterm24'] = $pcl->getSolarTerm($year$month$day);
0347: 
0348:             //七十二候
0349:             $items[$i]['solarterm72'] = $pcl->getSolarTerm72($year$month$day);
0350: 
0351:             //土用
0352:             list($ss1$ss2) = $pcl->isDoyo($year$month$day);
0353:             if ($ss2 == '明け') {
0354:                 $ss2 = '';
0355:             } else if (($ss1 != '') && ($ss2 == '')) {
0356:                 $ss2 = '';
0357:             }
0358:             if ($ss1 != '' && $ss2 != '') {
0359:                 $ss2 = '土用の' . $ss2;
0360:             }
0361:             $items[$i]['doyo'] = $ss2;
0362: 
0363:             //彼岸
0364:             if (($higan[0]['in']['month'] == $month) && ($higan[0]['in']['day'] == $day)) {
0365:                 $solarterm = '彼岸入り';
0366:                 $ss2 = '彼岸入り' . $ss2;
0367:             } else if (($higan[0]['out']['month'] == $month) && ($higan[0]['out']['day'] == $day)) {
0368:                 $solarterm = '彼岸明け';
0369:                 $ss2 = '彼岸明け' . $ss2;
0370:             } else if (($higan[1]['in']['month'] == $month) && ($higan[1]['in']['day'] == $day)) {
0371:                 $solarterm = '彼岸入り';
0372:                 $ss2 = '彼岸入り' . $ss2;
0373:             } else if (($higan[1]['out']['month'] == $month) && ($higan[1]['out']['day'] == $day)) {
0374:                 $solarterm = '彼岸明け';
0375:                 $ss2 = '彼岸明け' . $ss2;
0376:             }
0377:             //雑節
0378:             foreach ($table_za as $label) {
0379:                 if (($zassetsu[$label]['month'] == $month) && ($zassetsu[$label]['day'] == $day)) {
0380:                     $solarterm = $label;
0381:                     $ss2 = $label . $ss2;
0382:                 }
0383:             }
0384: 
0385:             //祝日
0386:             $holiday = $pcl->getHoliday($year$month$day, 'jp');
0387:             $items[$i]['holiday'] = ($holiday == FALSE) ? '' : $holiday;
0388: 
0389:             //旧暦
0390:             list($oldmonth$oldday$oldleap) = $pcl->Gregorian2Lunar($year$month$day);
0391:             $oldleap = $oldleap ? '' : '';
0392:             $items[$i]['oldcal'] = sprintf('%s%d月%d日', $oldleap$oldmonth$oldday);
0393:             $items[$i]['rokuyou'] = $pcl->rokuyou($oldmonth$oldday);
0394: 
0395:             //日の干支
0396:             $items[$i]['eto'] = $pcl->eto_day($year$month$day);
0397:         }
0398:     }
0399: }

ユーザー関数 addWeeklyCalendar は、天気予報によって取得した年月日に基づき、カレンダーの計算を行う。
具体的には、毎日の天気予報情報を格納した配列 $items に対して、日出没・月出没・月齢、二十四節気、七十二候、土用、祝日、旧暦の順にデータを追加していく。

グレゴリオ暦から旧暦を求める手順は、「PHPで3ヶ月カレンダーを作る」で紹介している。

解説:表示とURLパラメータ

0583: //パラメータ
0584: $id        = (int)getParam('id',          FALSE, 0);            //表示モード
0585: $query     = (string)getParam('query',    TRUE,  '');          //地図検索キー
0586: $latitude  = (float)getParam('latitude',  FALSEDEF_LATITUDE); //緯度
0587: $longitude = (float)getParam('longitude', FALSEDEF_LONGITUDE);    //経度
0588: $zoom      = (int)getParam('zoom',        FALSEDEF_ZOOM);     //ズーム
0589: $type      = (string)getParam('type',     FALSEDEF_TYPE);     //マップタイプ
0590: $category  = (string)getParam('category', FALSE, 'address');   //カテゴリ
0591: $outenc    = (string)getParam('charset',  FALSEINTERNAL_ENCODING);

URLパラメータを使って
weeklyCalendar?id=1&query=%E6%9C%AD%E5%B9%8C%E5%B8%82
のようにすることで、query をキーワードにして検索した地点のカレンダーのみを表示させることができる。つまり、このスクリプトをホームページやブログの一部として組み込むことで、週間天気予報を表示するパーツになる。
query はUTF-8をURLエンコードしたもの。Yahoo!JAPAN住所検索を使う場合は、category をあわせて指定すること。
また、出力はHTML文のみとなり、スタイルシートは本体ページの方で用意していただきたい。必要なclassは次の通り。

0133: <style>
0134: /* カレンダー:キャプション */
0135: h3.caption {
0136:     width: {$width}px;
0137:     font-size: 140%;
0138:     text-align: center;
0139: }
0140: /* カレンダー */
0141: table.DailyCalendar {
0142:     table-layout: fixed;
0143:     width: {$width}px;
0144:     border: solid 1px gray;
0145:     border-collapse: collapse;
0146:     margin-top:10px;
0147: }
0148: /* カレンダー:日付表示 */
0149: td.label1 {
0150:     border:solid 1px gray;
0151:     border-collapse: collapse;
0152:     padding: 4px;
0153:     white-space: nowrap;
0154:     font-size: 120%;
0155:     text-align:center;
0156:     color: white;
0157:     background-color: dimgray;
0158: }
0159: /* カレンダー:旧暦表示 */
0160: span.oldcal {
0161:     font-size: 80%;
0162: }
0163: /* カレンダー:ラベル表示 */
0164: td.label3 {
0165:     width: {$width3}px;
0166:     border:solid 1px gray;
0167:     border-collapse: collapse;
0168:     padding: 4px;
0169:     white-space: nowrap;
0170:     font-size: 100%;
0171:     text-align: center;
0172:     background-color: gainsboro;
0173: }
0174: /* カレンダー:データ表示 */
0175: td.data3 {
0176:     width: {$width3}px;
0177:     border:solid 1px gray;
0178:     border-collapse: collapse;
0179:     padding: 4px;
0180:     white-space: nowrap;
0181:     font-size: 100%;
0182:     text-align: center;
0183: }
0184: /* カレンダー:データ表示(小さい文字) */
0185: td.data4 {
0186:     width: {$width3}px;
0187:     border:solid 1px gray;
0188:     border-collapse: collapse;
0189:     padding: 4px;
0190:     white-space: nowrap;
0191:     font-size: 70%;
0192:     text-align: center;
0193: }
0194: /* 月の満ち欠け画像 */
0195: img.moonage {
0196:     width:  {$width9}px;
0197:     height: {$width9}px;
0198:     padding: 5px;
0199: }
0200: /* 天気予報表:予報アイコン */
0201: img.wicon {
0202:     width: 60px;
0203: }
0204: </style>

また、親となるホームページやブログの文字コードセットにあわせ、charset 変数で出力文字コードを変更できるようにした。たとえば
weeklyCalendar?id=1&query=%E6%9C%AD%E5%B9%8C%E5%B8%82&charset=SJIS
とすると、シフトJISで出力することができる。
緯度・経度を直接、URLパラメータに渡すこともできる。
weeklyCalendar?id=1&latitude=26.591&longitude=127.977
のようにすることで、北緯26.591度、東経127.977度のカレンダーのみを表示させることができる。

参考サイト

(この項おわり)
header