読者です 読者をやめる 読者になる 読者になる

妄想まとめ

研究とかWebセキュとか時事ネタとか。 @kazu1130_h

LINEのBOTを組んでみた

お久しぶりです、ひろたんです。

ようやくLINEがBOTAPIを一般公開してくれたと聞いて、飛びついてきました。


LINE Developers - BOT API - Overview

先着1万人らしいですよ!!はよはよ!!



ただこいつ、中々に曲者で……。
Botに対して発言とかのアクションがあったときに、あらかじめ登録しておいたcallback用URLを叩きにきてくれる機能があるのですが、HTTPSじゃないとダメな上、Let'sEncryptの証明書だと叩きに来てくれないんですよね。


なので、こんなスクリプトをherokuにおいて、自前のサーバにバイパスさせて遊んでました。

<?php
function heroku_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; 
} 

$headers = heroku_getallheaders();

if(isset($headers["X-LINE-CHANNELSIGNATURE"])){
  $json_string = file_get_contents('php://input');
  $url = "https://urische.me/hogehoge";
  $curl = curl_init($url);
  $options = array(
    CURLOPT_HTTPHEADER => array(
      'Content-type: application/json',
      'X-LINE-ChannelSignature: '.$headers["X-LINE-CHANNELSIGNATURE"]
    ),
    CURLOPT_POST => true,//POST
    CURLOPT_POSTFIELDS => $json_string, 
    CURLOPT_SSL_VERIFYPEER => false
  );
  curl_setopt_array($curl, $options);
  $result = curl_exec($curl);
  exit();
} else {
  print "making now....";
}

herokuだとgetallheaders()が使えなかったので、PHP: getallheaders - Manualにあった代替関数を定義して使ってます。

これで何処でも受け取れるようになるので、urische.meでこんなスクリプトを動かしてAPIを叩いてます。

肝心の中身は単に発言された内容をsay:なんちゃら とオウム返しするだけです。

<?php
$headers = getallheaders();

if(isset($headers["X-LINE-ChannelSignature"])){
  $json_string = file_get_contents('php://input');
  if(base64_decode($headers["X-LINE-ChannelSignature"]) === hash_hmac("sha256",$json_string,$LINE_SECRET,true)){
    botmain(json_decode($json_string));
  }
}

function botmain($json){
  global $LINE_SECRET,$LINE_CHANNEL,$LINE_MID;
  $results = $json->result;
  $ret = array();
  $sendheaders = array(
                'Content-Type: application/json; charset=UTF-8',
                'X-Line-ChannelID: '.$LINE_CHANNEL,
                'X-Line-ChannelSecret: '.$LINE_SECRET,
                'X-Line-Trusted-User-With-ACL: '.$LINE_MID
             );

  for($i=0;$i<count($results);++$i){
    $resContent = array(
      "contentType"=>1,
      "toType"=>1,
      "text"=>"say:".$results[$i]->content->text
    );
    $resp = array(
                'to' => array($results[$i]->content->from),
                'toChannel' => 1383378250, # Fixed value
                'eventType' => '138311608800106203', # Fixed value
                'content' => $resContent,
    );
  $url = "https://trialbot-api.line.me/v1/events";
  $curl = curl_init($url);
  $options = array(
    CURLOPT_HTTPHEADER => $sendheaders,
    CURLOPT_POST => true,//POST
    CURLOPT_POSTFIELDS => json_encode($resp), 
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_RETURNTRANSFER => true
  );
  curl_setopt_array($curl, $options);
  $result = curl_exec($curl);
  curl_close($curl);
  }
}


Trialということで機能は少ないですが、自分用に色々するには便利そうですね!



ところで巷で公開されてるサンプルの大半が署名検証をはしょってるんですよね。(要出典)
そのままコピペしてそのまま動かしている人が沢山居るだろうな……と思うと何とも言えない気持ちになりますね。

PHPでX-LINE-ChannelSignatureを検証するコード、以下に改めて張っておきます。

<?php
base64_decode($headers["X-LINE-ChannelSignature"]) === hash_hmac("sha256",$json_string,$LINE_SECRET,true)


ではでは、そのうち何処かで。