CakePHP3で動かす
はい、前回の公開から時間が経ってますが、書いていきます。
CakePHP3を使って、LINE BOTを使うというところからですね。
CakePHP3の使い方がわからない人は、調べてください。
BotController作成
<?php
namespace App\Controller;
use App\Controller\AppController;
class BotController extends AppController
{
// アクセストークン
protected $ACCESS_TOKEN = 'developerの[メッセージ送受信設定]の[アクセストークン]';
public function index()
{
// autoRenderは使用しません
$this->autoRender = false;
// 返却する文字列
$message_text = "";
$messageData = array();
$request = $this->request->getData();
// ユーザーから送られてきたデータ
$event = $request['events'][0];
$type = $event['type'];
$replyToken = $event['replyToken'];
$userId = $event['source']['userId'];
if($type == 'follow'){
// 登録された時に文言を返す
$message_text = "登録ありがとう。よろしくね。";
}elseif($type == 'unfollow'){
// 削除された場合の処理
}elseif($type == "message"){
// メッセージ
$messageType = $event['message']['type'];
if($messageType == 'text') {
// text そのまま返す
$message_text = $event['message']['text'];
}
}
// 返信可能な場合に処理する
if(!empty($message_text)) {
//レスポンスフォーマット
$response_format_text = [
"type" => 'text',
"text" => $message_text
];
//ポストデータ
$post_data = [
"replyToken" => $replyToken,
"messages" => [$message_text]
];
//curl実行
$ch = curl_init("https://api.line.me/v2/bot/message/reply");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charser=UTF-8',
'Authorization: Bearer ' . $ACCESS_TOKEN
));
$result = curl_exec($ch);
curl_close($ch);
}
echo 200;
}
}
コレで、https://hogehoge/bot
とかをWebhook URLに指定すれば、
前回と同じようなことができますね。
天気予報
では次に。天気予報。
今回はOpenWeatherMapを利用します。
登録して、API KEYを取得したら、「天気予報」と言う言葉に反応して、
沼津市=Numazu, JP
の現在の天気を取得します。
WeatherMapComponent作成
まずは、天気予報関連の処理をまとめたいので
WeatherMapComponent.php
を作りましょう。
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
class WeatherMapComponent extends Component
{
// 現在の天気を取得
protected $WEATHER_MAP_WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather";
// 沼津市を指定
protected $CITY = "Numazu, JP";
// api key
protected $WEATHER_MAP_API = "[OpenWeatherMap の API KEY]";
/**
* 天気予報文字列を返す
* @return string
*/
public function getWeather(){
$url = self::getWeatherUrlFromCity();
$weather = json_decode(file_get_contents($url), true);
return self::getWeatherText($weather);
}
/**
* 都市名検索URL(現在の天気)
* @return string
*/
public function getWeatherUrlFromCity(){
return $this->WEATHER_MAP_WEATHER_URL. "?q=".$this->CITY."&units=metric&appid=".$this->WEATHER_MAP_API;
}
/**
* objectから天気予報を取得して文字列を返す
* @param $weather
* @return string
*/
public function getWeatherText($weather){
$text = '';
if(isset($weather['weather'][0]['id'])){
$main = $this->getMainText($weather['weather'][0]['main']);
$description = $this->getWeatherDescription($weather['weather'][0]['id']);
$text .= "今の天気は".$main."で、".$description."です。\n";
}
// degが風向きを、speedが風速を表してます。
if(isset($weather['wind']['deg']) && isset($weather['wind']['speed'])){
$digger = $this->getWindDigger($weather['wind']['deg']);
$text .= $digger."向きの風、風速".$weather['wind']['speed']."メートル。\n";
}
// tempが気温を示しています
if(isset($weather['main']['temp'])){
$text .= "気温は".$weather['main']['temp']."度です。";
}
return $text;
}
/**
* @param $main
* @return mixed
*/
public function getMainText($main){
$inEnglish = array('Clear', 'Clouds', 'Rain', 'Snow','Mist');
$inJapanese = array('晴れ', 'くもり', '雨', '雪','霧');
$key = array_search($main,$inEnglish);
if($key !== false){
return $inJapanese[$key];
}
return $main;
}
/**
* 天気詳細
* @param $id
* @return string
*/
public function getWeatherDescription($id){
$description[200] = '雨が降る雷雨';
$description[201] = '雨が降る雷雨';
$description[202] = '豪雨による雷雨';
$description[210] = '雷雨';
$description[211] = '雷雨';
$description[212] = '重い雷雨';
$description[221] = '荒れた雷雨';
$description[230] = '軽い霧雨で雷雨';
$description[231] = '雷雨と霧雨';
$description[232] = '重い霧雨で雷雨';
$description[300] = '光度の霧雨';
$description[301] = '霧雨';
$description[302] = '重い霧雨の霧';
$description[310] = '光度降雨雨';
$description[311] = '霧雨';
$description[312] = '強い霧雨';
$description[313] = 'にわか雨と霧雨';
$description[314] = '重いにわか雨と霧雨';
$description[321] = 'にわか霧雨';
$description[500] = '小雨';
$description[501] = '中程度の雨';
$description[502] = '強い雨';
$description[503] = '非常に豪雨';
$description[504] = '極端な雨';
$description[511] = '雨氷';
$description[520] = '強度のにわか雨';
$description[521] = 'にわか雨';
$description[522] = '激しいにわか雨';
$description[531] = '不規則なにわか雨';
$description[600] = '小雪';
$description[601] = '雪';
$description[602] = '大雪';
$description[611] = 'みぞれ';
$description[612] = 'にわかみぞれ';
$description[615] = '明るい雨と雪';
$description[616] = '雨や雪';
$description[620] = '雷とにわか雪';
$description[621] = 'にわか雪';
$description[622] = '重いにわか雪';
$description[701] = 'ミスト';
$description[711] = '煙';
$description[721] = 'ヘイズ';
$description[731] = '砂、ほこり旋回する';
$description[741] = '霧';
$description[751] = '砂';
$description[761] = 'ほこり';
$description[762] = '火山灰';
$description[771] = 'スコール';
$description[781] = '竜巻';
$description[800] = '晴天';
$description[801] = '薄い雲';
$description[802] = '雲';
$description[803] = '曇りがち';
$description[804] = '厚い雲';
$description[900] = '竜巻';
$description[901] = '熱帯低気圧';
$description[902] = 'ハリケーン';
$description[903] = '寒い';
$description[904] = '暑い';
$description[905] = '風が強い';
$description[906] = '雹';
$description[951] = '落ち着いた';
$description[952] = 'そよ風';
$description[953] = 'そよ風';
$description[954] = '中風';
$description[955] = '新鮮な風';
$description[956] = '強い風';
$description[957] = '高風、近くの暴風';
$description[958] = 'ガール';
$description[959] = '深刻な暴風';
$description[960] = '嵐';
$description[961] = '暴風雨';
$description[962] = 'ハリケーン';
if(isset($description[$id])){
return $description[$id];
}
return '';
}
/**
* 風向き計算
*
* @param $digree
* @return mixed
*/
public function getWindDigger($digree){
$dname = ["北","北北東","北東", "東北東", "東", "東南東", "南東", "南南東", "南", "南南西", "南西", "西南西", "西", "西北西", "北西", "北北西", "北"];
$dindex = round($digree / 22.5);
return $dname[$dindex];
}
}
BotController修正
今度はこのComponentを使えるようにしないとですね。
class BotController extends AppController
{
public $components = [ "WeatherMap" ];
// アクセストークン
protected $ACCESS_TOKEN = 'developerの[メッセージ送受信設定]の[アクセストークン]';
componentsに"WeatherMap"を指定します。
}elseif($type == "message"){
// メッセージ
$messageType = $event['message']['type'];
if($messageType == 'text') {
// 文言に「天気予報」が含まれていたら天気予報を返す
if(strpos("天気予報",$event['message']['text']) !== false){
$message_text = $this->WeatherMap->();
}else{
// text そのまま返す
$message_text = $event['message']['text'];
}
}
}
if(strpos("天気予報",$event['message']['text']) !== false){
このようにして、文言の中に「天気予報」が含まれていたら、天気を返します。
とはいえ、今回返しているのは現在の天気なわけですが…
まとめ
このようにして、Controller、Componentを作成して、BOTに天気を返させる処理ができました。
今回は現在の天気を返していますが、URLの「weather」を「forecast」にすれば、予報の処理も作成できます。
(返ってくる値が違うので、気をつけてください)
APIと連携したら色々と面白いBOTが作れそうだなぁーと言うのがこちらを作った際の感想でした。
でも、現在はPUSH機能を使ったBOTがかなり面白いので、そちらの処理も後々書きたいと思います。
この機能を使ったおしゃべりBOT 堕天使YOHANEを公開しています。
メインはおしゃべりなので、何か言うと返ってきます。
また、占いとか…現在の沼津の天気を教えてくれるそんなBOTです。