LoginSignup
5
4

More than 3 years have passed since last update.

PHP+LINE Messaging APIでクイズアプリを作ってみよう

Last updated at Posted at 2020-05-24

今回やりたいこと

今回はPHPでLINE Messaging APIを使いクイズアプリを作成します。

仕様

・リッチメニューをタップしクイズを出題
・4つの選択肢から回答する
・正解の場合のみ解説の参考サイトurlを添付
・クイズはDB管理とし、クイズの追加・編集・削除機能がある管理画面の作成
※管理画面は後日公開予定です。

こちらから友達追加してお試しいただけます!
https://lin.ee/3AOdmRRlo
スクリーンショット 2020-05-24 13.56.43.png

イメージ

あいさつメッセージ
IMG_6287.PNG

リッチメニューをタップするとクイズを出題
IMG_6306.PNG

不正解の選択肢をタップした場合のメッセージ
IMG_6289.PNG

正解の選択肢をタップした場合のメッセージ
IMG_6290.PNG

いいえをタップした場合のメッセージ
IMG_6305.PNG

はいをタップした場合、次のクイズが出題
IMG_6306.PNG

以上の仕様を実装します。

VPSで環境構築

VPSはこちらを参考に構築しました。詳細は下記サイトから確認してみてください。他にも参考になる記事がたくさんあるのでググってみて下さい!
ネコでもわかる!さくらのVPS講座 〜第一回:VPSてなんだろう?〜

Messaging APIを設定

Messaging APIの概要はこちら

プログラム

DBカラム

quizzes : id | quiz | ans1 | ans2 | ans3 | ans4 | correct | url | deleted

quiz:問題文
ans1~4:選択肢1~4
correct:正解番号
url:解説サイトのurl
deleted:論理削除用

index.php
<?php

$accessToken = 'アクセストークン'; 
//file_get_contents()関数でPOSTされたJSON文字列を取り出し
$jsonString = file_get_contents('php://input'); 
//エラーログ記録
error_log($jsonString); 
//json_decode()関数でJSONをデコードして変数に格納
$jsonObj = json_decode($jsonString); 
//メッセージイベントを取得
//スタンプ、テキスト、画像などの場合がある
$message = $jsonObj->{"events"}[0]->{"message"};
//ReplyToken取得
//受信したイベントに対して返信を行うために必要
$replyToken = $jsonObj->{"events"}[0]->{"replyToken"};
//メッセージタイプ取得
//ここで、受信したメッセージがテキストか画像かなどを判別
$type = $jsonObj->{'events'}[0]->{'type'};

// 送られてきたメッセージの中身からレスポンスのタイプを選択 

