LINE BOT API Trialでできる全ての事を試してみた

4/7 18:00頃にLINEの「BOT API Trial Account」が無償提供されたと聞いてとりあえず触ってみたら出来る事は結構少なかったので勢いで全て試してみた。

**[追記 4/14 9:28]**
[Facebook Messenger Platform BETAでできる全ての事を試してみた（LINE BOT APIとの比較あり）](http://qiita.com/betchi/items/539f5e32cd9a9c8d2db4)も合わせてどうぞ。


**[追記 4/9 11:49]**
**現在、巷で話題のLet's Encrypt問題以外でコールバックがコールされない問題があるらしいのでご注意を。**

**[追記 4/9 12:49]**
**上記の問題は解決した模様。**


## まずはアカウント登録

※先着10,000名って少ない気がするけどまだ登録できるって事はそんなに人気ないのかな。
https://business.line.me/ja/products/4/introduction


> BOT API が利用開始になる前に、その一部の機能をお試しいただけます。
お試しいただける機能は BOT API のユーザーコミュニケーション機能となります。

一部の機能って事はこれからもっと増えるのね。
ここで作成したTrialのbotアカウントの「友だち」登録可能なユーザー数は50人までらしい。

とりあえず登録完了するとこんな感じでTRIAL_BOTアカウントができる。

![FireShot_Capture_2_-_LINE_developers_-_https___developers_line_me_channels_1461727885_png.png](https://qiita-image-store.s3.amazonaws.com/0/39177/886bb0a7-677f-a62e-4669-ec4eedead34a.png)


アカウント作成時に生成された以下の情報はAPIリクエスト時にリクエストヘッダに設定する事になる。トークンを取得してどうこうするAPIではないので楽。

* Channel ID
* Channel Secret
* MID

当然ながら登録された友達から送られてきたメッセージに対して何も反応する必要がなければ「Callback URL」を実装しなくても問題ない。BOTアカウントから一方的なメッセージ送信等は可能。ただしそれではBOTの意味がないけど。

あと、「Callback URL」はSSL通信必須なので注意。

## BOT APIでできる事

| API | 内容 |
|:-----------|:------------|
|Sending messages|メッセージ送信（テキスト、JPG画像、mp4動画、m4a音声、ロケーション、スタンプ）|
|Sending multiple messages|上記のメッセージを纏めて複数送信|
|Sending rich messages|リッチメッセージ送信（画像の指定した場所をタップすると指定したリンク先を表示）|
|Getting message content|受信したメッセージが画像、動画、及び音声であった場合にそのバイナリデータを取得（一定期間を過ぎるとLINEのプラットフォームからは削除される）|
|Getting previews of message content|上記のサムネイル画像を取得|
|Getting user profile information|ユーザID(MID)をキーにユーザ情報を取得|

ちなみに「Sending messages」でスタンプを送信する時に必要なSTKID、STKPKGID、STKVERはどこかで公開されているのだろうか。スタンプ製作者しか知らないものなのだろうか。よくわからずスタンプ送信だけ試せていない。

[追記]4/9 14:26
STKID、STKPKGID、STKVERは一回自分でボットに送ってコールバックの中身解析すればわかるじゃん。アホでした。でもスタンプは送れない。

[追記]4/9 16:24
上記は有料スタンプだったから送れなかっただけだった・・・
無料スタンプであれば送れた。(例えば `STKVER":"100","STKID":"108","STKPKGID":"1"` ）

## API確認が目的のBOTを作ってみた
ユーザから、
`image` というテキストメッセージが送信されると画像が、
`video` というテキストメッセージが送信されると動画が、
`audio` というテキストメッセージが送信されると音声が、
`location` というテキストメッセージが送信されると位置情報が、
`sticker` というテキストメッセージが送信されるとスタンプが、（実際にはこれはできてない）
`multi` というテキストメッセージが送信されると上記全てが、
上記以外が送信されると「なるほど。「（ユーザが送信したメッセージ）」という事ですね。さすがです。」が、
BOTから送信される仕様。

ログは無茶をしてerror_log関数で出力してる。
送信してきたユーザ情報もerror_logで出力。

サクッと作ったものだけど一応利用できるAPIは全て網羅してる。

```php:callback.php
<?php
error_log("callback start.");

// アカウント情報設定
$channel_id = "[チャンネルID]";
$channel_secret = "[チャンネルシークレット]";
$mid = "[MID]";

// リソースURL設定
$original_content_url_for_image = "[画像URL]";
$preview_image_url_for_image = "[サムネイル画像URL]";
$original_content_url_for_video = "[動画URL]";
$preview_image_url_for_video = "[動画のサムネイル画像URL]";
$original_content_url_for_audio = "[音声URL]";
$download_url_for_rich = "[リッチ画像URL]";

// メッセージ受信
$json_string = file_get_contents('php://input');
$json_object = json_decode($json_string);
$content = $json_object->result{0}->content;
$text = $content->text;
$from = $content->from;
$message_id = $content->id;
$content_type = $content->contentType;

// ユーザ情報取得
api_get_user_profile_request($from);

// メッセージが画像、動画、音声であれば保存
if (in_array($content_type, array(2, 3, 4))) {
    api_get_message_content_request($message_id);
}

// メッセージコンテンツ生成
$image_content = <<< EOM
        "contentType":2,
        "originalContentUrl":"{$original_content_url_for_image}",
        "previewImageUrl":"{$preview_image_url_for_image}"
EOM;
$video_content = <<< EOM
        "contentType":3,
        "originalContentUrl":"{$original_content_url_for_video}",
        "previewImageUrl":"{$preview_image_url_for_video}"
EOM;
$audio_content = <<< EOM
        "contentType":4,
        "originalContentUrl":"{$original_content_url_for_audio}",
        "contentMetadata":{
            "AUDLEN":"240000"
        }
EOM;
$location_content = <<< EOM
        "contentType":7,
        "text":"Convention center",
        "location":{
            "title":"Convention center",
            "latitude":35.61823286112982,
            "longitude":139.72824096679688
        }
EOM;
$sticker_content = <<< EOM
        "contentType":8,
        "contentMetadata":{
          "STKID":"100",
          "STKPKGID":"1",
          "STKVER":"100"
        }
EOM;
$rich_content = <<< EOM
        "contentType": 12,
        "contentMetadata": {
            "DOWNLOAD_URL": "{$download_url_for_rich}",
            "SPEC_REV": "1",
            "ALT_TEXT": "Alt Text.",
            "MARKUP_JSON": "{\"canvas\":{\"width\": 1040, \"height\": 1040, \"initialScene\": \"scene1\"},\"images\":{\"image1\": {\"x\": 0, \"y\": 0, \"w\": 1040, \"h\": 1040}},\"actions\": {\"link1\": {\"type\": \"web\",\"text\": \"Open link1.\",\"params\": {\"linkUri\": \"http://line.me/\"}},\"link2\": {\"type\": \"web\",\"text\": \"Open link2.\",\"params\": {\"linkUri\": \"http://linecorp.com\"}}},\"scenes\":{\"scene1\": {\"draws\": [{\"image\": \"image1\", \"x\": 0, \"y\": 0, \"w\": 1040, \"h\": 1040}],\"listeners\": [{\"type\": \"touch\", \"params\": [0, 0, 1040, 720], \"action\": \"link1\"}, {\"type\": \"touch\", \"params\": [0, 720, 1040, 720], \"action\": \"link2\"}]}}}"
        }
EOM;

// 受信メッセージに応じて返すメッセージを変更
$event_type = "138311608800106203";
if ($text == "image") {
    $content = $image_content;
} else if ($text == "video") {
    $content = $video_content;
} else if ($text == "audio") {
    $content = $audio_content;
} else if ($text == "location") {
    $content = $location_content;
} else if ($text == "sticker") {
    $content = $sticker_content;
} else if ($text == "rich") {
    $content = $rich_content;
} else if ($text == "multi") {
    $event_type = "140177271400161403";
$content = <<< EOM
    "messageNotified": 0,
    "messages": [
        {{$image_content}},
        {{$video_content}},
        {{$audio_content}},
        {{$location_content}},
        {{$sticker_content}},
        {{$rich_content}}
    ]
EOM;
} else { // 上記以外はtext送信
    if ($content_type != 1) {
        $text = "テキスト以外";
    }
$content = <<< EOM
        "contentType":1,
        "text":"なるほど。「{$text}」という事ですね。さすがです。"
EOM;
}
$post = <<< EOM
{
    "to":["{$from}"],
    "toChannel":1383378250,
    "eventType":"{$event_type}",
    "content":{
        "toType":1,
        {$content}
    }
}
EOM;

api_post_request("/v1/events", $post);

error_log("callback end.");

function api_post_request($path, $post) {
    $url = "https://trialbot-api.line.me{$path}";
    $headers = array(
        "Content-Type: application/json",
        "X-Line-ChannelID: {$GLOBALS['channel_id']}",
        "X-Line-ChannelSecret: {$GLOBALS['channel_secret']}",
        "X-Line-Trusted-User-With-ACL: {$GLOBALS['mid']}"
    );

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $output = curl_exec($curl);
    error_log($output);
}

function api_get_user_profile_request($mid) {
    $url = "https://trialbot-api.line.me/v1/profiles?mids={$mid}";
    $headers = array(
        "X-Line-ChannelID: {$GLOBALS['channel_id']}",
        "X-Line-ChannelSecret: {$GLOBALS['channel_secret']}",
        "X-Line-Trusted-User-With-ACL: {$GLOBALS['mid']}"
    ); 

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $output = curl_exec($curl);
    error_log($output);
}

function api_get_message_content_request($message_id) {
    $url = "https://trialbot-api.line.me/v1/bot/message/{$message_id}/content";
    $headers = array(
        "X-Line-ChannelID: {$GLOBALS['channel_id']}",
        "X-Line-ChannelSecret: {$GLOBALS['channel_secret']}",
        "X-Line-Trusted-User-With-ACL: {$GLOBALS['mid']}"
    ); 

    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $output = curl_exec($curl);
    file_put_contents("/tmp/{$message_id}", $output);
}
```