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
-
次の記事
記事がありません
コメントを書く