JavaScriptで位置情報を取得し、PHPでCSV保存する

JavaScriptで取得した位置情報をサーバ側へ保存したいなぁ、という思いから作りました。

成果物

こんな感じになりました。ソースはココ

フロント側。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8" />
    <title>hoge</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script defer>

        // ボタンクリック時
        $(document).ready(function() {
            $('#send').click(function() {
                // 位置情報の取得可否により分岐
                navigator.geolocation.getCurrentPosition(success, fail);
            });
        });

        // 位置情報が取得できた場合
        function success(pos) {
            var date = new Date(pos.timestamp);
            const position = {
                data: date.toLocaleString(),                // 日時
                lat: pos.coords.latitude,                   // 緯度
                lon: pos.coords.longitude,             // 経度
                alt: pos.coords.altitude,              // 高度
                posacc: pos.coords.accuracy,           // 位置精度
                altacc: pos.coords.altitudeAccuracy,   // 高度精度
                head: pos.coords.heading,              // 移動方向
                speed: pos.coords.speed                // 速度
            };
            // サーバーサイドへPOSTする
            $.ajax({
                type: "post",
                url: "server_side.php",
                data: {
                    "date": position.data,
                    "lat": position.lat,
                    "lon": position.lon,
                    "alt": position.alt,
                    "posacc": position.posacc,
                    "altacc": position.altacc,
                    "head": position.head,
                    "speed": position.speed
                },
                // 通信が成功した場合 
                success: function(data, dataType) {
                    alert(data); // サーバーサイドからの返答を表示させてみる
                },
                // 通信が失敗した場合
                error: function() {
                    alert('失敗らしい');
                }
            });
        }

        // 位置情報が取得できなかった場合
        function fail(error) {
            if (error.code == 1) alert('位置情報を取得する時に許可がない')
            if (error.code == 2) alert('何らかのエラーが発生し位置情報が取得できなかった。')
            if (error.code == 3) alert('タイムアウト 制限時間内に位置情報が取得できなかった。')
        }
    </script>
</head>

<body>
    <button type="button" id="send">ボタン</button>
</body>

</html>

サーバ側。

<?php
header("Content-type: text/plain; charset=UTF-8");

// POST変数を取得
$date = $_POST['date'];
$lat = $_POST['lat'];
$lon = $_POST['lon'];
$alt = $_POST['alt'];
$posacc = $_POST['posacc'];
$altacc = $_POST['altacc'];
$head = $_POST['head'];
$speed = $_POST['speed'];

// csv保存
$file = fopen("position.csv", "a");
fwrite($file, "$date,$lat,$lon,$alt,$posacc,$altacc,$head,$speed");
fwrite($file, "\n");
fclose($file);

// フロントサイドへてきとーに返しておく
echo "これもらったよ。$date,$lat,$lon,$alt,$posacc,$altacc,$head,$speed";

解説

まず、ボタンをクリックすると、GeolocationというAPIを呼び出します。

APIと通信ができたらsuccess関数へ、できなかったらfail関数へ処理を流します。

        // ボタンクリック時
        $(document).ready(function() {
            $('#send').click(function() {
                // 位置情報の取得可否により分岐
                navigator.geolocation.getCurrentPosition(success, fail);
            });
        });

ではsuccess関数の中身の解説です。

APIからもらった情報をオブジェクトに突っ込んで、Ajaxを使ってその値をサーバへPOSTさせています。

        // 位置情報が取得できた場合
        function success(pos) {
            var date = new Date(pos.timestamp);
            const position = {
                data: date.toLocaleString(),                // 日時
                lat: pos.coords.latitude,                   // 緯度
                lon: pos.coords.longitude,             // 経度
                alt: pos.coords.altitude,              // 高度
                posacc: pos.coords.accuracy,           // 位置精度
                altacc: pos.coords.altitudeAccuracy,   // 高度精度
                head: pos.coords.heading,              // 移動方向
                speed: pos.coords.speed                // 速度
            };
            // サーバーサイドへPOSTする
            $.ajax({
                type: "post",
                url: "server_side.php",
                data: {
                    "date": position.data,
                    "lat": position.lat,
                    "lon": position.lon,
                    "alt": position.alt,
                    "posacc": position.posacc,
                    "altacc": position.altacc,
                    "head": position.head,
                    "speed": position.speed
                },
                // 通信が成功した場合 
                success: function(data, dataType) {
                    alert(data); // サーバーサイドからの返答を表示させてみる
                },
                // 通信が失敗した場合
                error: function() {
                    alert('失敗らしい');
                }
            });
        }

POSTの内容をPHPで取得します。

その内容をcsvへ追記していきます。

MySQLなどに格納しても良いですが、私はcsvが欲しかっただけなのでこれで満足です。

<?php
header("Content-type: text/plain; charset=UTF-8");

// POST変数を取得
$date = $_POST['date'];
$lat = $_POST['lat'];
$lon = $_POST['lon'];
$alt = $_POST['alt'];
$posacc = $_POST['posacc'];
$altacc = $_POST['altacc'];
$head = $_POST['head'];
$speed = $_POST['speed'];

// csv保存
$file = fopen("position.csv", "a");
fwrite($file, "$date,$lat,$lon,$alt,$posacc,$altacc,$head,$speed");
fwrite($file, "\n");
fclose($file);

// フロントサイドへてきとーに返しておく
echo "これもらったよ。$date,$lat,$lon,$alt,$posacc,$altacc,$head,$speed";

環境構築とか

ここに書いてあるDockerfileとdocker-compose.ymlをコピペし、docker-compose up -dをするだけでOKです。

htmlとmysqlというディレクトリが生成されるので、html直下にコンテンツを作っていけば良いです。

コンテンツはhttp://localhost:8080で見れます。

Docker便利ですねぇ。。

最後に

このツールを作成した背景としては、「端末の位置情報とWi-Fiの情報を取得し、都内のWi-Fiのセキュリティレベルを調査したい」というものがありました。

位置情報を取得するのであればiOSアプリを作った方が簡単そうだと思ったのですが、Wi-Fiのセキュリティ方式などの詳細な情報を抜き出そうとすると、実装が難しそうに思えたため諦めました。。

結果、「JavaScriptだと簡単に位置情報が抽出できる上に、Macに仕込んで出歩けばWi-Fi情報と位置情報を取得することができる」というイメージが付いたので、JavaScript + PHP + シェルで実装しました。

実際に作ってみて実感したことがあります。

それは、「位置情報はブラウザ経由で簡単に取得できてしまう」ということです。

例えば、私がこのツールを本サイトに仕込んでおけば、そこにアクセスした人が「位置情報の取得を許可する」を押すと、その人の位置情報や端末情報、IPアドレスなどが簡単に得られてしまいます。

そう考えると、日頃からGoogle Mapなどを使っている私たちは、インターネットを介して個人情報がダダ漏れになっていると言っても過言ではないと思います。

「科学は人間を機械の奴隷にした」というアインシュタイン(が言ったとされる)の言葉を彷彿しました。

などなど、、色んなことを考えさせてくれる良い開発となりました。

参考資料