Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
29
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

LINE BOT API + Laravel5(PHP)でのリッチメッセージ送信方法

概要

Laravel5でLINE BOTのリッチメッセージを送信する方法をまとめた。

BOT API Trial Accountの取得方法や設定方法については、
既に沢山記事があるのでそちらを参照のこと。
(個人的にはこちらの記事を参考にさせていただきました)

使うもの

  • Laravel5
  • line-bot-sdk-php
    • BOTのメッセージ送信全般の実装が楽になる。特にリッチメッセージのマークアップ部分。
  • Intervention Image
    • 画像の生成・加工が簡単に行えるライブラリ。今回はリッチメッセージ全体画像の生成に利用。

リッチメッセージとは

line-bot-api-v1ドキュメントにある通り、全体が画像となっているメッセージ。
画像の任意領域にタップ時のアクション(webリンク or メッセージ送信)を設定できる。

今回は、下記のようなリッチメッセージを送信する方法の例を紹介。
(実際には画像中の文字はもっと小さくなります。。)

Slack for iOS Upload-2.png.png
・ユーザーが送信したメッセージを白領域に書く。
・白領域をタップするとwebページが開く(webアクション)。
・黒領域をタップすると'user message'というメッセージをユーザーに送信させる(sendMessageアクション)。

リッチメッセージのデータの流れ

リッチメッセージでは下記の図のようなリクエストが発生する。

Qiita投稿用2 (1).png

今回は便宜上、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にも下記を追記。

config/app.php
'providers' => array(
    // ...
    'Intervention\Image\ImageServiceProvider',
)

...

'aliases' => array(
    // ...
    'Image'     => 'Intervention\Image\Facades\Image',
)

SDKを利用してリッチメッセージ送信

line-bot-sdk-phpのREADME「LINEBot#sendRichMessage」を参考にしながら実装。

routes.php
// LINEから飛んでくるリクエストはpost
Route::post('richmessage', 'RichMessageController@index');
RichMessageController.php
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/{ユーザーが送信したメッセージ}

参考:line-bot-api-v1ドキュメント

全体画像のURL = <ベースURL>/<横幅(1040|700|460|300|240)>

実装は下記のような感じ。

routes.php
// URL末尾が数字
Route::get('img/{message}/{img_width}', 'ImgController@index')->where('img_width', '[0-9]+');
ImageController.php
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"となってしまう。
app/Http/Kernel.php
protected $middleware = [
    // ...
    'App\Http\Middleware\VerifyCsrfToken', // ←この行は削除
];

参考

https://speakerdeck.com/yusukebe/sumahoshi-dai-falsebotapurifalsetukurifang
(かなり参考にさせていただきました)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
29
Help us understand the problem. What are the problem?