Quantcast
Viewing all articles
Browse latest Browse all 8636

【簡易版】APIを使いOpenWeatherMapから気象情報が取得できるWebサービスをPHPで作成する方法

準備 OpenWeatherMapにアカウント登録しAPI Keyを発行する. API Keyをメモする. 事前リサーチ1: 都市コードを調べる 例)札幌市の場合検索窓に英語表記でsapporoと入力 上記画像URL欄末尾に表記される札幌市の都市コード2128295をメモする. 事前リサーチ2: ブラウザでJSONを表示させてみる 【URLの組み立て方】 下記URLに都市コードとAPI Keyを設定する. https://api.openweathermap.org/data/2.5/weather?id=都市コード&appid=API Key ブラウザでアクセスしてみる. 下記JSONが表示された. {"coord":{"lon":141.3469,"lat":43.0642},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"base":"stations","main":{"temp":273.71,"feels_like":269.44,"temp_min":273.71,"temp_max":273.71,"pressure":1020,"humidity":81},"visibility":10000,"wind":{"speed":4.17,"deg":158,"gust":7.56},"clouds":{"all":100},"dt":1617729138,"sys":{"type":3,"id":64679,"country":"JP","sunrise":1617739594,"sunset":1617786400},"timezone":32400,"id":2128295,"name":"Sapporo","cod":200} Webサービスの作製 【システム環境】 macOS 10.11.6以降(他のOSでも可) Apache 2.4.28以降 PHP 5.5.38以降 本記事ではディレクトリ操作をmacOSに合せて記述しているため,他のOS(Linux, Windows等)の使用時は必要に応じてディレクトリ構造を置き換えて考えるものとする. ディレクトリとファイルの作成 $ sudo mkdir /Library/WebServer/Documents/Weather $ sudo touch /Library/WebServer/Documents/Weather/weather_info.php $ sudo mkdir /Library/WebServer/Documents/Weather/common $ sudo touch /Library/WebServer/Documents/Weather/common/header.php $ sudo touch /Library/WebServer/Documents/Weather/common/openweathermap.php $ sudo mkdir /Library/WebServer/Documents/Weather/config $ sudo touch /Library/WebServer/Documents/Weather/config/opn_wm_api_key.php $ sudo mkdir /Library/WebServer/Documents/Weather/css $ sudo touch /Library/WebServer/Documents/Weather/css/weather_info_css.php 気象情報表示用ページweather_info.phpのソースコード 約10〜20分間隔でOpenWeatherMapから最新データが配信される. weather_info.php <?php require_once __DIR__ . '/common/header.php'; require_once __DIR__ . '/common/openweathermap.php'; # ページタイトル $title = '気象情報'; # ブラウザ自動更新間隔(10分とする) $reload_interval = 10 * 60; # 都市名と都市コードの連想配列(新たな都市は都度追加) $citycode1 = ['札幌' => 2128295, '東京都' => 1850144, '横浜市' => 1848354, '大阪市' => 1853909]; $citycode2 = ['名古屋市' => 1856057, '尾道市' => 1853992, '福岡市' => 1863967, '那覇市' => 1856035]; # 上記配列をマージ $citycodes = array_merge($citycode1, $citycode2); # 気象情報を取得したい都市名を上記連想配列から選択し入力 $city = $citycodes['東京都']; # 表示形式と都市コードを指定しJSONを連想配列にデコード $response = getAssociative('weather', $city); # 日付の書式1(表示用) $date1 = getDatetime($response, 'Y年m月d日'); # 日付の書式2(曜日取得用) $date2 = getDatetime($response, 'Ymd', 'weather'); # 曜日(日本語化) $day = getWeek($date2); # 時刻の書式 $time = getDatetime($response, 'H:i'); # 都市名(英語表記) $city = $response['name']; # 都市名(日本語化) $city = getCityName($city); # 天気情報の配列 $weather_data = $response['weather']; # 現在の天気(英語表記) $weather = $weather_data[0]['main']; # 現在の天気(日本語化) $weather = getWeatherTranslation($weather); # 天気の詳細(英語表記) $description = $weather_data[0]['description']; # 天気の詳細(日本語化) $description = getDescriptionTranslation($description); # 天気アイコン $icon = $weather_data[0]['icon']; $img = 'https://openweathermap.org/img/wn/' .$icon .'@2x.png'; # 絶対零度 $absolute_zero = -273.15; # 温度情報のメイン階層 $temp_data = $response['main']; # 現在の気温,体感温度,最高気温,最低気温(小数点以下四捨五入かつ摂氏表示) $temp = round($temp_data['temp'] + $absolute_zero); $feels_like = round($temp_data['feels_like'] + $absolute_zero); $temp_max = round($temp_data['temp_max'] + $absolute_zero); $temp_min = round($temp_data['temp_min'] + $absolute_zero); # 湿度 $humidity = $temp_data['humidity']; # 気圧 $pressure = $temp_data['pressure']; # 風の情報のメイン階層 $wind_data = $response['wind']; # 風速(小数点第二位で四捨五入) $speed = round($wind_data['speed'], 1); # 風向(16方位で日本語化) $deg = getDirection($wind_data['deg']); ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="refresh" content="<?= $reload_interval; ?>"> <!-- 時刻によって背景色と文字色を切り替えるCSSを設定 PHPを使用するので拡張子はcssではなくphpにする --> <link rel="stylesheet" href="css/weather_info_css.php"> <title><?= $title; ?></title> </head> <body> <font> <h1><?= $title; ?></h1> <div><span><?= $date1; ?></span><span><?= '(' . $day . ')' ?></span></div> <div><span><?= $time; ?></span> 時点の気象情報</div> <hr style="border:0;border-top:1px none;"> <div>都市名  : <span><?= $city; ?></span></div> <div>現在の天気: <span><?= $weather; ?></span></div> <div>天気の詳細: <span><?= $description; ?></span></div> <img src="<?= $img; ?>"> <div>現在の気温: <span><?= $temp . '℃'; ?></span></div> <div>体感気温 : <span><?= $feels_like . '℃'; ?></span></div> <div>最高気温 : <span><?= $temp_max . '℃'; ?></span></div> <div>最低気温 : <span><?= $temp_min . '℃'; ?></span></div> <div>湿度   : <span><?= $humidity . '%'; ?></span></div> <div>気圧   : <span><?= $pressure . 'hPa'; ?></span></div> <div>風速   : <span><?= $speed . 'm/s'; ?></span></div> <div>風向   : <span><?= $deg . 'の風'; ?></span></div> </font> </body> </html> ヘッダ設定ファイルheader.phpのソースコード header.php <?php # HTMLを記述するコード内でのヘッダ設定 header('Content-type: text/html; charset=utf-8'); 【試作版】メインモジュールopenweathermap.phpのソースコード 後述のWarning対策に対応していないので下記ソースコードは本採用しない. openweathermap.php <?php require_once __DIR__ . '/../config/opn_wm_api_key.php'; /** * OpenWeatherMapのAPIを利用したJSONを取得し連想配列にデコードする関数 * 引数は表示形式と都市コード */ function getAssociative($api_type, $area_id) { /** API Keyを外部ファイルから呼び出し(.gitignore済) * OpenWeatherMapよりAPI Keyを取得して設定することも可能 */ $api_key = opn_wm_api_key(); # ベースURL $api_base = 'https://api.openweathermap.org/data/2.5/'; # ベースURLのパラメータ $api_parm = '?id=' . $area_id . '&appid=' . $api_key; # URLの連結 $api_url = $api_base . $api_type . $api_parm; # URLの読み込み $api_url = file_get_contents($api_url); # JSONをデコード(第二引数をtrueにすることでJSONを連想配列にする) $associative = json_decode($api_url, true); # 戻り値はデコードされた連想配列 return $associative; } # 下記関数への引数(エラー制御演算子付き) @$response = getAssociative($api_type, $area_id); # 上記関数から取得した最新のUTCから指定した書式に変換する関数 function getDatetime($response, $format) { # 最新のUNIX時刻(UTC) $utc = $response['dt']; # DateTimeZoneオブジェクトのインスタンスを生成しJSTを設定 $jst = new DateTimeZone('Asia/Tokyo'); /** * DateTimeオブジェクトのインスタンスを生成 * UNIX時刻を日時に変換 */ $datetime = new DateTime(); # UTCをJSTに変換 $datetime->setTimestamp($utc)->setTimeZone($jst); # 書式設定し年月日を取得 $date = $datetime->format($format); return $date; } # 日本語表記の曜日を取得する関数 function getWeek($date) { # $date2をUNIX時刻に変換 $day = strtotime($date); # 曜日の配列番号を取得 $day = date('w', $day); # 曜日の配列 $week = ['日', '月', '火', '水', '木', '金', '土']; # 連想配列の長さマイナス1 $length = count($week) - 1; # 曜日の日本語表示の分岐 for ($i = 0; $i <= $length; $i++): if ($day == $i): return $week[$i]; endif; endfor; } # 都市名を日本語化する関数(新たな都市は都度追加) function getCityName($city) { # 都市名の連想配列 $list1 = ['Sapporo' => '札幌市', 'Tokyo' => '東京都', 'Yokohama' => '横浜市', 'Osaka' => '大阪市']; $list2 = ['Nagoya' => '名古屋市', 'Onomichi' => '尾道市', 'Fukuoka' => '福岡市', 'Naha' => '那覇市']; # 上記配列をマージ $lists = array_merge($list1, $list2); # 連想配列の長さマイナス1 $length = count($lists) - 1; # 連想配列のキー $keys = array_keys($lists); # 連想配列の値 $values = array_values($lists); # 都市名の日本語表示の分岐 for ($i = 0; $i <= $length; $i++): if($city == $keys[$i]): return $values[$i]; endif; endfor; } # 現在の天気を翻訳する関数 function getWeatherTranslation($weather) { # 翻訳用天気名の連想配列(新たな英語表記の天気名が表示された場合は都度追加) $list = ['Clear' => '晴れ', 'Clouds' => 'くもり', 'Rain' => '雨', 'Snow' => '雪', 'Mist' => '霧']; # 連想配列の長さマイナス1 $length = count($list) - 1; # 連想配列のキー $keys = array_keys($list); # 連想配列の値 $values = array_values($list); # 天気名の日本語化 for ($i = 0; $i <= $length; $i++): if ($weather == $keys[$i]): return $values[$i]; endif; endfor; } # 天気詳細を翻訳する関数 function getDescriptionTranslation($description) { switch ($description): case 'overcast clouds': return 'どんよりした雲<br class="nosp">(雲85~100%)'; break; case 'broken clouds': return '千切れ雲<br class="nosp">(雲51~84%)'; break; case 'scattered clouds': return '散らばった雲<br class="nosp">(雲25~50%)'; break; case 'few clouds': return '少ない雲<br class="nosp">(雲11~25%)'; break; case 'light rain': return '小雨'; break; case 'moderate rain': return '雨'; break; case 'heavy intensity rain': return '大雨'; break; case 'very heavy rain': return '激しい大雨'; break; case 'clear sky': return '快晴'; break; case 'shower rain': return 'にわか雨'; break; case 'light intensity shower rain': return '小雨のにわか雨'; break; case 'heavy intensity shower rain': return '大雨のにわか雨'; break; case 'thunderstorm': return '雷雨'; break; case 'snow': return '雪'; break; case 'light snow': return '小雪'; break; case 'light shower snow': return '弱いにわか雪'; break; case 'mist': return '靄'; break; case 'tornado': return '強風'; break; default: return $description; endswitch; } # 16方位により風向を取得する関数 function getDirection($deg) { if ($deg >= 0 && $deg <= 10): return '北'; elseif ($deg >= 11 && $deg <= 29): return '北北東'; elseif ($deg >= 30 && $deg <= 60): return '北東'; elseif ($deg >= 61 && $deg <= 79): return '東北東'; elseif ($deg >= 80 && $deg <= 100): return '東'; elseif ($deg >= 101 && $deg <= 119): return '東南東'; elseif ($deg >= 120 && $deg <= 150): return '南東'; elseif ($deg >= 151 && $deg <= 169): return '南南東'; elseif ($deg >= 170 && $deg <= 190): return '南'; elseif ($deg >= 191 && $deg <= 209): return '南南西'; elseif ($deg >= 210 && $deg <= 240): return '南西'; elseif ($deg >= 241 && $deg <= 259): return '西南西'; elseif ($deg >= 260 && $deg <= 280): return '西'; elseif ($deg >= 281 && $deg <= 299): return '西北西'; elseif ($deg >= 300 && $deg <= 330): return '北西'; elseif ($deg >= 331 && $deg <= 349): return '北北西'; elseif ($deg >= 350 && $deg <= 360): return '北'; endif; } API Key記述ファイルopn_wm_api_key.phpのソースコード(下記戻り値にAPI Keyを設定) GitHub等でのバージョン管理を考慮して外部ファイルとした.(.gitignoreに記述を推奨) opn_wm_api_key.php <?php # OpenWeatherMapのAPI Keyを返す関数 function opn_wm_api_key() { return 'API Keyを設定'; } 画面装飾ファイルweather_info_css.phpのソースコード PHPでCSSを制御しシステム時刻により背景色・文字色を切り替える. 参照: PHPでCSSファイルを制御する weather_info_css.php <?php # タイムゾーンの設定 require_once __DIR__ . '/../common/timezone.php'; # CSSを記述するコード内でのヘッダ設定 header('Content-Type: text/css; charset=utf-8'); # 現在のシステム時刻(ゼロなしの時) $now = date('G'); # システム時刻5:00〜16:59までとそれ以外の時刻で背景色と文字色を切り替える $bgcol = $now >= 5 && $now < 17 ? '#87ceeb' : '#000033'; $ftcol = $now >= 5 && $now < 17 ? '#000000' : '#ffffff'; ?> body { background-color: <?= $bgcol; ?>; color: <?= $ftcol; ?>; } 動作確認 Apacheの起動 $ sudo apachectl start ブラウザ上にlocalhost/Weather/weather_info.phpを入力して動作確認を行う. システム時刻5:00〜16:59 システム時刻17:00〜翌日4:59 システム時刻により背景色・文字色を切り替わることが確認された. Warning画面(ネットワーク系統の不具合発生時) 前述した【試作版】メインモジュールopenweathermap.phpのままだとLAN/WAN系,その他偶発的なネットワーク系統の不具合が発生すると以下の画面が表示される. 【Warning画面の再現方法】 使用マシンのネットワーク接続(Wi-Fi等)を切にする. ブラウザ上にlocalhost/Weather/weather_info.phpを入力する. 日付が1970年01月01日と表示され,各種パラメータに異常値が表示される. Warning対策 【下記curlコマンドに対するレスポンスの検証】 Wi-Fiを入にした状態で下記curlコマンドを実行してみる. グローバルIPアドレスが返ってくる. $ curl -s ifconfig.me | grep '^[21]' XXX.XXX.XXX.XXX Wi-Fiを切にした状態で下記curlコマンドを実行してみる. グローバルIPアドレスが返ってこない. $ curl -s ifconfig.me | grep '^[21]' 上記検証よりネットワーク系統に不具合が発生するとグローバルIPアドレスが返ってこないことが判明した.グローバルIPアドレスが返ってこない場合は専用画面を表示させ,5秒ごとに再接続を試みるようにすることでWarning対策を行う. 専用画面: 前述した【試作版】メインモジュールopenweathermap.phpに下記コードを追記する. 専用画面を表示させ,5秒ごとに再接続を試みるようにする関数をソースコードの始まりに追記 <?php # ネットワークエラー画面を表示する関数(5秒間隔でリロード再接続を試みる) function networkError($msg, $sec = 5) { ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="refresh" content="<?= $sec; ?>"> <title><?= $msg; ?></title> </head> <body> <div><?= $msg; ?></div> <div><?= $sec; ?>秒後に再接続します</div> </body> </html> <?php exit(); } ?> getAssociative関数内の始まりに下記コードを追記 # グローバルIPアドレスを調べるコマンド $command = 'curl -s ifconfig.me | grep \'^[21]\''; # 上記コマンドからレスポンス値を取得(グローバルIPアドレス) exec($command, $response); # グローバルIPアドレスが返ってこないの場合のエラーメッセージ $msg = 'Network Error..'; # グローバルIPアドレスが返ってこないの場合はエラー画面を表示する !isset($response[0]) ? networkError($msg) : null; 【決定版】Warning対策済メインモジュールopenweathermap.php デメリットとしてifconfig.meに一旦アクセスするためレスポンスの取得が若干遅くなる. openweathermap.php <?php require_once __DIR__ . '/../config/opn_wm_api_key.php'; # ネットワークエラー画面を表示する関数(5秒間隔でリロード再接続を試みる) function networkError($msg, $sec = 5) { ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="refresh" content="<?= $sec; ?>"> <title><?= $msg; ?></title> </head> <body> <div><?= $msg; ?></div> <div><?= $sec; ?>秒後に再接続します</div> </body> </html> <?php exit(); } /** * OpenWeatherMapのAPIを利用したJSONを取得し連想配列にデコードする関数 * 引数は表示形式と都市コード */ function getAssociative($api_type, $area_id) { # グローバルIPアドレスを調べるコマンド $command = 'curl -s ifconfig.me | grep \'^[21]\''; # 上記コマンドからレスポンス値を取得(グローバルIPアドレス) exec($command, $response); # グローバルIPアドレスが返ってこないの場合のエラーメッセージ $msg = 'Network Error..'; # グローバルIPアドレスが返ってこないの場合はエラー画面を表示する !isset($response[0]) ? networkError($msg) : null; /** API Keyを外部ファイルから呼び出し(.gitignore済) * OpenWeatherMapよりAPI Keyを取得して設定することも可能 */ $api_key = opn_wm_api_key(); # ベースURL $api_base = 'https://api.openweathermap.org/data/2.5/'; # ベースURLのパラメータ $api_parm = '?id=' . $area_id . '&appid=' . $api_key; # URLの連結 $api_url = $api_base . $api_type . $api_parm; # URLの読み込み $api_url = file_get_contents($api_url); # JSONをデコード(第二引数をtrueにすることでJSONを連想配列にする) $associative = json_decode($api_url, true); # 戻り値はデコードされた連想配列 return $associative; } # 下記関数への引数(エラー制御演算子付き) @$response = getAssociative($api_type, $area_id); # 上記関数から取得した最新のUTCから指定した書式に変換する関数 function getDatetime($response, $format) { # 最新のUNIX時刻(UTC) $utc = $response['dt']; # DateTimeZoneオブジェクトのインスタンスを生成しJSTを設定 $jst = new DateTimeZone('Asia/Tokyo'); /** * DateTimeオブジェクトのインスタンスを生成 * UNIX時刻を日時に変換 */ $datetime = new DateTime(); # UTCをJSTに変換 $datetime->setTimestamp($utc)->setTimeZone($jst); # 書式設定し年月日を取得 $date = $datetime->format($format); return $date; } # 日本語表記の曜日を取得する関数 function getWeek($date) { # $date2をUNIX時刻に変換 $day = strtotime($date); # 曜日の配列番号を取得 $day = date('w', $day); # 曜日の配列 $week = ['日', '月', '火', '水', '木', '金', '土']; # 連想配列の長さマイナス1 $length = count($week) - 1; # 曜日の日本語表示の分岐 for ($i = 0; $i <= $length; $i++): if ($day == $i): return $week[$i]; endif; endfor; } # 都市名を日本語化する関数(新たな都市は都度追加) function getCityName($city) { # 都市名の連想配列 $list1 = ['Sapporo' => '札幌市', 'Tokyo' => '東京都', 'Yokohama' => '横浜市', 'Osaka' => '大阪市']; $list2 = ['Nagoya' => '名古屋市', 'Onomichi' => '尾道市', 'Fukuoka' => '福岡市', 'Naha' => '那覇市']; # 上記配列をマージ $lists = array_merge($list1, $list2); # 連想配列の長さマイナス1 $length = count($lists) - 1; # 連想配列のキー $keys = array_keys($lists); # 連想配列の値 $values = array_values($lists); # 都市名の日本語表示の分岐 for ($i = 0; $i <= $length; $i++): if($city == $keys[$i]): return $values[$i]; endif; endfor; } # 現在の天気を翻訳する関数 function getWeatherTranslation($weather) { # 翻訳用天気名の連想配列(新たな英語表記の天気名が表示された場合は都度追加) $list = ['Clear' => '晴れ', 'Clouds' => 'くもり', 'Rain' => '雨', 'Snow' => '雪', 'Mist' => '霧']; # 連想配列の長さマイナス1 $length = count($list) - 1; # 連想配列のキー $keys = array_keys($list); # 連想配列の値 $values = array_values($list); # 天気名の日本語化 for ($i = 0; $i <= $length; $i++): if ($weather == $keys[$i]): return $values[$i]; endif; endfor; } # 天気詳細を翻訳する関数 function getDescriptionTranslation($description) { switch ($description): case 'overcast clouds': return 'どんよりした雲<br class="nosp">(雲85~100%)'; break; case 'broken clouds': return '千切れ雲<br class="nosp">(雲51~84%)'; break; case 'scattered clouds': return '散らばった雲<br class="nosp">(雲25~50%)'; break; case 'few clouds': return '少ない雲<br class="nosp">(雲11~25%)'; break; case 'light rain': return '小雨'; break; case 'moderate rain': return '雨'; break; case 'heavy intensity rain': return '大雨'; break; case 'very heavy rain': return '激しい大雨'; break; case 'clear sky': return '快晴'; break; case 'shower rain': return 'にわか雨'; break; case 'light intensity shower rain': return '小雨のにわか雨'; break; case 'heavy intensity shower rain': return '大雨のにわか雨'; break; case 'thunderstorm': return '雷雨'; break; case 'snow': return '雪'; break; case 'light snow': return '小雪'; break; case 'light shower snow': return '弱いにわか雪'; break; case 'mist': return '靄'; break; case 'tornado': return '強風'; break; default: return $description; endswitch; } # 16方位により風向を取得する関数 function getDirection($deg) { if ($deg >= 0 && $deg <= 10): return '北'; elseif ($deg >= 11 && $deg <= 29): return '北北東'; elseif ($deg >= 30 && $deg <= 60): return '北東'; elseif ($deg >= 61 && $deg <= 79): return '東北東'; elseif ($deg >= 80 && $deg <= 100): return '東'; elseif ($deg >= 101 && $deg <= 119): return '東南東'; elseif ($deg >= 120 && $deg <= 150): return '南東'; elseif ($deg >= 151 && $deg <= 169): return '南南東'; elseif ($deg >= 170 && $deg <= 190): return '南'; elseif ($deg >= 191 && $deg <= 209): return '南南西'; elseif ($deg >= 210 && $deg <= 240): return '南西'; elseif ($deg >= 241 && $deg <= 259): return '西南西'; elseif ($deg >= 260 && $deg <= 280): return '西'; elseif ($deg >= 281 && $deg <= 299): return '西北西'; elseif ($deg >= 300 && $deg <= 330): return '北西'; elseif ($deg >= 331 && $deg <= 349): return '北北西'; elseif ($deg >= 350 && $deg <= 360): return '北'; endif; } 今回は簡易版としてAPIを使いOpenWeatherMapから気象情報が取得できるWebサービスをPHPで作成する方法について記述したが,次回は応用編としてOpenWeatherMapから取得した気象情報をDBに記録する方法に関して記述予定である.

Viewing all articles
Browse latest Browse all 8636

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>