LaravelでLINE botを作る最低限の実装方法
はじめに
LaravelでLINEのボットを作成する際の最低限の実装手順です。
line-bot-sdkが昨年のアップデートで大幅に仕様が変わったらしく、ネットの記事だとうまくいかない部分があったので、一応現時点のバージョンでの方法を残しておきます。
前提
- php 8.1
- Laravel 10
- line-bot-sdk-php 9.5
ゴール
ユーザーが送ったメッセージをそのまま返信するボットを作る。
実装手順
全体の流れとしては、
- LINE Developersへ登録して必要なキーを取得
- Laravelにline-bot-sdkをインストール
- Webhookでメッセージを受け取って、そのまま返す
となります。
LINE Developersへ登録
LINE Developersではいくつかのサービスを提供していますが、今回はMessaging APIというサービスを使って実装します。
LINE Developers
https://developers.line.biz/ja/
Messaging API
https://developers.line.biz/ja/services/messaging-api/
プロバイダーとチャネルの作成
アカウントを登録したらプロバイダーとチャネルを作成します。
プロバイダー
事業やプロジェクト単位で作成します。1つのアカウントで複数作る事ができます。
チャネル
プロバイダーの中にチャネルを作成します。用途ごとにチャネルを分けて複数作る事ができます。
チャネルを作ると、チャネルシークレットとチャネルアクセストークンを取得できます。これは後ほどLaravelの.envで使用します。
Webhook URLの設定
Messaging APIは、ユーザーが友達追加したりメッセージを送った場合、イベントを送信します。その送信先URLを設定します。
「Webhookの利用」を有効にして、例えば以下のようなURLを設定します。
https://[ドメイン]/webhook/linebot
後ほど、LaravelでこのWebhookを受け取るようルーティング設定をします。
参考
開発環境でWebhookを利用する場合、http://localhostでは受け取れないので、ngrokなどのサービスを使って外部からのPOSTを受け取れるようにする必要があります。
Docker環境の場合ですが、ngrokについての記事を書いたので良かったら参考にしてください。
line-bot-sdkのインストール
LaravelでMessaging APIを簡単に使うために用意されたline-bot-sdkという公式のツールをインストールします。
(Laravel環境は各自事前に構築してください)
$ composer require linecorp/line-bot-sdk
line-bot-sdk-php
https://github.com/line/line-bot-sdk-php
チャネルシークレットとチャネルアクセストークンを設定
先程取得したチャネルシークレットとチャネルアクセストークンをLaravelの.envにセットします。
.env
LINE_CHANNEL_ID="" LINE_CHANNEL_SECRET="チャネルシークレット" LINE_CHANNEL_ACCESS_TOKEN="チャネルアクセストークン"
LINE_CHANNEL_IDは今回は使用しません。
.envの内容を直接コントローラーなどで取得するのは望ましくないので、configで一旦読み込んでおきます。configならどこでも良いですが、今回はservices.phpに追加しておきます。
config/services.php
return [ // 前後省略 'line' => [ 'id' => env('LINE_CHANNEL_ID'), 'secret' => env('LINE_CHANNEL_SECRET'), 'token' => env('LINE_CHANNEL_ACCESS_TOKEN'), ], ];
コントローラー作成
Webhookを処理するためのコントローラーを作成します。名前はなんでもいいです。
$ php artisan make:controller LineBotController
例えば、以下の内容で実装します。(コピペでOK)
各所にコメントを付けてあるので、参考にしてください。
namespace App\Http\Controllers; use Illuminate\Http\Request; use GuzzleHttp\Client; use LINE\Clients\MessagingApi\Configuration; use LINE\Clients\MessagingApi\Api\MessagingApiApi; use LINE\Clients\MessagingApi\Model\TextMessage; use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; use LINE\Clients\MessagingApi\ApiException; use LINE\Webhook\Model\MessageEvent; use LINE\Webhook\Model\TextMessageContent; use LINE\Parser\EventRequestParser; use Illuminate\Support\Facades\Log; class LineBotController extends Controller { public function reply(Request $request) { // チャネルシークレットとチャネルアクセストークンを読み込む $channelSecret = config('services.line.secret'); $channelToken = config('services.line.token'); // Webhookイベントを取得する $httpRequestBody = $request->getContent(); // 署名を検証する(Messaging APIから送られたものであるかチェック) $hash = hash_hmac('sha256', $httpRequestBody, $channelSecret, true); $signature = base64_encode($hash); if ($signature !== $request->header('X-Line-Signature')) return; // LINEBOTクライアントを作成 $client = new Client(); $config = new Configuration(); $config->setAccessToken($channelToken); // LINE Messaging APIを作成 $messagingApi = new MessagingApiApi( client: $client, config: $config, ); try { // イベントリクエストをパース $parsedEvents = EventRequestParser::parseEventRequest($httpRequestBody, $channelSecret, $signature); // イベントは配列(必ずしも1つとは限らない)で来るのでforeachで回す foreach ($parsedEvents->getEvents() as $event) { // メッセージイベント以外は無視 if (!($event instanceof MessageEvent)) continue; // メッセージを取得 $eventMessage = $event->getMessage(); // テキストメッセージ以外は無視 if (!($eventMessage instanceof TextMessageContent)) continue; // テキストメッセージを取得 $eventMessageText = $eventMessage->getText(); // 応答メッセージを作成 $message = new TextMessage([ 'type' => 'text', 'text' => $eventMessageText, ]); // 応答リクエストを作成 $request = new ReplyMessageRequest([ 'replyToken' => $event->getReplyToken(), 'messages' => [$message], // 配列である必要があります ]); // 応答リクエストを送信する $response = $messagingApi->replyMessageWithHttpInfo($request); // レスポンスをチェックする(エラーの場合の処理) $responseBody = $response[0]; $responseStatusCode = $response[1]; if ($responseStatusCode != 200) { throw new \Exception($responseBody); } } return; } catch (ApiException $e) { // エラー内容をログに出力 Log::error($e->getCode() . ':' . $e->getResponseBody()); } } }
ルーティング作成
WebhookのPOSTリクエストをコントローラーへ送ります。
routes/web.php
use Illuminate\Support\Facades\Route; use App\Http\Controllers\LineBotController; Route::post('webhook/linebot', [LineBotController::class, 'reply']);
CSRFトークンのチェックを解除
デフォルトではCSRF対策でcsrfトークンがないとPOSTを受け付けないようになっています。
Messaging APIから送られてくるWebhookは当然csrfトークンがないので、なくても受け取れるようにWebhookのルートを除外します。
app/Http/Middleware/VerifyCsrfToken.php
namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { /** * The URIs that should be excluded from CSRF verification. * * @var array<int, string> */ protected $except = [ 'webhook/*' // これを追加 ]; }
確認
実装は以上です。実際に動くか確認してみましょう。
LINE Developersのチャネルページの「Messaging API設定」を開きます。
Webhookの検証
Webhook設定の「検証」ボタンを押して、Webhookが正しく届いているかチェックします。
「成功」と表示されたらOKです。
実際に動作テスト
実際に動くかチェックしてみます。
「友達追加」用のQRコードをスマホで読み取って友達追加します。
「あいさつメッセージ」が届くはずです。
「あいさつメッセージ」の内容は変更できます。無効にもできます。
何かメッセージ(テキスト)を送ります。すぐに同じメッセージが返ってきたら成功です。
自動の「応答メッセージ」も一緒に返ってきますが、設定で無効にできます。
返ってこない場合は、どこかでエラーが出ています。Laravelのログを確認してみてください。
まとめ
今回は最低限の実装なので、実際に稼働させる上で必要な処理が出てくると思いますが、これをベースに肉付けしてもらえたらと思います。
LINE Developersのドキュメントは充実していて見やすいのですが、line-bot-sdkは簡単なマニュアルしかない?のでリポジトリ内のサンプルコードなどを参考にするしかないのですかね。。。
-
前の記事
Laravelのテストコードでcookieをモックする方法 2023.12.19
-
次の記事
記事がありません
コメントを書く