前回こんな記事を書きました。
田村ゆかりさん公式サイトの通知を LINE BOT API で作ってみた。 #yukarin
この記事では友達追加をしてもらった際にメッセージを送ってもらって
mid(ユーザーID)を保存するという処理だったのですが、友人が
「友達追加時にもCallbackされるからメッセージ送らなくてもmid保存できるよ」と教えてもらいました。
試しに中身を覗いてみた
{ "result": [ { "content": { "message": null, "opType": 4, "params": [ "", null, null ], "reqSeq": 0, "revision": 350 }, "createdTime": 1461579375186, "eventType": "138311609100106403", "from": "", "fromChannel": , "id": "", "to": [ "" ], "toChannel": 1462173514 } ] }
注目するのは “opType”: 4 です。
友達追加時は 4
ブロック時は 8 が返ってきます。
LINE Developers にも記載されてました…。
友達追加時に、midを保存。
ブロック時にmidを削除といったことが可能ですね。
ということでPHPで友達追加時に相手のmidを保存するコードは以下に。
<?php /** * $otType は 登録時とブロック時にリクエストが飛んで来る。 * 4 = 友だち追加 * 8 = ブロック */ $f_mids = file_get_contents('./mids'); $content = file_get_contents('php://input'); $content = json_decode($content); $opType = $content->result[0]->content->opType; $mid = trim($content->result[0]->from); /* * 最初の登録 */ if ($opType === 4 && strpos($f_mids, $mid) === false) { $text = "ご登録が完了しました。\r\n田村ゆかりさん公式サイトが更新される度にLINEでお知らせいたします。"; $response_format_text = ['contentType' => 1, "toType" => 1, "text" => $text]; $post_data = [ "to" => [$mid], "toChannel" => "1383378250", "eventType" => "138311608800106203", "content" => $response_format_text ]; toPost($post_data); file_put_contents('mids', $mid . "\r\n", FILE_APPEND | LOCK_EX); die(); }
この一々保存するの面倒なので一斉送信できるAPIを公開してくだしゃい
ふとコードを書き直してる時にセキュリティやばくね?ってなって思ってた時に署名とかこないの?って思ったら署名乗ってくるみたいですね…。
Qiitaとか9割方、署名確認してないです。
LINEからのアクセスか検証する
LINEからのアクセスの場合、ヘッダーに X-LINE-CHANNELSIGNATURE があり
これをbase64デコードしたもの + LINEきたらjsonの内容を LINE BUSINESS CENTER で確認できる ChannelSecret をキーとしたHMAC方式SHA256アルゴリズムのハッシュ値が
合致すればOKということです。
/* LINE からのアクセスか検証 */ $channel_secret = "<チャンネルシークレット>"; $headers = getallheaders(); $content = file_get_contents('php://input'); if (base64_decode($headers['X-LINE-CHANNELSIGNATURE']) === hash_hmac('sha256', $content, $channel_secret, true)) { $f_mids = file_get_contents('./mids'); $opType = $content->result[0]->content->opType; $mid = trim($content->result[0]->from); } else { die(); }
ちなみに nginx だとPHPの getallheaders 関数が使えないので
function getallheaders() { $headers = ''; foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) == 'HTTP_') { $headers[strtoupper(str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($name, 5)))))] = $value; } } return $headers; }
よく見るこんなのを使います。