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を編集します。
Route::post('line-callback', [LineBotController::class, 'callback'])->name('line.callback');
ここで設定した内容によってPOSTするURLが決まります。
URLが決まったら、LINE DevelopersサイトでWebhook URLの入力・検証するのをお忘れなく。
コントローラ
今回は「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への接続情報(アクセストークン、アクセスシークレット)を設定します。
今回は下記のようにしました。
<?php
return [
'line_token' => env('LINE_ACCESS_TOKEN', ''),
'line_secret' => env('LINE_CHANNEL_SECRET', ''),
];
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するようにしています。
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で読み込ませます。
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
// ~~~ 中略 ~~~
/** add */
App\Providers\LineBotProvider::class,
],
ここまでで、一先ず疎通はできる段階かなと思います。
この先で具体的な処理を書いていきます。
コントローラの修正
最初に作ったコントローラを修正します。
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
ここまでご覧頂き、ありがとうございました。