//$typeがmessageの場合
if ($type == 'message') {
   //messageがtextであり、かつtextがクイズの場合クイズを返信する
    if ($message->{"text"} == 'クイズ') {
    //DB接続
        $dbh = new PDO("mysql:host=localhost;dbname=DB名", 'ユーザー名', 'パスワード');
     //sql文を変数にセット
       //DBから論理削除されていないクイズIDの配列を作る
        $sql = "SELECT id FROM quizzes WHERE deleted = 0";
        $res = $dbh->query($sql);
        $quizIdArray = array();
        foreach ($res as $row) {
            array_push($quizIdArray, $row['id']);
        }
    //クイズIDをランダムに並べ替える
        shuffle($quizIdArray);
      //クイズID配列の先頭要素をキーに、クイズを取得し表示する
        $targetQuizId = $quizIdArray[0];
        $sql2 = "select * from quizzes where id = $targetQuizId";
        $stmt = $dbh->query($sql2);
        $targetRow = $stmt->fetch();
    //$messageDataにクイズの内容を代入する
        $messageData = [ 
            'type' => 'template', 
            'altText' => 'クイズ', 
            'template' => [ 'type' => 'buttons', 'text' => $targetRow['quiz'], 
            'actions' => [
            [ 'type' => 'postback', 'label' => $targetRow['ans1'], 'data' => 'ans=' . $targetRow['ans1'] . '&num=1&correct=' . $targetRow['correct'] . '&id=' . $targetRow['id'] ],
            [ 'type' => 'postback', 'label' => $targetRow['ans2'], 'data' => 'ans=' . $targetRow['ans2'] . '&num=2&correct=' . $targetRow['correct'] . '&id=' . $targetRow['id'] ],
            [ 'type' => 'postback', 'label' => $targetRow['ans3'], 'data' => 'ans=' . $targetRow['ans3'] . '&num=3&correct=' . $targetRow['correct'] . '&id=' . $targetRow['id'] ],
            [ 'type' => 'postback', 'label' => $targetRow['ans4'], 'data' => 'ans=' . $targetRow['ans4'] . '&num=4&correct=' . $targetRow['correct'] . '&id=' . $targetRow['id'] ],
            ] 
            ]
        ]; 
    //messageがtextであり、かつtextがいいえであった場合の返信を$massageDataに代入
    }elseif ($message->{"text"} == 'いいえ') {
        $messageData = [ 'type' => 'text', 'text' => 'いつも[解剖学クイズbot]をご利用いただきありがとうございます。クイズチャレンジお疲れ様でした!楽しんでいただけましたでしょうか?またのチャレンジをお待ちしております!' ]; 
        $messageData2 = [ 'type' => 'text', 'text' => '再度クイズにチャレンジする場合は、「クイズにチャレンジ!」をタップしてください!' ]; 
    } else {
   //$typeが上記以外の場合の返信内容を$messageDataに代入
        $messageData = [ 'type' => 'text', 'text' => '申し訳ありません、その操作には対応しておりません。「クイズにチャレンジ!」をタップしてクイズにチャレンジしてみて下さい。' ]; 
    } 
}
//$typeがpostbackの場合
if ($type == 'postback') {
   // JSONデータからポストバックデータを取得
    $postback = $jsonObj->{"events"}[0]->{"postback"}->{"data"};
   //文字列を名前と値に分解し変数に代入
    parse_str($postback, $data);
   //各値を変数に代入
    $answer = $data["ans"];
    $number = $data["num"];
    $id = $data["id"];
    $correct = $data["correct"];
   //ユーザーの選択した選択肢と正解番号を比較し、正解・不正解の場合で返信内容を$massageDataに代入
   //正解の場合
    if ($number == $correct) {
        $dbh = new PDO("mysql:host=localhost;dbname=DB名", 'ユーザー名', 'パスワード');
   //選択された選択肢のIDから解説サイトのurlを取得
        $sql3 = "SELECT url FROM quizzes WHERE id = $id";
        $stmt2 = $dbh->query($sql3);
        $targetRowUrl = $stmt2->fetch();
        $url = $targetRowUrl['url'];
   //$massageDataに返信内容を代入
        $messageData = [ 'type' => 'text', 'text' => $answer . 'ですね。' ]; 
        $messageData2 = [ 'type' => 'text', 'text' => '素晴らしい!『正解』です!!!' ]; 
        $messageData3 = [ 
            'type' => 'template',
            'altText' => '解説', 
            'template' => [
            'type' => 'buttons',
            'title' => '解説です!',
            'text' => '確認してみてね!', 
            'actions' => [
            [
            'type' => 'uri',
            'label' => 'Wikipediaへ移動', 
            'uri' => "$url", 
            ]
            ]
            ] 
        ]; 
        $messageData4 = [ 
            'type' => 'template', 
            'altText' => '次のクイズにチャレンジしますか?', 
            'template' => [ 'type' => 'confirm', 'text' => '次のクイズにチャレンジしますか?', 
            'actions' => [
            [ 'type' => 'message', 'label' => 'はい', 'text' => 'クイズ' ],
            [ 'type' => 'message', 'label' => 'いいえ', 'text' => 'いいえ' ], 
            ] 
            ]
        ];
    }else{
   //不正解の場合の返信内容を$massageDataに代入
        $messageData = [ 'type' => 'text', 'text' => $answer . 'ですね。' ]; 
        $messageData2 = [ 'type' => 'text', 'text' => 'むむ、、『不正解』です。' ]; 
    }
}
//メッセージの数に合わせ条件分岐
if ($messageData4 == true) {
    $response = [ 'replyToken' => $replyToken, 'messages' => [$messageData,$messageData2,$messageData3,$messageData4] ]; 
}elseif ($messageData3 == true) {
    $response = [ 'replyToken' => $replyToken, 'messages' => [$messageData,$messageData2,$messageData3] ]; 
}elseif ($messageData2 == true) {
    $response = [ 'replyToken' => $replyToken, 'messages' => [$messageData,$messageData2] ]; 
}else{
    $response = [ 'replyToken' => $replyToken, 'messages' => [$messageData] ]; 
}
error_log(json_encode($response)); 
//curlセッション初期化。urlも設定
$ch = curl_init('https://api.line.me/v2/bot/message/reply'); 
//curlオプション設定
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($response)); 
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json; charser=UTF-8', 'Authorization: Bearer ' . $accessToken )); 
//curl実行
$result = curl_exec($ch);
//エラーログ記録
error_log($result); 
//curlセッション終了
curl_close($ch);

?>

工夫した点

・クイズをDB管理とし、追加・編集・削除機能をつけた
・クイズをランダムに出題
・ユーザーからのレスポンスに応じて異なる処理

改善案

・メッセージの数に合わせた条件分岐がダサいのでスマートに書けないものか。。。
・クイズ内容を身体の部位ごとに指定するなど、分野を分ける
・解説を外部サイトに依存しているが、bot内で完結しても良いか
・その場合、画像付きの解説などを入れるとUXが高められそう

5
4
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
5
4