LINE Messaging APIがグループ内でユーザーを認識できるようになったのでトーク管理＆アルバム化Bot作ってみた

<img width="375" alt="IMG_1341.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/164153/f05afbf1-6c7f-816d-0034-4e41ec02af4e.png">

LINE Messaging APIがグループ内でユーザーを認識できるようになったので、前から作りたかったグループにBot入れとけばトーク全部保存しといてくれて、後から2016年度とかの区切りでトークをまとめてリアルなアルバムにして郵送してくれるようなサービスのデモを作ってみました。

# Botの準備

ググれば情報出てくるので適当に。または拙著「[LINE BOTを作ろう! Messaging APIを使ったチャットボットの基礎と利用例](https://www.amazon.co.jp//dp/4798150738)」を見て下さい。

[![book.png](https://qiita-image-store.s3.amazonaws.com/0/164153/68ebde6d-ce63-357a-5d2a-eb0c7dab3673.png)](https://www.amazon.co.jp//dp/4798150738)

# 実装

こんな感じ。暗号化やってないので適宜。

```index.php
// Composerでインストールしたライブラリを一括読み込み
require_once __DIR__ . '/vendor/autoload.php';

define('TABLE_NAME_MESSAGES', 'messages');

// アクセストークンを使いCurlHTTPClientをインスタンス化
$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(getenv('CHANNEL_ACCESS_TOKEN'));
// CurlHTTPClientとシークレットを使いLINEBotをインスタンス化
$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => getenv('CHANNEL_SECRET')]);
// LINE Messaging APIがリクエストに付与した署名を取得
$signature = $_SERVER['HTTP_' . \LINE\LINEBot\Constant\HTTPHeader::LINE_SIGNATURE];

// 署名が正当かチェック。正当であればリクエストをパースし配列へ
// 不正であれば例外の内容を出力
try {
  $events = $bot->parseEventRequest(file_get_contents('php://input'), $signature);
} catch(\LINE\LINEBot\Exception\InvalidSignatureException $e) {
  error_log('parseEventRequest failed. InvalidSignatureException => '.var_export($e, true));
} catch(\LINE\LINEBot\Exception\UnknownEventTypeException $e) {
  error_log('parseEventRequest failed. UnknownEventTypeException => '.var_export($e, true));
} catch(\LINE\LINEBot\Exception\UnknownMessageTypeException $e) {
  error_log('parseEventRequest failed. UnknownMessageTypeException => '.var_export($e, true));
} catch(\LINE\LINEBot\Exception\InvalidEventRequestException $e) {
  error_log('parseEventRequest failed. InvalidEventRequestException => '.var_export($e, true));
}

// 配列に格納された各イベントをループで処理
foreach ($events as $event) {
  // MessageEventクラスのインスタンスでなければ処理をスキップ
  if (!($event instanceof \LINE\LINEBot\Event\MessageEvent)) {
    error_log('Non message event has come');
    continue;
  }

  if(!$event->isGroupEvent()) {
    $bot->replyText($event->getReplyToken(), 'Add this Bot to Group.');
    continue;
  }

  if ($event instanceof \LINE\LINEBot\Event\MessageEvent\TextMessage) {

    if($event->getText() == 'cmd_album') {
      replyMultiMessage($bot, $event->getReplyToken(),
        new \LINE\LINEBot\MessageBuilder\TextMessageBuilder("以下のリンクをクリックするとトークのアルバムをプレビューできます。"),
        new \LINE\LINEBot\MessageBuilder\TextMessageBuilder("http://" . $_SERVER["HTTP_HOST"] . "/album/" . $event->getGroupId())
      );
      continue;
    }

    appendMessage($event->getUserId(), $event->getGroupId(), $event->getTimestamp(), $event->getMessageId(), $event->getMessageType(), $event->getText());
  } else if($event instanceof \LINE\LINEBot\Event\MessageEvent\ImageMessage) {

    $response = $bot->getMessageContent($event->getMessageId());
    $fileUrl = uploadImageToCloudAppThenGetUrl($response->getRawBody());
    appendMessage($event->getUserId(), $event->getGroupId(), $event->getTimestamp(), $event->getMessageId(), $event->getMessageType(), $fileUrl);

  } else if($event instanceof \LINE\LINEBot\Event\MessageEvent\StickerMessage) {
    appendMessage($event->getUserId(), $event->getGroupId(), $event->getTimestamp(), $event->getMessageId(), $event->getMessageType(), json_encode(array('packageID' => $event->getPackageId(), 'stickerId' => $event->getStickerId())));
  } else {
    $bot->replyText($event->getReplyToken(), '未対応のメッセージ形式');
  }
}

function appendMessage($userId, $groupId, $timestamp, $messageid, $messageType, $messageBody) {
  $dbh = dbConnection::getConnection();
  $sql = 'insert into '. TABLE_NAME_MESSAGES .' (userid, groupid, timestamp, messageid, messagetype, messagebody) values (?, ?, ?, ?, ?, ?) ';
  $sth = $dbh->prepare($sql);
  $sth->execute(array($userId, $groupId, $timestamp, $messageid, $messageType, $messageBody));

}

function uploadImageToCloudAppThenGetUrl($rawBody) {
  \Cloudinary::config(array(
    "cloud_name" => "xxxxxxxxx",
    "api_key" => "0123456789123",
    "api_secret" => "xxxxxxxxxxxxxxxxxx"
  ));

  $im = imagecreatefromstring($rawBody);
  $resultString = "";
  if ($im !== false) {
      $filename = uniqid();
      $directory_path = "tmp";
      if(!file_exists($directory_path)) {
      	if(mkdir($directory_path, 0777, true)) {
      		chmod($directory_path, 0777);
        }
      }
      imagejpeg($im, $directory_path. "/" . $filename . ".jpg", 75);
  } else {
      error_log("fail to create image.");
  }

  $path = dirname(__FILE__) . '/' . $directory_path. "/" . $filename . ".jpg";
  $result = \Cloudinary\Uploader::upload($path);
  error_log('result : ' . var_export($result, true));

  return $result['url'];
}
```

## データベース

DBを作ってユーザーID、グループID、タイムスタンプ、メッセージタイプ、メッセージの内容を格納できるテーブル作っときます。

## 格納

Eventから内容取ってDBに入れてくだけ。スタンプとか絵文字とかの処理は面倒なので後回し。

画像のみアップロードしてURLを格納しとく。

## 画像のアップロード

Herokuだと普通に保存しといてもデプロイする度に画像消えるのでCloudinaryのアドオン使いました。ある程度は無料でめちゃ簡単。

## プレビューページ

グループID受け取ってDBなめてトーク取り出して表示するだけ。

# デモ

グループに作って、家族とBotを招待します。Botは管理画面でグループに参加できるよう設定しておきましょう。

<img width="375" alt="IMG_1338.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/164153/760f9f9e-d194-5eb0-6c9e-40813c9d1666.png">

また、被招待側はグループへの参加と共にBotと友だちになっておく必要があります。ユーザーIDは友達になっていなくても取れるのですが、これがないとユーザー名やプロフィール画像等のProfile取ろうとしてもNot Foundになります。適当にトークします。

<img width="375" alt="IMG_1339.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/164153/12313a5d-0162-a8cf-9e4a-7271439fb759.png">

アルバムのプレビューをしたい時はコマンド送ります。

<img width="375" alt="IMG_1340.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/164153/af87c8da-8674-0701-34d2-5e5a6e5d6fd0.png">

プレビューが表示され、アルバムの注文ボタンが。タップすると印刷されたアルバムが郵送されます。背景とかレイアウトいじれるといいでしょうね。

![pureview.png](https://qiita-image-store.s3.amazonaws.com/0/164153/b4aaf09e-b5cf-d2b0-9544-e1582db44691.png)

# まとめ

相変わらずとても使いやすいAPIなので色々夢が広がります！アイディア色々あるので引き続き色々作ります。