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

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

(2023年12月30日)予報地点情報ファイルを更新
(2023年8月27日)予報地点情報ファイルを更新
(2023年8月12日)国土地理院ジオコーディングAPIを利用できるようにした.検索キーの最小・最大長が指定できるようにした.
(2023年3月18日)予報地点情報ファイルを更新
(2023年2月11日)予報地点情報ファイルを更新
(2023年1月15日)太陽、月の位置計算の精度向上,予報地点情報ファイルを更新

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

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

目次

サンプル・プログラム

圧縮ファイルの内容
weeklyCalendar.phpサンプル・プログラム本体
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
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で天気予報を求める」参照。
weeklyCalendar.php 更新履歴
バージョン 更新日 内容
3.2.0 2023/08/12 検索キーの最小・最大長の指定
3.1.0 2023/08/12 国土地理院ジオコーディングAPIを追加
3.0.0 2022/05/28 太陽・月に関わる計算精度向上
2.9 2022/05/28 雑節を追加,2033年問題解決案を追加
2.81 2022/03/19 ヘルプの修正
pahooGeoCode.php 更新履歴
バージョン 更新日 内容
6.3.1 2023/07/09 bug-fix
6.3.0 2023/07/02 getPointsGSI()追加
6.2.0 2023/07/02 ip2address()追加
6.1.0 2022/12/30 ip2address()追加
6.0.4 2022/12/13 PHP8.2対応
pahooWeather.php 更新履歴
バージョン 更新日 内容
5.4.1 2023/08/12 __construct() -- 不具合修正
5.4 2023/02/11 FILE_VERSION = 2.2 に更新
5.3 2022/03/10 気象庁防災情報XMLのhttps化に対応
5.2 2021/04/08 pahoo_simplexml_loadをpahooCache::simplexml_loadへ
5.1 2021/04/02 キャッシュ・システム導入:pahooCacheクラス
pahooCalendar.php 更新履歴
バージョン 更新日 内容
4.3.2 2023/02/11 getSolarTerm72() 表記改訂:水澤腹堅→水沢腹堅
4.3.1 2023/02/03 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候
4.3.0 2023/01/14 コメント表記などを見直した,tenshanichi()追加
4.2.0 2023/01/11 getTimeDifference(),setTimeDifference()追加
4.1.0 2023/01/09 太陽,月の位置計算の基準をUTCに変更した
pahooCache.php 更新履歴
バージョン 更新日 内容
1.1.1 2023/02/11 コメント追記
1.1 2021/04/08 simplexml_load()メソッド追加
1.0 2021/04/02 初版
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.4.1 2023/09/30 コメントの訂正
1.4.0 2023/09/09 $_GET, $_POST参照をfilter_input()関数に置換
1.3.0 2023/07/11 roundFloat() 追加
1.2.0 2023/04/22 exitIfLessVersion() 追加
1.1.2 2023/02/05 validString() 修正

