6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【LINE Messaging API】PHP素人がコピペを駆使してラーメン屋BOTを作ってみた。

Last updated at Posted at 2017-06-05

概要

LINE BOTを使って、位置情報を送ると周辺のラーメン情報を答えさせます。
先人達が数々のすばらしい記事をあげているので、
何番煎じだ?というところですが自分メモとして投稿します。

結果としてとりあえず動いていますが、
ソースを完全に理解できていない部分もあり、まだまだ勉強中です。
不備不足をご指摘いただけると助かります。

環境や利用サービス

windows7 64bit
LINE API
ぐるなびAPI
PHP
heroku

参考記事

実装手順

  1. LINEBOTアカウント取得
  2. ぐるなびAPI取得
  3. herokuアカウント取得
  4. こちらの記事を参考にサンプルプログラムソースをherokuにデプロイ
  5. Heroku CLI.をインストールする
  6. リモートリポジトリをクローンする
  7. こちらの記事を参考にcallback.phpを編集する(ソースは後述)
  8. 編集したcallback.phpをherokuにPUSHする
  9. herokuの環境変数※1.にぐるなびAPIとLINEのアクセスキー(gnavi_access_key、LINE_CHANNEL_ACCESS_TOKEN)を登録する
  10. 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.)。
そこから少しずつ改修→テスト→改修といった流れで実装していきました。

#ソースファイル

callback.php
<?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遊びで作ってみたんすよ」と言えるのは楽しいです。

6
6
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?