概要
LINE BOTを使って、位置情報を送ると周辺のラーメン情報を答えさせます。
先人達が数々のすばらしい記事をあげているので、
何番煎じだ?というところですが自分メモとして投稿します。
結果としてとりあえず動いていますが、
ソースを完全に理解できていない部分もあり、まだまだ勉強中です。
不備不足をご指摘いただけると助かります。
環境や利用サービス
windows7 64bit
LINE API
ぐるなびAPI
PHP
heroku
参考記事
- 【LINE BOT API】位置情報を送ると近くのラーメン屋さんを教えてくれるBOTを作ってみました
- LINE BOT API Trialでできる全ての事を試してみた
- 【LINE Bot】Heroku+PHP+雑談対話APIで会話Bot作ってみた
- ぐるナビAPIのサンプルコードでポエム書いた
- わずか5分。新LINE Messaging APIでbotを作ってみた手順全公開
実装手順
- LINEBOTアカウント取得
- ぐるなびAPI取得
- herokuアカウント取得
- こちらの記事を参考にサンプルプログラムソースをherokuにデプロイ
- Heroku CLI.をインストールする
- リモートリポジトリをクローンする
- こちらの記事を参考にcallback.phpを編集する(ソースは後述)
- 編集したcallback.phpをherokuにPUSHする
- herokuの環境変数※1.にぐるなびAPIとLINEのアクセスキー(gnavi_access_key、LINE_CHANNEL_ACCESS_TOKEN)を登録する
- LINE管理者メニュー※2.にコールバックURLを設定(例:https://sample.herokuapp.com/callback.php)
※1. heroku環境変数 (setting→Config Variables)
※2. LINE管理者メニュー (LINE BUSINESS CENTER→LINE Developers→Webhook URL)
PHPというかWeb開発はほぼ素人だったため、理屈は置いといて
まずはサンプルプログラムが動くようにしました(1.~4.)。
そこから少しずつ改修→テスト→改修といった流れで実装していきました。
#ソースファイル
<?php
// アクセスキー
$gnaviaccesskey = getenv('gnavi_access_key');
$accessToken = getenv('LINE_CHANNEL_ACCESS_TOKEN');
//ユーザーからのメッセージ取得
$json_string = file_get_contents('php://input');
$jsonObj = json_decode($json_string);
$type = $jsonObj->{"events"}[0]->{"message"}->{"type"};
//メッセージ取得
$text = $jsonObj->{"events"}[0]->{"message"}->{"text"};
//ReplyToken取得
$replyToken = $jsonObj->{"events"}[0]->{"replyToken"};
//緯度取得
$latitude = $jsonObj->{"events"}[0]->{"message"}->{"latitude"};
//経度取得
$longitude = $jsonObj->{"events"}[0]->{"message"}->{"longitude"};
//エンドポイントのURIとフォーマットパラメータを変数に入れる
$uri = "http://api.gnavi.co.jp/RestSearchAPI/20150630/";
//APIアクセスキーを変数に入れる
$acckey= $gnaviaccesskey;
//返却値のフォーマットを変数に入れる
$format= "json";
//緯度・経度、範囲を変数に入れる
// 業態がラーメン屋さんを意味するぐるなびのコード(大業態マスタ取得APIをコールして調査)
$category_s = "RSFST08008";
$hit_per_page = "5";
//緯度経度は日本測地系で日比谷シャンテのもの。範囲はrange=2で500m以内を指定している。
$range = 2;
//URL組み立て
$url = sprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", $uri, "?format=", $format, "&keyid=", $acckey, "&latitude=", $latitude,"&longitude=",$longitude,"&category_s=",$category_s,"&range=",$range,"&hit_per_page=",$hit_per_page);
//API実行
$json = file_get_contents($url);
//取得した結果をオブジェクト化
$obj = json_decode($json);
$total_hit_count = $obj->{'total_hit_count'};
$result = "";
//店舗情報の格納配列
$i = 1;
//イケてないけど、$response_format_textにループで配列データ格納しようとしても
//失敗してしまうのでベタうちにする。
$get_name1 ="該当なし";
$get_url1 ="http://www.yahoo.co.jp/";
$get_name2 ="該当なし";
$get_url2 ="http://www.yahoo.co.jp/";
$get_name3 ="該当なし";
$get_url3 ="http://www.yahoo.co.jp/";
$get_name4 ="該当なし";
$get_url4 ="http://www.yahoo.co.jp/";
$get_name5 ="該当なし";
$get_url5 ="http://www.yahoo.co.jp/";
//結果をパース
if ($total_hit_count === null) {
$result .= "近くにラーメン屋さんはありません。";
}else{
$result .= "近くにあるラーメン屋さんです。\n\n";
foreach((array)$obj as $key => $val){
if(strcmp($key, "rest") == 0){
foreach((array)$val as $restArray){
//最寄駅入れようかと思ったけど、任意位置で計測するから駅近とは限らないことに気づいた
//$station ="";
//$station .= $restArray->{"access"}->{"station"};
//$station .= $restArray->{"access"}->{"exit"};
//$station .= $restArray->{"access"}->{"walk"} . "分";
//switch文だとLineにレスが返らないのでif文で対応
if($i===1){
$get_name1 = $restArray->{"name"};
$get_url1 = $restArray->{"url"};
$get_address1 = $restArray->{"address"};
}
if($i===2){
$get_name2 =$restArray->{"name"};
$get_url2 =$restArray->{"url"};
$get_address2 = $restArray->{"address"};
}
if($i===3){
$get_name3 =$restArray->{"name"};
$get_url3 =$restArray->{"url"};
$get_address3 = $restArray->{"address"};
}
if($i===4){
$get_name4 =$restArray->{"name"};
$get_url4 =$restArray->{"url"};
$get_address4 = $restArray->{"address"};
}
if($i===5){
$get_name5 =$restArray->{"name"};
$get_url5 =$restArray->{"url"};
$get_address5 = $restArray->{"address"};
}
$i++;
}
}
}
}
//返信データ作成
$response_format_text = [
"type" => "template",
"altText" => "候補をご案内しています。(Powered by ぐるなび)",
"template" => [
"type" => "carousel",
"columns" => [
[
"title" => $get_name1,
"text" => "住所:".$get_address1,
"actions" => [
[
"type" => "uri",
"label" => "URL",
"uri" => $get_url1
]
]
],
[
"title" => $get_name2,
"text" => "住所:".$get_address2,
"actions" => [
[
"type" => "uri",
"label" => "URL",
"uri" => $get_url2
]
]
],
[
"title" => $get_name3,
"text" => "住所:".$get_address3,
"actions" => [
[
"type" => "uri",
"label" => "URL",
"uri" => $get_url3
]
]
],
[
"title" => $get_name4,
"text" => "住所:".$get_address4,
"actions" => [
[
"type" => "uri",
"label" => "URL",
"uri" => $get_url4
]
]
],
[
"title" => $get_name5,
"text" => "住所:".$get_address5,
"actions" => [
[
"type" => "uri",
"label" => "URL",
"uri" => $get_url5
]
]
]
]
]
];
$post_data = [
"replyToken" => $replyToken,
"messages" => [$response_format_text]
];
$ch = curl_init("https://api.line.me/v2/bot/message/reply");
curl_setopt($ch, CURLOPT_POST,true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charser=UTF-8',
'Authorization: Bearer ' . $accessToken
));
$result = curl_exec($ch);
curl_close($ch);
はまったところ(未解決)
ぐるなびAPIから取得できる[PR]や[画像]を持って来ようとするとBOTが反応しなくなりました。
恐らく取得したデータの形式が制約に引っかかってると思われます。
(必須なのにNULLとか画像サイズが大きすぎるとか)
- PRは文字列が長すぎるかも?ということで[pr_long]から[pr_short]にしてもダメ。
- 画像はサイズ等があっていないかも?ということでいらすとやさんの画像をダウンロードしてGithub上に配置し、取得しようとしてもダメ。
諦めてぐるなびAPIから取得する項目は[店名][住所][URL]のみに絞りました。
あとたぶんPHPが理解できていないだけだと思いますが、
switch文を使うと反応しなくなったので諦めてif文で対応しました。
次やりたいこと
- 勉強もかねてPOSTデータのテスト環境を構築したい。(上記は毎回スマホでテストしていたので大変だった)
- ぐるなびAPIのレスポンスが一部だけ無い場合でも、LINE側にレスポンスが返せるようにする。
- Docomo雑談対話APIの実装
- 今回省略したGithubとCloud9とherokuを連携する方式についても記事化する。
感想
「ちょっとLINE BOT遊びで作ってみたんすよ」と言えるのは楽しいです。