概要
Laravel5でLINE BOTのリッチメッセージを送信する方法をまとめた。
※BOT API Trial Accountの取得方法や設定方法については、
既に沢山記事があるのでそちらを参照のこと。
(個人的にはこちらの記事を参考にさせていただきました)
使うもの
- Laravel5
-
line-bot-sdk-php
- BOTのメッセージ送信全般の実装が楽になる。特にリッチメッセージのマークアップ部分。
-
Intervention Image
- 画像の生成・加工が簡単に行えるライブラリ。今回はリッチメッセージ全体画像の生成に利用。
リッチメッセージとは
line-bot-api-v1ドキュメントにある通り、全体が画像となっているメッセージ。
画像の任意領域にタップ時のアクション(webリンク or メッセージ送信)を設定できる。
今回は、下記のようなリッチメッセージを送信する方法の例を紹介。
(実際には画像中の文字はもっと小さくなります。。)
・ユーザーが送信したメッセージを白領域に書く。
・白領域をタップするとwebページが開く(webアクション)。
・黒領域をタップすると'user message'というメッセージをユーザーに送信させる(sendMessageアクション)。
リッチメッセージのデータの流れ
リッチメッセージでは下記の図のようなリクエストが発生する。
今回は便宜上、3の画像リクエストの度に画像を生成・出力する構成で実装。
(本運用するなら1の時点で画像生成・ストレージ保存、とか、、?)
line-bot-sdk-phpの導入
READMEに書いてある通り、下記コマンドでLaravelにインストール。
composer require linecorp/line-bot-sdk
Intervention Imageの導入
Installationに書いてある通り、下記コマンドでインストール。
composer require intervention/image
php artisan vendor:publish --provider="Intervention\Image\ImageServiceProviderLaravel5"
app.phpにも下記を追記。
'providers' => array(
// ...
'Intervention\Image\ImageServiceProvider',
)
...
'aliases' => array(
// ...
'Image' => 'Intervention\Image\Facades\Image',
)
SDKを利用してリッチメッセージ送信
line-bot-sdk-phpのREADME「LINEBot#sendRichMessage」を参考にしながら実装。
// LINEから飛んでくるリクエストはpost
Route::post('richmessage', 'RichMessageController@index');
use LINE\LINEBot\HTTPClient\GuzzleHTTPClient;
use LINE\LINEBot\Message\RichMessage\Markup;
use Request;
class RichMessageController extends Controller
{
public function index()
{
// ユーザーから送信された情報の中から"from"を取得
$request = Request::all();
$from = $request['result'][0]['content']['from'];
// チャネル等の設定
$config = [
'channelId' => 'アカウント管理画面から取得',
'channelSecret' => 'アカウント管理画面から取得',
'channelMid' => 'アカウント管理画面から取得',
];
$bot = new LINEBot($config, new GuzzleHTTPClient($config));
// リッチメッセージのマークアップ
$markup = (new Markup(1040))
// リッチメッセージの上半分がタップされた時はexample.comを開く
->setAction('OpenExampleCom', 'openexamplecom', 'https://example.com/')
->addListener('OpenExampleCom', 0, 0, 1040, 520)
// リッチメッセージの下半分がタップされた時はユーザーに'user message'というメッセージを送信させる
->setAction('GetUserToSendMessage', 'user message', '', 'sendMessage')
->addListener('GetUserToSendMessage', 0, 520, 1040, 1040);
// 画像のベースURLを動的に生成
$img_base_url = 'https://myapp.com/img/' . urlencode($request['result'][0]['content']['text']);
// リッチメッセージ送信
$bot->sendRichMessage($from, $img_base_url, 'Alt text', $markup);
}
}
※ユーザーにメッセージを送信させる場合、setActionの第4引数に'sendMessage'を指定するが、
webリンクの場合はデフォルト値で'web'が入るため指定しなくてOK.
詳細はSDKの下記ソースを参照。
https://github.com/line/line-bot-sdk-php/blob/master/src/LINEBot/Message/RichMessage/Markup.php#L80
リッチメッセージ全体画像を動的に生成
sendRichMessage第2引数はリッチメッセージ全体画像のベースURLであり、
今回の場合、LINE側から下記のようにリクエストされる。
https://myapp.com/img/{ユーザーが送信したメッセージ}/1040 →アプリ側で幅1040pxの画像を出力
https://myapp.com/img/{ユーザーが送信したメッセージ}/700 →アプリ側で幅700pxの画像を出力
(他サイズも同様)
※ベースURL = https://myapp.com/img/{ユーザーが送信したメッセージ}
全体画像のURL = <ベースURL>/<横幅(1040|700|460|300|240)>
実装は下記のような感じ。
// URL末尾が数字
Route::get('img/{message}/{img_width}', 'ImgController@index')->where('img_width', '[0-9]+');
use Intervention\Image\ImageManagerStatic as Image;
class ImgController extends Controller
{
public function index($message, $img_width)
{
// ベースの白い全体画像を生成(今回は正方形とする)
$base_img = Image::canvas($img_width, $img_width, '#ffffff');
// 全体画像にユーザーが送信したメッセージを挿入
$base_img->text($message, $img_width/2, $img_width/4, function($font) {
$font->color('#000000');
$font->align('center');
});
// 黒領域の画像を生成
$black_img = Image::canvas($img_width, $img_width / 2, '#000000');
// 黒領域の画像に'SendMessage'という文字を挿入
$black_img->text('SendMessage', $img_width/2, $img_width/4, function($font) {
$font->color('#ffffff');
$font->align('center');
});
// 全体画像の下部中央に貼り付け
$base_img->insert($black_img, 'bottom');
// 全体画像を出力
return $base_img->response();
}
}
※Intervention Imageのcanvas()やtext()の使い方はドキュメント参照。
動作確認
ここまで実装したら動くはず。
LINEアプリからBOTに適当なメッセージを送信してみて、リッチメッセージが返信されれば成功!
注意事項
- LINE側でリッチメッセージ全体画像をキャッシュしている模様(URL単位?)。
- キャッシュクリア方法は調査中。。
- 全体的にメッセージはURLエンコードしないと文字化けする模様。
- LaravelのMiddlewareのVerifyCsrfTokenを外さないと、LINEからpostされた時に"500 Internal Server Error"となってしまう。
protected $middleware = [
// ...
'App\Http\Middleware\VerifyCsrfToken', // ←この行は削除
];
参考
https://speakerdeck.com/yusukebe/sumahoshi-dai-falsebotapurifalsetukurifang
(かなり参考にさせていただきました)