準備:pahooGeoCode クラス

  37: class pahooGeoCode {
  38:     var $items;     //検索結果格納用
  39:     var $error;     //エラー・フラグ
  40:     var $errmsg;    //エラー・メッセージ
  41:     var $hits;      //検索ヒット件数
  42:     var $webapi;    //直前に呼び出したWebAPI URL
  43: 
  44:     //Google Cloud Platform APIキー
  45:     //https://cloud.google.com/maps-platform/
  46:     //※Google Maps APIを利用しないのなら登録不要
  47:     var $GOOGLE_API_KEY_1 = '**************************';   //HTTPリファラ用
  48:     var $GOOGLE_API_KEY_2 = '**************************';   //IP制限用
  49: 
  50:     //Yahoo! JAPAN Webサービス アプリケーションID
  51:     //https://e.developer.yahoo.co.jp/register
  52:     //※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
  53:     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の登録方法」を、それぞれ参照されたい。

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

  63: //地図描画サービスの選択
  64: //    0:Google
  65: //    2:地理院地図・OSM
  66: define('MAPSERVICE', 2);
  67: 
  68: //住所検索サービスの選択
  69: //    0:Google
  70: //    1:Yahoo!JAPAN
  71: //   11:HeartRails Geo API
  72: //   12:OSM Nominatim Search API
  73: //   13:国土地理院ジオコーディングAPI
  74: define('GEOSERVICE', 1);
  75: 
  76: //逆ジオコーディングサービスの選択
  77: //    0:Google
  78: //    1:Yahoo!JAPAN
  79: //   11:HeartRails Geo API
  80: //   21:簡易ジオコーディングサービス
  81: define('REVGEOSERVICE', 1);

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

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

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

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

解説:カレンダー作成

 270: /**
 271:  * カレンダー情報を追加する
 272:  * @param   object $pcl   pahooCalendarオブジェクト
 273:  * @param   array  $spot  場所情報
 274:  * @param   array  $items カレンダー情報配列
 275:  * @return  なし
 276: */
 277: function addWeeklyCalendar($pcl, $spot, &$items) {
 278:     //雑節テーブル
 279:     $table_za = array('春社', '秋社', '八十八夜', '入梅', '二百十日', '二百二十日');
 280: 
 281:     $longitude = $spot['longitude'];
 282:     $latitude  = $spot['latitude'];
 283:     $height    = $spot['height'];
 284:     $year  = date('Y');
 285:     $month = 0;
 286:     $yy = ($items[0]['month'<2? $year - 1 : $year;
 287: 
 288:     //彼岸
 289:     $higan = $pcl->getHigan($year);
 290:     //雑節
 291:     $zassetsu = $pcl->getZassetsu($year);
 292:     ////旧暦計算用テーブル準備
 293:     $pcl->makeLunarCalendar($yy, RESOLVE2033);
 294: 
 295:     foreach ($items as $i=>$item) {
 296:         if (is_numeric($i)) {
 297:             //翌年
 298:             if ($month > $items[$i]['month']) {
 299:                 $year++;
 300:                 $month = $items[$i]['month'];
 301:                 //彼岸
 302:                 $higan = $pcl->getHigan($year);
 303:                 //雑節
 304:                 $zassetsu = $pcl->getZassetsu($year);
 305:             } else if ($month < $items[$i]['month']) {
 306:                 $month = $items[$i]['month'];
 307:             }
 308:             $day = $items[$i]['day'];
 309:             $items[$i]['year'] = $year;
 310: 
 311:             //日出没・月出没・月齢・距離
 312:             $sunrise = $pcl->sun_time(0, $longitude, $latitude, $height, $year, $month, $day);
 313:             $items[$i]['sunrise'] = $pcl->day2hhmm($sunrise);
 314:             $sunset = $pcl->sun_time(1, $longitude, $latitude, $height, $year, $month, $day);
 315:             $items[$i]['sunset'] = $pcl->day2hhmm($sunset);
 316:             $moonrise = $pcl->moon_time(0, $longitude, $latitude, $height, $year, $month, $day);
 317:             $items[$i]['moonrise'] = ($moonrise == FALSE? '---' : $pcl->day2hhmm($moonrise);
 318:             $moonset = $pcl->moon_time(1, $longitude, $latitude, $height, $year, $month, $day);
 319:             $items[$i]['moonset'] = ($moonset == FALSE? '---' : $pcl->day2hhmm($moonset);
 320:             $items[$i]['moonage'] = $pcl->moon_age($year, $month, $day, CALC_HOUR, 0, 0);
 321:             $items[$i]['moondist'] = sprintf('%4.3f', $pcl->distance_moon($year, $month, $day, CALC_HOUR, 0, 0));
 322: 
 323:             //潮
 324:             $moonmeridian = $pcl->moon_time(2, $longitude, $latitude, $height, $year, $month, $day);
 325:             $moonmeridian = ($moonmeridian == FALSE? '---' : $pcl->day2hhmm($moonmeridian);
 326:             $items[$i]['tide'] = (preg_match('/([0-9]+)\:([0-9]+)/', $moonmeridian, $arr> 0? $pcl->tide($year, $month, $day, $arr[1], $arr[2], 0)  : '';
 327: 
 328:             //二十四節気
 329:             $items[$i]['solarterm24'] = $pcl->getSolarTerm($year, $month, $day);
 330: 
 331:             //七十二候
 332:             $items[$i]['solarterm72'] = $pcl->getSolarTerm72($year, $month, $day);
 333: 
 334:             //土用
 335:             list($ss1, $ss2) = $pcl->isDoyo($year, $month, $day);
 336:             if ($ss2 == '明け') {
 337:                 $ss2 = '';
 338:             } else if (($ss1 !'夏'&& ($ss2 == '丑')) {
 339:                 $ss2 = '';
 340:             }
 341:             if ($ss1 !'' && $ss2 !'') {
 342:                 $ss2 = '土用の' . $ss2;
 343:             }
 344:             $items[$i]['doyo'] = $ss2;
 345: 
 346:             //彼岸
 347:             if (($higan[0]['in']['month'] == $month&& ($higan[0]['in']['day'] == $day)) {
 348:                 $solarterm = '彼岸入り';
 349:                 $ss2 = '彼岸入り' . $ss2;
 350:             } else if (($higan[0]['out']['month'] == $month&& ($higan[0]['out']['day'] == $day)) {
 351:                 $solarterm = '彼岸明け';
 352:                 $ss2 = '彼岸明け' . $ss2;
 353:             } else if (($higan[1]['in']['month'] == $month&& ($higan[1]['in']['day'] == $day)) {
 354:                 $solarterm = '彼岸入り';
 355:                 $ss2 = '彼岸入り' . $ss2;
 356:             } else if (($higan[1]['out']['month'] == $month&& ($higan[1]['out']['day'] == $day)) {
 357:                 $solarterm = '彼岸明け';
 358:                 $ss2 = '彼岸明け' . $ss2;
 359:             }
 360:             //雑節
 361:             foreach ($table_za as $label) {
 362:                 if (($zassetsu[$label]['month'] == $month&& ($zassetsu[$label]['day'] == $day)) {
 363:                     $solarterm = $label;
 364:                     $ss2 = $label . $ss2;
 365:                 }
 366:             }
 367: 
 368:             //祝日
 369:             $holiday = $pcl->getHoliday($year, $month, $day, 'jp');
 370:             $items[$i]['holiday'] = ($holiday == FALSE? '' : $holiday;
 371: 
 372:             //旧暦
 373:             list($oldmonth, $oldday, $oldleap) = $pcl->Gregorian2Lunar($year, $month, $day);
 374:             $oldleap = $oldleap ? '閏' : '';
 375:             $items[$i]['oldcal'] = sprintf('%s%d月%d日', $oldleap, $oldmonth, $oldday);
 376:             $items[$i]['rokuyou'] = $pcl->rokuyou($oldmonth, $oldday);
 377: 
 378:             //日の干支
 379:             $items[$i]['eto'] = $pcl->eto_day($year, $month, $day);
 380:         }
 381:     }
 382: }

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

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

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

 567: //各種パラメータを代入する.
 568: $items  = array();
 569: $errmsg = $url = $address = '';
 570: $id        = (int)getParam('id',          FALSE, 0);            //表示モード
 571: $query    = getValidString('query', $errmsg, '', QUERY_MIN_LEN, QUERY_MAX_LEN);
 572: if ($errmsg !'') {
 573:     $errmsg = '検索キーの長さが' . $errmsg;
 574: }
 575: $latitude  = (float)getParam('latitude',  FALSE, DEF_LATITUDE); //緯度
 576: $longitude = (float)getParam('longitude', FALSE, DEF_LONGITUDE);    //経度
 577: $zoom      = (int)getParam('zoom',        FALSE, DEF_ZOOM);     //ズーム
 578: $type      = (string)getParam('type',     FALSE, DEF_TYPE);     //マップタイプ
 579: $category  = (string)getParam('category', FALSE, 'address');    //カテゴリ
 580: $outenc    = (string)getParam('charset',  FALSE, INTERNAL_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は次の通り。

 158: <style>
 159: /* カレンダー:キャプション */
 160: h3.caption {
 161:     width: {$width}px;
 162:     font-size: 140%;
 163:     text-align: center;
 164: }
 165: /* カレンダー */
 166: table.DailyCalendar {
 167:     table-layout: fixed;
 168:     width: {$width}px;
 169:     border: solid 1px gray;
 170:     border-collapse: collapse;
 171:     margin-top:10px;
 172: }
 173: /* カレンダー:日付表示 */
 174: td.label1 {
 175:     border:solid 1px gray;
 176:     border-collapse: collapse;
 177:     padding: 4px;
 178:     white-space: nowrap;
 179:     font-size: 120%;
 180:     text-align:center;
 181:     color: white;
 182:     background-color: dimgray;
 183: }
 184: /* カレンダー:旧暦表示 */
 185: span.oldcal {
 186:     font-size: 80%;
 187: }
 188: /* カレンダー:ラベル表示 */
 189: td.label3 {
 190:     width: {$width3}px;
 191:     border:solid 1px gray;
 192:     border-collapse: collapse;
 193:     padding: 4px;
 194:     white-space: nowrap;
 195:     font-size: 100%;
 196:     text-align: center;
 197:     background-color: gainsboro;
 198: }
 199: /* カレンダー:データ表示 */
 200: td.data3 {
 201:     width: {$width3}px;
 202:     border:solid 1px gray;
 203:     border-collapse: collapse;
 204:     padding: 4px;
 205:     white-space: nowrap;
 206:     font-size: 100%;
 207:     text-align: center;
 208: }
 209: /* カレンダー:データ表示(小さい文字) */
 210: td.data4 {
 211:     width: {$width3}px;
 212:     border:solid 1px gray;
 213:     border-collapse: collapse;
 214:     padding: 4px;
 215:     white-space: nowrap;
 216:     font-size: 70%;
 217:     text-align: center;
 218: }
 219: /* 月の満ち欠け画像 */
 220: img.moonage {
 221:     width:  {$width9}px;
 222:     height: {$width9}px;
 223:     padding: 5px;
 224: }
 225: /* 天気予報表:予報アイコン */
 226: img.wicon {
 227:     width: 60px;
 228: }
 229: </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