Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8829

常に動くLINEBOTにお引っ越し(レンタルサーバ+PHP編)

$
0
0

今回のモチベーション

前回、こちらの記事を参考にWikipedia APIを使った、調べものLINE botを作った。

前回の記事
https://qiita.com/shima-07/items/2322598ca5a40cfee47b

だが、

  • ngrokを立ち上げている時しか使えないから普段使えない。
  • いざ、ngrokを立ち上げるとアドレスが変わってしまうため、Messaging API settingsのwebhook URLを毎度変えないと動かない。

うーん。。。

ngrok立ち上げるのめんどくさい! 常に使えるようにしないと意味ないじゃん!

と思ったわけです。だから『常に動くようにしよう!』が今回の動機です。

今回やったこと

  • 1. まずは nowを試してみた
  • 2. さくらのレンタルサーバでやることにした
  • 3. jsで書いていたものをPHPに書き直した

最終的にはPHP化してさくらサーバに載っけました。

1. まずは nowを試してみた

このあたりを参考に進めてみる。

さすが良記事!サクサク進むぜと思いながら最後までいきデプロイ完了!
簡単だったなあと思いながら、Webhook URLに入れて「Verify」をクリック・・・・

image.png

う。。まあよくある。

(1時間ほど立ち向かう)
色々と試すが私の手におえないと判断して諦める。

2. さくらのレンタルサーバでやることにした

この記事を発見!
http://blog.hetabun.com/line-bot-php-sakura

これ通りやることで、「こんにちは」に対して「こんにちは!」と元気よく返してくれるボットができました。

3. jsで書いていたものをPHPに書き直した

ここからが本番。前回あげた下記jsのコードと同じような振る舞いをPHPで書いていく。
PHPももちろん初心者である。

再掲

server.js
'use strict';constexpress=require('express');constline=require('@line/bot-sdk');constPORT=process.env.PORT||3000;// 追加constaxios=require('axios');constconfig={channelSecret:'作成したBOTのチャンネルシークレット',channelAccessToken:'作成したBOTのチャンネルアクセストークン'};constapp=express();app.get('/',(req,res)=>res.send('Hello LINE BOT!(GET)'));//ブラウザ確認用(無くても問題ない)app.post('/webhook',line.middleware(config),(req,res)=>{//ここのif文はdeveloper consoleの"接続確認"用なので後で削除して問題ないです。if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT!(POST)');console.log('疎通確認用');return;}Promise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result));});constclient=newline.Client(config);functionhandleEvent(event){if(event.type!=='message'||event.message.type!=='text'){returnPromise.resolve(null);}letmes=''// console.log(event.message.text);if(event.message.text.indexOf('')>-1){// ?を含んでいる場合にはwikiで検索したものを出して、含んでない場合はurlを返すvarstr=event.message.text;varresult=str.split('').join('');//?を取り除く処理mes=result+'の説明:';//wikiのbodyの前の一言getBody(event.source.userId,result);//wiki APIで取得できたらプッシュメッセージ}else{varresult=event.message.text;mes=result+'のURL:';//wikiのurlの前の一言getUrl(event.source.userId,result);//wiki APIで取得できたらプッシュメッセージ}returnclient.replyMessage(event.replyToken,{type:'text',text:mes});}constgetBody=async(userId,word)=>{constres=awaitaxios.get('http://wikipedia.simpleapi.net/api?keyword='+encodeURIComponent(word)+'&output=json');constitem=res.data;// console.log(item); awaitclient.pushMessage(userId,{type:'text',text:item[0].body,});}constgetUrl=async(userId,word)=>{constres=awaitaxios.get('http://wikipedia.simpleapi.net/api?keyword='+encodeURIComponent(word)+'&output=json');constitem=res.data;// console.log(item); awaitclient.pushMessage(userId,{type:'text',text:item[0].url,});}app.listen(PORT);console.log(`Server running at ${PORT}`);

 処理の整理

  • LINEからのメッセージを受け取る
  • そのメッセージをWikipedia APIに渡して結果を受け取る
  • メッセージによってLINE側に返却するものを変える
    • ?があるときはurlを返す
    • ?がないときはbodyを返す

LINEからのメッセージを受け取る

参考にした記事中にあった下記の$textで取れているからそれはOK。

LINEからのメッセージ.php
//ユーザーからのメッセージ取得$json_string=file_get_contents('php://input');$jsonObj=json_decode($json_string);$type=$jsonObj->{"events"}[0]->{"message"}->{"type"};//メッセージ取得$text=$jsonObj->{"events"}[0]->{"message"}->{"text"};//ReplyToken取得$replyToken=$jsonObj->{"events"}[0]->{"replyToken"};

そのメッセージをWikipedia APIに渡して結果を受け取る

ここが一番ハマった。
jsではres.data.item[0].bodyの構造で取れていたので、
同じノリで $value = $res->{"data"}->{"item"}[0]->{"body"};のような書き方をして、、当然何も取れず。

