LoginSignup
7
4

More than 1 year has passed since last update.

【!2022年最新!】Laravel9でLINE Messaging APIを使う

Posted at

Qiita初投稿です!お手柔らかにお願いします。

業務でLINE Messaging APIを使う機会はあったのですが、当時はPHP7.4だったりLaravelも8系だったりと
古い環境だったので、現在の最新バージョンでサンプルを作ってみました。
これからLaravelを使って、LINEBotなどを作ろうとしている方は参考になるかと思います。

準備

環境を準備します。
今回は以下の環境でやりました。(OSはWindowsでしたがMacでも同様です)

  • Windows10 Pro 22H2(WSL2インストール)
  • Docker Desktop 4.9.1 (81317)
  • 以下、docker内でインストール
    • PHP 8.1
    • Laravel v9.38.0
    • line-bot-sdk 7.6.1

docker環境の作り方やLaravelのインストール方法などは割愛します。
composerを使い、line-bot-sdkをインストールします。

composer require linecorp/line-bot-sdk

私はここでミスに気付かずに、古いバージョン(3.6)をインストールしてしまいました。
正常にインストール自体はできたので、問題ないと思ったんです。
ただ、ライブラリは記事執筆時点で7.6.1がリリースされているため、
私のように古いバージョンがインストールされてしまった方は注意して下さい。
packagistに情報がある通り

  • phpのバージョンは7.2以上
  • ext-curl、ext-json、ext-socketsが有効になっている

が必要です。

LINE DevelopersでMessaging APIを有効にする

この辺りの記事を参考に↓

LINEでMessaging APIを使えるように設定します。

いよいよ実装

それではいよいよ実装です。
似たような記事は他にもあると思うので、そちらも参考にしてみると良いでしょう。

ルーティング

routes/api.phpを編集します。

routes/api.php
Route::post('line-callback', [LineBotController::class, 'callback'])->name('line.callback');

ここで設定した内容によってPOSTするURLが決まります。
URLが決まったら、LINE DevelopersサイトでWebhook URLの入力・検証するのをお忘れなく。

コントローラ

今回は「app\Http\Controllers\Api\Line\LineBotController.php」とします。

app\Http\Controllers\Api\Line\LineBotController.php
class LineBotController extends Controller
{
    public function callback(LINEBot $bot, Request $request): JsonResponse
    {
        return response()->json('success');
    }
}

LINEBotクラスのインスタンスをメソッドインジェクションしています。
後述で解説します。

LINEに接続するための環境変数設定

.envファイルを用意し、LINEへの接続情報(アクセストークン、アクセスシークレット)を設定します。
今回は下記のようにしました。

config/const.php
<?php

return [
    'line_token' => env('LINE_ACCESS_TOKEN', ''),
    'line_secret' => env('LINE_CHANNEL_SECRET', ''),
];

.env
APP_NAME=laravel-linebot-sample
APP_ENV=local
APP_KEY="base64:hogehogehoge..."
APP_DEBUG=true
APP_URL=http://localhost

 ~~~ 中略 ~~~

LINE_ACCESS_TOKEN=aaaaaaa
LINE_CHANNEL_SECRET=bbbbbb

ここも、古いバージョンのline-bot-sdkをインストールしてしまったことで
config/const.phpを作り、環境変数を代入するという作り方をしたのですが
最新版はenvの設定のみで動くようになっています。
vendor\linecorp\line-bot-sdk\src\Laravel\config\line-bot.php
というファイルがありますので、そちらを覗くと

return [
    'channel_access_token' => env('LINE_BOT_CHANNEL_ACCESS_TOKEN'),
    'channel_secret' => env('LINE_BOT_CHANNEL_SECRET'),
];

と定義されていますので、そちらに合わせてenvを作成してください(私も後で直したい・・・)

サービスプロバイダを登録する

コントローラの解説部分で、LINEBotクラスのインスタンスをメソッドインジェクションしている
と書きましたが、サービスプロバイダを使ってDIするようにしています。

app\Providers\LineBotProvider.php
class LineBotProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(LINEBot::class, function () {
            $httpClient = new CurlHTTPClient(config('const.line_token'));
            return new LINEBot($httpClient, ['channelSecret' => config('const.line_secret')]);
        });
    }

}

Controllerやビジネスロジック発動の度に毎度LINEBotインスタンスを作るのが面倒だったので
singletonで必ず1度初期化するようにしてます。
このあたりは個人の好みですので、初学者の方など、まだDIの仕組みやLaravelFrameworkに慣れていない方は
ロジック側でnewする形でも良いでしょう。

サービスプロバイダを作ったら、config\app.phpで読み込ませます。

config\app.php
'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,

     // ~~~ 中略 ~~~

        /** add */
        App\Providers\LineBotProvider::class,

    ],

ここまでで、一先ず疎通はできる段階かなと思います。
この先で具体的な処理を書いていきます。

コントローラの修正

最初に作ったコントローラを修正します。

app\Http\Controllers\Api\Line\LineBotController.php
class LineBotController extends Controller
{
    public function callback(LINEBot $bot, Request $request): JsonResponse
    {
        // Line Signature Check
        $signature = $request->header(HTTPHeader::LINE_SIGNATURE);
        if (empty($signature)) {
            return abort(400, 'Bad Request');
        }

        try {
            $events = $bot->parseEventRequest($request->getContent(), $signature);

            foreach ($events as $event) {

                if ($event instanceof FollowEvent) {
                    // 友達登録時の処理
                } elseif ($event instanceof TextMessage) {
                    // テキストメッセージが送られてきた時の処理
                } elseif ($event instanceof ImageMessage) {
                    // 画像メッセージが送られてきた時の処理
                } elseif ($event instanceof PostbackEvent) {
                    // ポストバックが来た時の処理
                } elseif ($event instanceof UnfollowEvent) {
                    // 友達解除時の処理
                }
            }
        } catch (Throwable $th) {
            logger()->error($th->getMessage());
            logger()->error($th->getTraceAsString());
        }
        

        return response()->json('success');
    }
}

一応、try~catchブロックで主処理を囲んでます。
先ず、最初に「シグネチャチェック」というものを実行します。
LINEサーバからwebhookされてきたものが正しいかどうかチェックする処理です。
必須というわけでは無いのですが、LINE Messaging API開発ガイドラインに従い、実装します。
https://developers.line.biz/ja/docs/messaging-api/development-guidelines/

次にevent情報を受け取り、foreachループ内で処理します。
LINEは「Webhookイベントオブジェクト」という形でデータを送信してきます。
この「Webhookイベントオブジェクト」は配列、且つ順番を保持しません(元を辿るとjson形式になります)
詳しくはこちらの資料を参照してみてください。
https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects

配列で受け取った後は、単一のeventオブジェクトがどんな処理なのかを判定します。
line-bot-sdkでイベントをパースした場合、それぞれのクラスのオブジェクトに変化します。

  • 友達登録:FollowEvent
  • 友達解除:UnfollowEvent
  • テキストメッセージ:MessageEvent\TextMessage
  • 画像メッセージ:MessageEvent\ImageMessage

というような感じです。今回のケースでは、変数$eventの「型」がどのクラスのものかで種類を判定します。
後は、それぞれのイベントで自由にロジックを組むと良いでしょう。

以上です。GitHubに実装したものを置いていますので
最終形がどんなものになるのか、気になる方はそちらもご覧ください。
実際に友達登録してみて、動作を試すこともできます。
https://github.com/engineer-yone3/laravel-linebot-sample

ここまでご覧頂き、ありがとうございました。

7
4
0

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
7
4