LoginSignup
43
43

More than 5 years have passed since last update.

LINE BOT APIでBOTのお友達全員にメッセージを送ってみる

Last updated at Posted at 2016-04-11

LINEのBOT API Trial Account 先着10,000名様まで先行申し込み受付中、という言葉につられて登録したので試してみました。

基本的にはbotとお友達になって、botに何か話しかけたら答える、みたいな1対1の対話が想定のようで、メッセージを受信したら送信者に何かを送るという流れのようです。
なので、お友達全員にメッセージを一斉送信、ということがしたかったのですが、友達のID一覧取得、みたいのがないので、お友達になった時(operation requestを受信した時)に保存しておくようにしました。(配列をjson_encodeしてファイルに保存してます。)

LINEのChannels管理画面みたいなので自分のBOTのChannel IDとかSecretとかMIDとかを確認して、Callback URL に https://myhost.mydomain.jp:443/linebot/rcv みたいに受信するURLを設定します。

諸事情によりCodeIgniter2で書いてます。

controllers/linebot.php
class Linebot extends CI_Controller {

    private $_channel_id = '自分のBOTのChannel ID';
    private $_channel_secret = '自分のBOTのChannel Secret';
    private $_channel_mid = '自分のBOTのMID';

    private $_allow_ip = 'メッセージ送信を許可するIPアドレス(自分のIPとか)';
    private $_save_path;

    public function __construct()
    {
        parent::__construct();
        $this->_save_path = APPPATH . 'logs/line_friends';
    }

    public function rcv()
    {
        $input = file_get_contents('php://input');
        log_message('debug', $input);
        $json = json_decode($input);
        if ( ! isset($json->result) OR ! is_array($json->result))
        {
            log_message('error', 'no result');
            $this->output->set_status_header('400');
            return;
        }
        foreach ($json->result as $result) {
            if ( ! isset($result->content->opType))
            {
                // operation requestじゃない(メッセージとかが送られてきた)場合はスタンプをランダムで返す
                $this->_send_sticker(rand(1, 17), 1, $result->content->from);
                continue;
            }
            // operation requestの場合
            switch ($result->content->opType)
            {
                case 4:
                    // added as friend
                    if ($this->_set_friend($result->content->params[0]) !== FALSE) {
                        $this->_send_text('ようこそ!', $result->content->params[0]);
                    }
                    break;
                case 8:
                    // blocked account
                    $this->_del_friend($result->content->params[0]);
                    break;
            }
        }
        $this->output->set_status_header('200');
    }

    public function snd($msg)
    {
        // 指定したIPからのアクセスのみ許可する
        $remote_addr = $this->input->server('HTTP_X_FORWARDED_FOR');
        if ($remote_addr === FALSE)
        {
            $remote_addr = $this->input->server('REMOTE_ADDR');
        }
        if (empty($remote_addr))
        {
            log_message('error', 'no remote address');
            show_error('no remote address');
        }
        if ($remote_addr !== $this->_allow_ip)
        {
            log_message('error', 'invalid access: ' . $remote_addr);
            show_error('invalid access: ' . $remote_addr);
        }
        $this->_send_text(urldecode($msg));
        $this->output->set_status_header('200');
    }

    private function _get_friends()
    {
        if ( ! file_exists($this->_save_path))
        {
            return array();
        }
        return json_decode(file_get_contents($this->_save_path));
    }

    private function _set_friend($mid)
    {
        $friends = $this->_get_friends();
        if ( ! in_array($mid, $friends))
        {
            $friends[] = $mid;
            return file_put_contents($this->_save_path, json_encode($friends));
        }
    }

    private function _del_friend($mid)
    {
        $friends = $this->_get_friends();
        if (($key = array_search($mid, $friends)) !== FALSE)
        {
            unset($friends[$key]);
            return file_put_contents($this->_save_path, json_encode(array_values($friends)));
        }
    }

    private function _send_text($message, $mid_arr = NULL)
    {
        $content = array(
                'contentType' => 1,
                'toType' => 1,
                'text' => $message
        );
        return $this->_send_message($content, $mid_arr);
    }

    private function _send_sticker($stkid, $stkpkgid, $mid_arr = NULL)
    {
        $content = array(
                'contentType' => 8,
                'toType' => 1,
                'contentMetadata' => array(
                        'STKID' => (string)$stkid,
                        'STKPKGID' => (string)$stkpkgid
                )
        );
        return $this->_send_message($content, $mid_arr);
    }

    private function _send_message($content, $mid_arr = NULL)
    {
        if (is_string($mid_arr))
        {
            $mid_arr = array($mid_arr);
        }
        elseif (is_null($mid_arr)) {
            $mid_arr = $this->_get_friends();
        }
        if (empty($mid_arr))
        {
            return FALSE;
        }
        $url = 'https://trialbot-api.line.me/v1/events';
        $headers = array(
                'Content-Type: application/json; charser=UTF-8',
                'X-Line-ChannelID: ' . $this->_channel_id,
                'X-Line-ChannelSecret: ' . $this->_channel_secret,
                'X-Line-Trusted-User-With-ACL: ' . $this->_channel_mid
        );
        $post = array(
                'to' => $mid_arr,
                'toChannel' => 1383378250,
                'eventType' => '138311608800106203',
                'content' => $content
        );

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post, JSON_UNESCAPED_UNICODE));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        $ret = curl_exec($ch);
        log_message('debug', $ret);
        return $ret;
    }
}

なにか話しかけられた時に何もないのも寂しいので、17種類のスタンプをランダムで返すようにしました。
(スタンプのIDとかは、API referenceにsticker listのExcelファイルがあります。)

https://myhost.mydomain.jp/linebot/snd/Hello
とかで『Hello』をBOTのお友達全員に送ることができます。
日本語とか記号はURLエンコードする必要があります。(日本語はブラウザがやってくれるかも)

toTypeが『1 = user』って書いてあって、1しか書いてないんだけど、他にも違うタイプがあるのか、これからできるようになるのか…。
グループにも送信できるといいんだけどなー。

43
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
43