結論、下記のような取り方でできた。

wikipediaAPIからURLやbody取得部分.php
$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);// 0番目の物だけを抽出する。もっとたくさん抽出したいときはここを変更する$jsonwiki=$jsonwiki_decode[0];//欲しい項目だけの配列にする$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];

流れとしては、

  • LINEから受け取ったキーワードをAPIのkeywordとして渡せるようにエンコードする
  • それをAPIに渡し$resとして取得する
  • json_decodeして配列にする
  • そのキーワードに対しての一番先頭の回答を取得するため[0]を取得する
  • それに対して$wikidataとして必要な項目だけ取得する
  • LINEに返したいものは、$URL = $wikidata["url"]や $body = $wikidata["body"]として取得できる

補足

上記 $resにどんなものが入っているか見るために下記のようなものをページを作って見てました。( jsはconsole.log()で気軽に見えたけどphpではどうやってみたらいいかわからずわざわざこんなことしました。。。 )
image.png

check_data.php
<html><head><title> test </title></head><body><formmethod="POST"action="show.php">キーワード:
<inputtype="text"name="name"size="15"/><inputtype="submit"name="submit"value="送信" /></form><?phpif($_REQUEST['submit']!=null){$input=$_REQUEST[name];//$textのなかに'?'が含まれている場合$text=str_replace('?','',$input);$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);$jsonwiki=$jsonwiki_decode[0];$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];print('$input: '.$input.'-----');print('$text: '.$text.'-----');print('$keyword: '.$keyword.'-----');print('$res: '.$res.'-----');print('$jsonwiki_decode :'.$jsonwiki_decode.'-----');print('$jsonwiki :'.$jsonwiki.'-----');print('$wikidata :'.$wikidata.'-----');print('URL: '.$URL.'-----');print('body: '.$body.'-----');}?></body></html>

メッセージによってLINE側に返却するものを変える

  • ?がある場合はURLをLINEに返す。また、Wikipedia APIに渡すときには?を取り除く。
  • ?がない場合はBodyをLINEに返す。
分岐部分.php
if(strpos($text,'?')!==false){//$textのなかに'?'が含まれている場合$text=str_replace('?','',$text);$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);// 0番目の物だけを抽出する。もっとたくさん抽出したいときはここを変更する$jsonwiki=$jsonwiki_decode[0];//欲しい項目だけの配列にする$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];// メッセージ部分$response_format_text=["type"=>"text","text"=>$URL];}else{// ?が含まれないときの処理$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);// 0番目の物だけを抽出する。もっとたくさん抽出したいときはここを変更する$jsonwiki=$jsonwiki_decode[0];//欲しい項目だけの配列にする$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];// メッセージ部分$response_format_text=["type"=>"text","text"=>$body];}}

サンプル

全ソースコード

linebot.php
<?php$accessToken='アクセストークン';//ユーザーからのメッセージ取得$json_string=file_get_contents('php://input');$jsonObj=json_decode($json_string);$type=$jsonObj->{"events"}[0]->{"message"}->{"type"};//メッセージ取得$text=$jsonObj->{"events"}[0]->{"message"}->{"text"};//ReplyToken取得$replyToken=$jsonObj->{"events"}[0]->{"replyToken"};//メッセージ以外のときは何も返さず終了if($type!="text"){exit;}if($type=="text"){if(strpos($text,'?')!==false){//$textのなかに'?'が含まれている場合$text=str_replace('?','',$text);$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);// 0番目の物だけを抽出する。もっとたくさん抽出したいときはここを変更する$jsonwiki=$jsonwiki_decode[0];//欲しい項目だけの配列にする$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];// メッセージ部分$response_format_text=["type"=>"text","text"=>$URL];}else{// ?が含まれないときの処理$keyword=mb_convert_encoding($text,"UTF-8","auto");$res=file_get_contents('http://wikipedia.simpleapi.net/api?keyword='.$keyword.'&output=json');$jsonwiki_decode=json_decode($res,true);// 0番目の物だけを抽出する。もっとたくさん抽出したいときはここを変更する$jsonwiki=$jsonwiki_decode[0];//欲しい項目だけの配列にする$wikidata=array('url'=>$jsonwiki["url"],'body'=>$jsonwiki["body"]);$URL=$wikidata["url"];$body=$wikidata["body"];// メッセージ部分$response_format_text=["type"=>"text","text"=>$body];}}$post_data=["replyToken"=>$replyToken,"messages"=>[$response_format_text]];$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 '.$accessToken));$result=curl_exec($ch);curl_close($ch);

おわりに

APIから返ってきた値をいい感じで取ってくるところでだいぶハマりました。
JSONデータの扱い方にもっと慣れないとなあー

次はHerokuを使ったお引っ越しもやってみようと思います。


Viewing all articles
Browse latest Browse all 8829

Trending Articles