こんにちは、りょうです。前回の記事では交通事故統計情報から交通事故が多発している交差点をcsvファイルにまとめました。
そこで作成したcsvファイルを使いやすい形にして僕のwebアプリに組み込みたいなと考えたので、今回はGPS座標を送信したら付近の危ない交差点の座標が返ってくるwebAPIを作成したいと思います!
作成したAPIの仕様
今回作成するAPIは、
- GETリクエストを受け付ける
- パラメータ[lat, lon]にはそれぞれ緯度、経度をいれる
- パラメータの座標を中心に10km四方の中の危険な交差点をJSON形式で返す
- パラメータに何も入っていなければデータベース上のすべてのデータを返す
- すべてphpで記述
という仕様にしたいと思います。
作成したソースコード
<?php
header('Content-Type: application/json; charset=UTF-8');
$dsn = "mysql:host=localhost;dbname=traffic_accident;charset=utf8";
$user = <ユーザネーム>;
$password = <パスワード>;
$dbh = new PDO($dsn, $user, $password);
$dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if(isset($_GET["lat"])&&isset($_GET["lon"])){ //パラメータが正しくセットされているときは10キロ四方のデータを返す
$query_lat = $_GET["lat"];
$query_lon = $_GET["lon"];
$lat = [floatval($query_lat) - 0.05, floatval($query_lat) + 0.05];
$lon = [floatval($query_lon) - 0.05, floatval($query_lon) + 0.05];
$sql = "select * from traffic_accident where (lat between '".$lat[0]."' and '".$lat[1]."') and (lon between '".$lon[0]."' and '".$lon[1]."')";
}else{ //パラメータが正しくセットされていないときは全データを返す
$sql = "select * from traffic_accident";
}
$stmt = $dbh -> prepare($sql);
$stmt -> execute();
while(true) {
$rec = $stmt -> fetch(PDO::FETCH_ASSOC);
if ($rec === false) {
break;
}
$arr[] = $rec;
}
print json_encode($arr, JSON_PRETTY_PRINT);
?>
9行目まではSQLの基本的な設定をしております。ひな形に従って記入しました。
なお今回のデータベースのdb名、テーブル名はどちらもtraffic_accidentにしており、カラムはid、lat、lon、countの4つで構成しております。
URLからパラメータを受け取る
GET通信において与えられたパラメータは$_GET[‘パラメータ名’]というスーパーグローバル変数(もともと定義された変数)に格納されます。簡単に扱えますね。
今回はパラメータが与えられているかを確認するためisset()関数を使用しました。
14、15行目でその値を使用していますが、string型として認識されているためfloatval()でfloat型に変換しています。
座標を中心に10km四方の範囲に該当するデータを検索する
「km」と「緯度経度」ってどうやるの?
まず10kmって緯度経度に表したらどれくらいなの?という疑問が出てきますが、調べてみると以下の記事が出てきました。
今回は値を厳密にとる必要は全くないのでそれぞれ0.01度を1kmとしています。
SQLって値の範囲で検索できたっけ?
いつもSQLはテーブル名を”SELECT”した後、欲しい値のデータを”LIKE”で検索するイメージでしたが、今回は範囲に該当するすべてのデータが欲しいため”BETWEEN”を使用します。
select * from テーブル名
where 項目名 between 開始値 and 終了値
のような記述で検索ができます。便利。
またphpの変数をSQL文に埋め込む際には、
‘”.$lat[0].”‘
のような書き方をします。
パラメータがなければ全データを返す
18行目ではSELECTのみをSQL文に入れているため、テーブルのすべてのデータを返します。
実装結果
※下のテストではデータの大きさの関係で交差点の回数が4回以上の交差点を返しています。
例)http://localhost/traffic_api?lat=43.0523&lon=141.404
上記のようなGETリクエストを送った場合のレスポンスは以下です。
4つのデータが返ってきています。
また、パラメータに何も入れないでおいた場合です。
例)http://localhost/traffic_api
1707箇所の交差点情報が返ってきました。ナイス。
おわりに
いかがだったでしょうか。今回はSQLの復習をするとともに、少し手を動かせたので僕としては満足です!