เนื้อหาในตอนนี้ เราจะมาดูเกี่ยวกับการใช้งานปุ่ม quick reply
ซึ่งเป็นปุ่มที่จะถูกส่งมาพร้อมกับข้อความโดย bot แสดงด้านล่างของหน้าต่างสนทนา
เมื่อผู้ใช้กดเลือกปุ่ม quick reply ที่ต้องการ ก็จะเป็นการตอบกลับ bot โดยส่งค่าตาม
action หรือการทำงานที่กำหนดไว้แล้ว
ปุ่ม quick reply สามารถใช้ได้กับการสนทนาระหว่างผู้ใช้กับ bot หรือ การสนทนาในกลุ่ม หรือห้อง
ที่มี bot อยู่ด้วยก็ได้ โดยสามารถกำหนดจำนวนของปุ่ม quick reply ได้สูงสุด 13 รายการ
หน้าตาของปุ่ม quick reply
ส่วนประกอบของปุ่ม Quick Reply
ปุ่ม Quick Reply ประกอบด้วย Element ต่างๆ ดังนี้
Action
การทำงานของ action เมื่อปุ่ม quick reply ถูกเลือก จะมีรูปแบบแตกต่าง กันไปดังนี้
** เราได้รู้จักกับ action object ไปบ้างแล้วในบทความ
การใช้งาน Template Message ใน LINE Messaging API ตอนที่ 3 http://niik.in/836
https://www.ninenik.com/content.php?arti_id=836 via @ninenik
ซึ่งในเนื้อหาตอนนั้้น เราได้รู้จักกับ
- Postback action
- Message action
-
URI action - Datetime picker action
โดย action ดังกล่าว สามารถใช้งานร่วมกับปุ่ม quick reply ได้ ยกเว้น URI action
นอกจาก action ข้างต้นแล้ว ในปุ่ม quick reply ยังรองรับ action เฉพาะเพิ่มเติม ดังนี้ด้วย
- Camera action (แสดงหน้าจอสำหรับถ่ายรูปภาพ ใน Line)
- Camera roll action (แสดงหน้าจอสำหรับเลือกรูปในคลังภาพ ใน Line)
- Location action (แสดงหน้าจอสำหรับเลือก location หรือพิกัดในแผนที่ ใน Line)
ค่า action ที่จะใช้กำหนดเป็นดังนี้
Postback action --> "postback"
Message action --> "message"
Datetime picker action --> "datetimepicker"
Camera action --> "camera"
Camera roll action --> "cameraRoll"
Location action --> "location"
ซึ่งในการใช้งานกับโค้ด เราจะใช้ Line Bot SDK ไม่ต้องกำหนดค่าเหล่านี้ก็ได้
Icon
ไอคอนในปุ่ม quick reply จะแสดงด้านหน้าสุดของปุ่ม
ถ้าเป็นปุ่มที่กำหนด action เป็น camera , camera roll หรือ location ตัวไอคอน จะเป็นค่าเริ่มต้น
เดิม ไม่สามารถกำหนดไอคอนเองได้
ถ้าเป็นปุ่มที่กำหนด action เป็น postback , message หรือ datetime picker เราสามารถกำหนดได้ว่า
จะให้มี หรือไม่มีไอคอนก็ได้
สำหรับการกำหนดไอคอนให้กับ quick reply นั้น เราจะกำหนดเป็น url ของรูปภาพ ผ่าน https โดยเป็นไฟล์รูป
นามสกุล png สัดส่วนรูป 1:1 หรือรูปสี่เหลี่ยมจัตุรัส ขนาดกว้างยาวเท่าไหร่ก็ได้ แต่ขนาดไฟล์ไม่เกิน 1 MB
Label
ข้อความที่แสดงในปุ่ม quick reply
ปุ่ม Quick Reply จะถูกซ่อนหรือ ไม่แสดง ในกรณีต่อไปนี้
1. เมื่อผู้ใช้กดเลือกปุ่ม quick reply ปุ่มก็จะหายไป ยกเว้นในกรณีที่ปุ่มนั้น กำหนด action เป็น camera , camera roll
หรือ location ที่เมื่อผู้ใช้กดปุ่มนั้นแล้ว ตัวปุ่มก็จะยังแสดงอยู่ จนกว่าผู้ใช้จะเลือกและส่งข้อมูลเสร็จสิ้เน ปุ่ม quick
reply จึงจะหายไป
2. เมื่อ bot หรือผู้ใช้ หรือ สมาชิกอื่นๆ ส่งข้อความใหม่เข้ามาในกลุ่มหรือห้องสนทนา แล้วข้อความนั้นถูกลบออก
ปุ่ม quick reply ก็จะแสดงอีกครั้ง
การใช้งาน Line bot sdk กำหนด Quick Reply
เราเข้าใจคร่าวๆ และรู้ถึงรูปแบบลักษณะของปุ่ม quick reply ไปแล้วข้างต้น
ต่อไป จะเป็นแนวทางสร้างปุ่ม quick reply โดยจะขอสร้างเป็นแนวทางทั้งหมด 6 ปุ่ม ได้แก่
ปุ่ม ที่สอดคล้องกับ action ที่รองรับทั้ง 6 แบบ ดังนี้
เราจะยึดรูปแบบการกำหนดในไฟล์ bot.php ตามบทความตอนที่แล้ว
แปลงข้อมูล ด้วย LINE bot sdk ใน LINE Messaging API ตอนที่ 6 http://niik.in/839
https://www.ninenik.com/content.php?arti_id=839 via @ninenik
ซึ่งในที่นี้เราจะประยุกต์เพิ่มเติม โดยการแยกไฟล์ส่วนของการกำหนดการส่งข้อความรูปแบบต่างๆ
จาก bot ไปยังผู้ใช้ อีกไฟล์หนึ่ง เพื่อรองรับกรณีเรามีการกำหนดเงื่อนไข การโต้ตอบกับ bot ที่มากขึ้น
และจะได้โฟกัสไปที่การจัดรูปแบบข้อความตามเงื่อนไขเป็นหลัก
ไฟล์ bot.php
บรรทัดที่ 52 - 57 คือ class เพิ่มเติมที่เราจำเป็นต้องเรียกใช้ในการใช้งาน quick reply
บรรทัดที่ 137 - 433 จะเป็นส่วนที่เราจะแยกไปใช้อีกไฟล์หนึ่ง สมมติเราใช้เป็นไฟล์ bot_action.php
<?php // กรณีต้องการตรวจสอบการแจ้ง error ให้เปิด 3 บรรทัดล่างนี้ให้ทำงาน กรณีไม่ ให้ comment ปิดไป ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); // include composer autoload require_once '../vendor/autoload.php'; // การตั้งเกี่ยวกับ bot require_once 'bot_settings.php'; // กรณีมีการเชื่อมต่อกับฐานข้อมูล //require_once("dbconnect.php"); ///////////// ส่วนของการเรียกใช้งาน class ผ่าน namespace use LINE\LINEBot; use LINE\LINEBot\HTTPClient; use LINE\LINEBot\HTTPClient\CurlHTTPClient; use LINE\LINEBot\Event; use LINE\LINEBot\Event\BaseEvent; use LINE\LINEBot\Event\MessageEvent; use LINE\LINEBot\Event\AccountLinkEvent; use LINE\LINEBot\Event\MemberJoinEvent; use LINE\LINEBot\MessageBuilder; use LINE\LINEBot\MessageBuilder\TextMessageBuilder; use LINE\LINEBot\MessageBuilder\StickerMessageBuilder; use LINE\LINEBot\MessageBuilder\ImageMessageBuilder; use LINE\LINEBot\MessageBuilder\LocationMessageBuilder; use LINE\LINEBot\MessageBuilder\AudioMessageBuilder; use LINE\LINEBot\MessageBuilder\VideoMessageBuilder; use LINE\LINEBot\ImagemapActionBuilder; use LINE\LINEBot\ImagemapActionBuilder\AreaBuilder; use LINE\LINEBot\ImagemapActionBuilder\ImagemapMessageActionBuilder ; use LINE\LINEBot\ImagemapActionBuilder\ImagemapUriActionBuilder; use LINE\LINEBot\MessageBuilder\Imagemap\BaseSizeBuilder; use LINE\LINEBot\MessageBuilder\ImagemapMessageBuilder; use LINE\LINEBot\MessageBuilder\MultiMessageBuilder; use LINE\LINEBot\TemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\DatetimePickerTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\MessageTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\PostbackTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateMessageBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ButtonTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselColumnTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ConfirmTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ImageCarouselTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ImageCarouselColumnTemplateBuilder; use LINE\LINEBot\QuickReplyBuilder; use LINE\LINEBot\QuickReplyBuilder\QuickReplyMessageBuilder; use LINE\LINEBot\QuickReplyBuilder\ButtonBuilder\QuickReplyButtonBuilder; use LINE\LINEBot\TemplateActionBuilder\CameraRollTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\CameraTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\LocationTemplateActionBuilder; $httpClient = new CurlHTTPClient(LINE_MESSAGE_ACCESS_TOKEN); $bot = new LINEBot($httpClient, array('channelSecret' => LINE_MESSAGE_CHANNEL_SECRET)); // คำสั่งรอรับการส่งค่ามาของ LINE Messaging API $content = file_get_contents('php://input'); // กำหนดค่า signature สำหรับตรวจสอบข้อมูลที่ส่งมาว่าเป็นข้อมูลจาก LINE $hash = hash_hmac('sha256', $content, LINE_MESSAGE_CHANNEL_SECRET, true); $signature = base64_encode($hash); // แปลงค่าข้อมูลที่ได้รับจาก LINE เป็น array ของ Event Object $events = $bot->parseEventRequest($content, $signature); $eventObj = $events[0]; // Event Object ของ array แรก // ดึงค่าประเภทของ Event มาไว้ในตัวแปร มีทั้งหมด 7 event $eventType = $eventObj->getType(); // สร้างตัวแปร ไว้เก็บ sourceId ของแต่ละประเภท $userId = NULL; $groupId = NULL; $roomId = NULL; // สร้างตัวแปรเก็บ source id และ source type $sourceId = NULL; $sourceType = NULL; // สร้างตัวแปร replyToken และ replyData สำหรับกรณีใช้ตอบกลับข้อความ $replyToken = NULL; $replyData = NULL; // สร้างตัวแปร ไว้เก็บค่าว่าเป้น Event ประเภทไหน $eventMessage = NULL; $eventPostback = NULL; $eventJoin = NULL; $eventLeave = NULL; $eventFollow = NULL; $eventUnfollow = NULL; $eventBeacon = NULL; $eventAccountLink = NULL; $eventMemberJoined = NULL; $eventMemberLeft = NULL; // เงื่อนไขการกำหนดประเภท Event switch($eventType){ case 'message': $eventMessage = true; break; case 'postback': $eventPostback = true; break; case 'join': $eventJoin = true; break; case 'leave': $eventLeave = true; break; case 'follow': $eventFollow = true; break; case 'unfollow': $eventUnfollow = true; break; case 'beacon': $eventBeacon = true; break; case 'accountLink': $eventAccountLink = true; break; case 'memberJoined': $eventMemberJoined = true; break; case 'memberLeft': $eventMemberLeft = true; break; } // สร้างตัวแปรเก็บค่า userId กรณีเป็น Event ที่เกิดขึ้นใน USER if($eventObj->isUserEvent()){ $userId = $eventObj->getUserId(); $sourceType = "USER"; } // สร้างตัวแปรเก็บค่า groupId กรณีเป็น Event ที่เกิดขึ้นใน GROUP if($eventObj->isGroupEvent()){ $groupId = $eventObj->getGroupId(); $userId = $eventObj->getUserId(); $sourceType = "GROUP"; } // สร้างตัวแปรเก็บค่า roomId กรณีเป็น Event ที่เกิดขึ้นใน ROOM if($eventObj->isRoomEvent()){ $roomId = $eventObj->getRoomId(); $userId = $eventObj->getUserId(); $sourceType = "ROOM"; } // เก็บค่า sourceId ปกติจะเป็นค่าเดียวกันกับ userId หรือ roomId หรือ groupId ขึ้นกับว่าเป็น event แบบใด $sourceId = $eventObj->getEventSourceId(); // ดึงค่า replyToken มาไว้ใช้งาน ทุกๆ Event ที่ไม่ใช่ Leave และ Unfollow Event และ MemberLeft // replyToken ไว้สำหรับส่งข้อความจอบกลับ if(is_null($eventLeave) && is_null($eventUnfollow) && is_null($eventMemberLeft)){ $replyToken = $eventObj->getReplyToken(); } // ส่วนของการทำงาน if(!is_null($events)){ // ถ้า bot ถูก invite เพื่อเข้า Join Event ให้ bot ส่งข้อความใน GROUP ว่าเข้าร่วม GROUP แล้ว if(!is_null($eventJoin)){ $textReplyMessage = "ขอเข้าร่วมด้วยน่ะ $sourceType ID:: ".$sourceId; $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้า bot ออกจาก สนทนา จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventLeave)){ } // ถ้า bot ถูกเพื่มเป้นเพื่อน หรือถูกติดตาม หรือ ยกเลิกการ บล็อก if(!is_null($eventFollow)){ $textReplyMessage = "ขอบคุณที่เป็นเพื่อน และติดตามเรา"; $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้า bot ถูกบล็อก หรือเลิกติดตาม จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventUnfollow)){ } // ถ้ามีสมาชิกคนอื่น เข้ามาร่วมใน room หรือ group // room คือ สมมติเราคุยกับ คนหนึ่งอยู่ แล้วเชิญคนอื่นๆ เข้ามาสนทนาด้วย จะกลายเป็นห้องใหม่ // group คือ กลุ่มที่เราสร้างไว้ มีชื่อกลุ่ม แล้วเราเชิญคนอื่นเข้ามาในกลุ่ม เพิ่มร่วมสนทนาด้วย if(!is_null($eventMemberJoined)){ $arr_joinedMember = $eventObj->getEventBody(); $joinedMember = $arr_joinedMember['joined']['members'][0]; if(!is_null($groupId) || !is_null($roomId)){ if($eventObj->isGroupEvent()){ foreach($joinedMember as $k_user=>$v_user){ if($k_user=="userId"){ $joined_userId = $v_user; } } $response = $bot->getGroupMemberProfile($groupId, $joined_userId); } if($eventObj->isRoomEvent()){ foreach($joinedMember as $k_user=>$v_user){ if($k_user=="userId"){ $joined_userId = $v_user; } } $response = $bot->getRoomMemberProfile($roomId, $joined_userId); } }else{ $response = $bot->getProfile($userId); } if ($response->isSucceeded()) { $userData = $response->getJSONDecodedBody(); // return array // $userData['userId'] // $userData['displayName'] // $userData['pictureUrl'] // $userData['statusMessage'] $textReplyMessage = 'สวัสดีครับ คุณ '.$userData['displayName']; }else{ $textReplyMessage = 'สวัสดีครับ ยินดีต้อนรับ'; } // $textReplyMessage = "ยินดีต้อนรับกลับมาอีกครั้ง ".json_encode($joinedMember); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้ามีสมาชิกคนอื่น ออกจากก room หรือ group จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventMemberLeft)){ } // ถ้ามีกาาเชื่อมกับบัญชี LINE กับระบบสมาชิกของเว็บไซต์เรา if(!is_null($eventAccountLink)){ // หลักๆ ส่วนนี้ใช้สำรหบัเพิ่มความภัยในการเชื่อมบัญตี LINE กับระบบสมาชิกของเว็บไซต์เรา $textReplyMessage = "AccountLink ทำงาน ".$replyToken." Nonce: ".$eventObj->getNonce(); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้าเป็น Postback Event if(!is_null($eventPostback)){ $dataPostback = NULL; $paramPostback = NULL; // แปลงข้อมูลจาก Postback Data เป็น array parse_str($eventObj->getPostbackData(),$dataPostback); // ดึงค่า params กรณีมีค่า params $paramPostback = $eventObj->getPostbackParams(); // ทดสอบแสดงข้อความที่เกิดจาก Postaback Event $textReplyMessage = "ข้อความจาก Postback Event Data = "; $textReplyMessage.= json_encode($dataPostback); $textReplyMessage.= json_encode($paramPostback); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้าเป้น Message Event if(!is_null($eventMessage)){ // สร้างตัวแปรเก็ยค่าประเภทของ Message จากทั้งหมด 7 ประเภท $typeMessage = $eventObj->getMessageType(); // text | image | sticker | location | audio | video | file // เก็บค่า id ของข้อความ $idMessage = $eventObj->getMessageId(); // ถ้าเป็นข้อความ if($typeMessage=='text'){ $userMessage = $eventObj->getText(); // เก็บค่าข้อความที่ผู้ใช้พิมพ์ } // ถ้าเป็น image if($typeMessage=='image'){ } // ถ้าเป็น audio if($typeMessage=='audio'){ } // ถ้าเป็น video if($typeMessage=='video'){ } // ถ้าเป็น file if($typeMessage=='file'){ $FileName = $eventObj->getFileName(); $FileSize = $eventObj->getFileSize(); } // ถ้าเป็น image หรือ audio หรือ video หรือ file และต้องการบันทึกไฟล์ if(preg_match('/image|audio|video|file/',$typeMessage)){ $responseMedia = $bot->getMessageContent($idMessage); if ($responseMedia->isSucceeded()) { // คำสั่ง getRawBody() ในกรณีนี้ จะได้ข้อมูลส่งกลับมาเป็น binary // เราสามารถเอาข้อมูลไปบันทึกเป็นไฟล์ได้ $dataBinary = $responseMedia->getRawBody(); // return binary // ดึงข้อมูลประเภทของไฟล์ จาก header $fileType = $responseMedia->getHeader('Content-Type'); switch ($fileType){ case (preg_match('/^application/',$fileType) ? true : false): // $fileNameSave = $FileName; // ถ้าต้องการบันทึกเป็นชื่อไฟล์เดิม $arr_ext = explode(".",$FileName); $ext = array_pop($arr_ext); $fileNameSave = time().".".$ext; break; case (preg_match('/^image/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $ext = ($ext=='jpeg' || $ext=='jpg')?"jpg":$ext; $fileNameSave = time().".".$ext; break; case (preg_match('/^audio/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $fileNameSave = time().".".$ext; break; case (preg_match('/^video/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $fileNameSave = time().".".$ext; break; } $botDataFolder = 'botdata/'; // โฟลเดอร์หลักที่จะบันทึกไฟล์ $botDataUserFolder = $botDataFolder.$userId; // มีโฟลเดอร์ด้านในเป็น userId อีกขั้น if(!file_exists($botDataUserFolder)) { // ตรวจสอบถ้ายังไม่มีให้สร้างโฟลเดอร์ userId mkdir($botDataUserFolder, 0777, true); } // กำหนด path ของไฟล์ที่จะบันทึก $fileFullSavePath = $botDataUserFolder.'/'.$fileNameSave; // file_put_contents($fileFullSavePath,$dataBinary); // เอา comment ออก ถ้าต้องการทำการบันทึกไฟล์ $textReplyMessage = "บันทึกไฟล์เรียบร้อยแล้ว $fileNameSave"; $replyData = new TextMessageBuilder($textReplyMessage); // $failMessage = json_encode($fileType); // $failMessage = json_encode($responseMedia->getHeaders()); $replyData = new TextMessageBuilder($failMessage); }else{ $failMessage = json_encode($idMessage.' '.$responseMedia->getHTTPStatus() . ' ' . $responseMedia->getRawBody()); $replyData = new TextMessageBuilder($failMessage); } } // ถ้าเป็น sticker if($typeMessage=='sticker'){ $packageId = $eventObj->getPackageId(); $stickerId = $eventObj->getStickerId(); } // ถ้าเป็น location if($typeMessage=='location'){ $locationTitle = $eventObj->getTitle(); $locationAddress = $eventObj->getAddress(); $locationLatitude = $eventObj->getLatitude(); $locationLongitude = $eventObj->getLongitude(); } switch ($typeMessage){ // กำหนดเงื่อนไขการทำงานจาก ประเภทของ message case 'text': // ถ้าเป็นข้อความ $userMessage = strtolower($userMessage); // แปลงเป็นตัวเล็ก สำหรับทดสอบ switch ($userMessage) { case "t_b": // กำหนด action 4 ปุ่ม 4 ประเภท $actionBuilder = array( new MessageTemplateActionBuilder( 'Message Template',// ข้อความแสดงในปุ่ม 'This is Text' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ), new UriTemplateActionBuilder( 'Uri Template', // ข้อความแสดงในปุ่ม 'https://www.ninenik.com' ), new DatetimePickerTemplateActionBuilder( 'Datetime Picker', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'reservation', 'person'=>5 )), // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event 'datetime', // date | time | datetime รูปแบบข้อมูลที่จะส่ง ในที่นี้ใช้ datatime substr_replace(date("Y-m-d H:i"),'T',10,1), // วันที่ เวลา ค่าเริ่มต้นที่ถูกเลือก substr_replace(date("Y-m-d H:i",strtotime("+5 day")),'T',10,1), //วันที่ เวลา มากสุดที่เลือกได้ substr_replace(date("Y-m-d H:i"),'T',10,1) //วันที่ เวลา น้อยสุดที่เลือกได้ ), new PostbackTemplateActionBuilder( 'Postback', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'buy', 'item'=>100 )) // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event // 'Postback Text' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ), ); $imageUrl = 'https://www.mywebsite.com/imgsrc/photos/w/simpleflower'; $replyData = new TemplateMessageBuilder('Button Template', new ButtonTemplateBuilder( 'button template builder', // กำหนดหัวเรื่อง 'Please select', // กำหนดรายละเอียด $imageUrl, // กำหนด url รุปภาพ $actionBuilder // กำหนด action object ) ); break; case "p": // ถ้าขณะนั้นเป็นการสนทนาใน ROOM หรือ GROUP if(!is_null($groupId) || !is_null($roomId)){ if($eventObj->isGroupEvent()){// ถ้าอยู่ใน GROUP $response = $bot->getGroupMemberProfile($groupId, $userId); // ดึงข้อมูลผู้ใช้ที่คุยกับ bot } if($eventObj->isRoomEvent()){ // ถ้าอยู่ใน ROOM $response = $bot->getRoomMemberProfile($roomId, $userId);// ดึงข้อมูลผู้ใช้ที่คุยกับ bot } }else{ // ถ้าเป็นการสนทนา ระหว่าง BOT $response = $bot->getProfile($userId); } if ($response->isSucceeded()) { $userData = $response->getJSONDecodedBody(); // return array // $userData['userId'] // $userData['displayName'] // $userData['pictureUrl'] // $userData['statusMessage'] $textReplyMessage = 'สวัสดีครับ คุณ '.$userData['displayName']; }else{ $textReplyMessage = 'สวัสดีครับ คุณคือใคร'; } $replyData = new TextMessageBuilder($textReplyMessage); break; case "l": // เงื่อนไขทดสอบถ้ามีใครพิมพ์ L ใน GROUP / ROOM แล้วให้ bot ออกจาก GROUP / ROOM $sourceId = $eventObj->getEventSourceId(); if($eventObj->isGroupEvent()){ $bot->leaveGroup($sourceId); } if($eventObj->isRoomEvent()){ $bot->leaveRoom($sourceId); } break; case "a": // เงื่อนไขกรณีต้องการ เชื่อม Line account กับ ระบบสมาชิกของเว็บไซต์เรา $response = $httpClient->post("https://api.line.me/v2/bot/user/".urlencode($userId)."/linkToken",array()); $result = json_decode($response->getRawBody(),TRUE); // กำหนด action 4 ปุ่ม 4 ประเภท $actionBuilder = array( new UriTemplateActionBuilder( 'Account Link', // ข้อความแสดงในปุ่ม 'https://www.example.com/link.php?linkToken='.$result['linkToken'] ) ); $imageUrl = ''; //กำหนด url รุปภาพ ถ้ามี $replyData = new TemplateMessageBuilder('Button Template', new ButtonTemplateBuilder( 'Account Link', // กำหนดหัวเรื่อง 'Please select', // กำหนดรายละเอียด $imageUrl, // กำหนด url รุปภาพ $actionBuilder // กำหนด action object ) ); break; default: $textReplyMessage = " คุณไม่ได้พิมพ์ ค่า ตามที่กำหนด"; $replyData = new TextMessageBuilder($textReplyMessage); break; } break; default: if(!is_null($replyData)){ }else{ // กรณีทดสอบเงื่อนไขอื่นๆ ผู้ใช้ไม่ได้ส่งเป็นข้อความ $textReplyMessage = 'สวัสดีครับ คุณ '.$typeMessage; $replyData = new TextMessageBuilder($textReplyMessage); } break; } } } $response = $bot->replyMessage($replyToken,$replyData); if ($response->isSucceeded()) { echo 'Succeeded!'; return; } // Failed echo $response->getHTTPStatus() . ' ' . $response->getRawBody(); ?>
จะได้ไฟล์ bot.php ใหม่เป็นดังนี้ (ตัดมาบางส่วน)
........................... ....................... ................ $sourceId = $eventObj->getEventSourceId(); // ดึงค่า replyToken มาไว้ใช้งาน ทุกๆ Event ที่ไม่ใช่ Leave และ Unfollow Event และ MemberLeft // replyToken ไว้สำหรับส่งข้อความจอบกลับ if(is_null($eventLeave) && is_null($eventUnfollow) && is_null($eventMemberLeft)){ $replyToken = $eventObj->getReplyToken(); } //////////////////////////// ส่วนของการทำงาน include_once("bot_action.php"); ////////////////////////// $response = $bot->replyMessage($replyToken,$replyData); if ($response->isSucceeded()) { echo 'Succeeded!'; return; } // Failed echo $response->getHTTPStatus() . ' ' . $response->getRawBody();
ไฟล์ bot_action.php
<?php ///////////// ส่วนของการเรียกใช้งาน class ผ่าน namespace use LINE\LINEBot; use LINE\LINEBot\HTTPClient; use LINE\LINEBot\HTTPClient\CurlHTTPClient; use LINE\LINEBot\Event; use LINE\LINEBot\Event\BaseEvent; use LINE\LINEBot\Event\MessageEvent; use LINE\LINEBot\Event\AccountLinkEvent; use LINE\LINEBot\Event\MemberJoinEvent; use LINE\LINEBot\MessageBuilder; use LINE\LINEBot\MessageBuilder\TextMessageBuilder; use LINE\LINEBot\MessageBuilder\StickerMessageBuilder; use LINE\LINEBot\MessageBuilder\ImageMessageBuilder; use LINE\LINEBot\MessageBuilder\LocationMessageBuilder; use LINE\LINEBot\MessageBuilder\AudioMessageBuilder; use LINE\LINEBot\MessageBuilder\VideoMessageBuilder; use LINE\LINEBot\ImagemapActionBuilder; use LINE\LINEBot\ImagemapActionBuilder\AreaBuilder; use LINE\LINEBot\ImagemapActionBuilder\ImagemapMessageActionBuilder ; use LINE\LINEBot\ImagemapActionBuilder\ImagemapUriActionBuilder; use LINE\LINEBot\MessageBuilder\Imagemap\BaseSizeBuilder; use LINE\LINEBot\MessageBuilder\ImagemapMessageBuilder; use LINE\LINEBot\MessageBuilder\MultiMessageBuilder; use LINE\LINEBot\TemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\DatetimePickerTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\MessageTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\PostbackTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateMessageBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ButtonTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselColumnTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ConfirmTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ImageCarouselTemplateBuilder; use LINE\LINEBot\MessageBuilder\TemplateBuilder\ImageCarouselColumnTemplateBuilder; use LINE\LINEBot\QuickReplyBuilder; use LINE\LINEBot\QuickReplyBuilder\QuickReplyMessageBuilder; use LINE\LINEBot\QuickReplyBuilder\ButtonBuilder\QuickReplyButtonBuilder; use LINE\LINEBot\TemplateActionBuilder\CameraRollTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\CameraTemplateActionBuilder; use LINE\LINEBot\TemplateActionBuilder\LocationTemplateActionBuilder; // ส่วนของการทำงาน if(!is_null($events)){ // ถ้า bot ถูก invite เพื่อเข้า Join Event ให้ bot ส่งข้อความใน GROUP ว่าเข้าร่วม GROUP แล้ว if(!is_null($eventJoin)){ $textReplyMessage = "ขอเข้าร่วมด้วยน่ะ $sourceType ID:: ".$sourceId; $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้า bot ออกจาก สนทนา จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventLeave)){ } // ถ้า bot ถูกเพื่มเป้นเพื่อน หรือถูกติดตาม หรือ ยกเลิกการ บล็อก if(!is_null($eventFollow)){ $textReplyMessage = "ขอบคุณที่เป็นเพื่อน และติดตามเรา"; $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้า bot ถูกบล็อก หรือเลิกติดตาม จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventUnfollow)){ } // ถ้ามีสมาชิกคนอื่น เข้ามาร่วมใน room หรือ group // room คือ สมมติเราคุยกับ คนหนึ่งอยู่ แล้วเชิญคนอื่นๆ เข้ามาสนทนาด้วย จะกลายเป็นห้องใหม่ // group คือ กลุ่มที่เราสร้างไว้ มีชื่อกลุ่ม แล้วเราเชิญคนอื่นเข้ามาในกลุ่ม เพิ่มร่วมสนทนาด้วย if(!is_null($eventMemberJoined)){ $arr_joinedMember = $eventObj->getEventBody(); $joinedMember = $arr_joinedMember['joined']['members'][0]; if(!is_null($groupId) || !is_null($roomId)){ if($eventObj->isGroupEvent()){ foreach($joinedMember as $k_user=>$v_user){ if($k_user=="userId"){ $joined_userId = $v_user; } } $response = $bot->getGroupMemberProfile($groupId, $joined_userId); } if($eventObj->isRoomEvent()){ foreach($joinedMember as $k_user=>$v_user){ if($k_user=="userId"){ $joined_userId = $v_user; } } $response = $bot->getRoomMemberProfile($roomId, $joined_userId); } }else{ $response = $bot->getProfile($userId); } if ($response->isSucceeded()) { $userData = $response->getJSONDecodedBody(); // return array // $userData['userId'] // $userData['displayName'] // $userData['pictureUrl'] // $userData['statusMessage'] $textReplyMessage = 'สวัสดีครับ คุณ '.$userData['displayName']; }else{ $textReplyMessage = 'สวัสดีครับ ยินดีต้อนรับ'; } // $textReplyMessage = "ยินดีต้อนรับกลับมาอีกครั้ง ".json_encode($joinedMember); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้ามีสมาชิกคนอื่น ออกจากก room หรือ group จะไม่สามารถส่งข้อความกลับได้ เนื่องจากไม่มี replyToken if(!is_null($eventMemberLeft)){ } // ถ้ามีกาาเชื่อมกับบัญชี LINE กับระบบสมาชิกของเว็บไซต์เรา if(!is_null($eventAccountLink)){ // หลักๆ ส่วนนี้ใช้สำรหบัเพิ่มความภัยในการเชื่อมบัญตี LINE กับระบบสมาชิกของเว็บไซต์เรา $textReplyMessage = "AccountLink ทำงาน ".$replyToken." Nonce: ".$eventObj->getNonce(); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้าเป็น Postback Event if(!is_null($eventPostback)){ $dataPostback = NULL; $paramPostback = NULL; // แปลงข้อมูลจาก Postback Data เป็น array parse_str($eventObj->getPostbackData(),$dataPostback); // ดึงค่า params กรณีมีค่า params $paramPostback = $eventObj->getPostbackParams(); // ทดสอบแสดงข้อความที่เกิดจาก Postaback Event $textReplyMessage = "ข้อความจาก Postback Event Data = "; $textReplyMessage.= json_encode($dataPostback); $textReplyMessage.= json_encode($paramPostback); $replyData = new TextMessageBuilder($textReplyMessage); } // ถ้าเป้น Message Event if(!is_null($eventMessage)){ // สร้างตัวแปรเก็ยค่าประเภทของ Message จากทั้งหมด 7 ประเภท $typeMessage = $eventObj->getMessageType(); // text | image | sticker | location | audio | video | file // เก็บค่า id ของข้อความ $idMessage = $eventObj->getMessageId(); // ถ้าเป็นข้อความ if($typeMessage=='text'){ $userMessage = $eventObj->getText(); // เก็บค่าข้อความที่ผู้ใช้พิมพ์ } // ถ้าเป็น image if($typeMessage=='image'){ } // ถ้าเป็น audio if($typeMessage=='audio'){ } // ถ้าเป็น video if($typeMessage=='video'){ } // ถ้าเป็น file if($typeMessage=='file'){ $FileName = $eventObj->getFileName(); $FileSize = $eventObj->getFileSize(); } // ถ้าเป็น image หรือ audio หรือ video หรือ file และต้องการบันทึกไฟล์ if(preg_match('/image|audio|video|file/',$typeMessage)){ $responseMedia = $bot->getMessageContent($idMessage); if ($responseMedia->isSucceeded()) { // คำสั่ง getRawBody() ในกรณีนี้ จะได้ข้อมูลส่งกลับมาเป็น binary // เราสามารถเอาข้อมูลไปบันทึกเป็นไฟล์ได้ $dataBinary = $responseMedia->getRawBody(); // return binary // ดึงข้อมูลประเภทของไฟล์ จาก header $fileType = $responseMedia->getHeader('Content-Type'); switch ($fileType){ case (preg_match('/^application/',$fileType) ? true : false): // $fileNameSave = $FileName; // ถ้าต้องการบันทึกเป็นชื่อไฟล์เดิม $arr_ext = explode(".",$FileName); $ext = array_pop($arr_ext); $fileNameSave = time().".".$ext; break; case (preg_match('/^image/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $ext = ($ext=='jpeg' || $ext=='jpg')?"jpg":$ext; $fileNameSave = time().".".$ext; break; case (preg_match('/^audio/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $fileNameSave = time().".".$ext; break; case (preg_match('/^video/',$fileType) ? true : false): list($typeFile,$ext) = explode("/",$fileType); $fileNameSave = time().".".$ext; break; } $botDataFolder = 'botdata/'; // โฟลเดอร์หลักที่จะบันทึกไฟล์ $botDataUserFolder = $botDataFolder.$userId; // มีโฟลเดอร์ด้านในเป็น userId อีกขั้น if(!file_exists($botDataUserFolder)) { // ตรวจสอบถ้ายังไม่มีให้สร้างโฟลเดอร์ userId mkdir($botDataUserFolder, 0777, true); } // กำหนด path ของไฟล์ที่จะบันทึก $fileFullSavePath = $botDataUserFolder.'/'.$fileNameSave; // file_put_contents($fileFullSavePath,$dataBinary); // เอา comment ออก ถ้าต้องการทำการบันทึกไฟล์ $textReplyMessage = "บันทึกไฟล์เรียบร้อยแล้ว $fileNameSave"; $replyData = new TextMessageBuilder($textReplyMessage); // $failMessage = json_encode($fileType); // $failMessage = json_encode($responseMedia->getHeaders()); $replyData = new TextMessageBuilder($failMessage); }else{ $failMessage = json_encode($idMessage.' '.$responseMedia->getHTTPStatus() . ' ' . $responseMedia->getRawBody()); $replyData = new TextMessageBuilder($failMessage); } } // ถ้าเป็น sticker if($typeMessage=='sticker'){ $packageId = $eventObj->getPackageId(); $stickerId = $eventObj->getStickerId(); } // ถ้าเป็น location if($typeMessage=='location'){ $locationTitle = $eventObj->getTitle(); $locationAddress = $eventObj->getAddress(); $locationLatitude = $eventObj->getLatitude(); $locationLongitude = $eventObj->getLongitude(); } switch ($typeMessage){ // กำหนดเงื่อนไขการทำงานจาก ประเภทของ message case 'text': // ถ้าเป็นข้อความ $userMessage = strtolower($userMessage); // แปลงเป็นตัวเล็ก สำหรับทดสอบ switch ($userMessage) { case "ot": // ทำอื่นๆ break; case "qr": $postback = new PostbackTemplateActionBuilder( 'Postback', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'buy', 'item'=>100 )), // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event 'Buy' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ); $txtMsg = new MessageTemplateActionBuilder( 'ข้อความภาษาไทย',// ข้อความแสดงในปุ่ม 'thai' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ); $datetimePicker = new DatetimePickerTemplateActionBuilder( 'Datetime Picker', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'reservation', 'person'=>5 )), // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event 'datetime', // date | time | datetime รูปแบบข้อมูลที่จะส่ง ในที่นี้ใช้ datatime substr_replace(date("Y-m-d H:i"),'T',10,1), // วันที่ เวลา ค่าเริ่มต้นที่ถูกเลือก substr_replace(date("Y-m-d H:i",strtotime("+5 day")),'T',10,1), //วันที่ เวลา มากสุดที่เลือกได้ substr_replace(date("Y-m-d H:i"),'T',10,1) //วันที่ เวลา น้อยสุดที่เลือกได้ ); $quickReply = new QuickReplyMessageBuilder( array( new QuickReplyButtonBuilder(new LocationTemplateActionBuilder('Location')), new QuickReplyButtonBuilder(new CameraTemplateActionBuilder('Camera')), new QuickReplyButtonBuilder(new CameraRollTemplateActionBuilder('Camera roll')), new QuickReplyButtonBuilder($postback), new QuickReplyButtonBuilder($datetimePicker), new QuickReplyButtonBuilder( $txtMsg, "https://www.ninenik.com/images/ninenik_page_logo.png" ), ) ); $textReplyMessage = "ส่งพร้อม quick reply "; $replyData = new TextMessageBuilder($textReplyMessage,$quickReply); break; default: $textReplyMessage = " คุณไม่ได้พิมพ์ ค่า ตามที่กำหนด"; $replyData = new TextMessageBuilder($textReplyMessage); break; } break; default: if(!is_null($replyData)){ }else{ // กรณีทดสอบเงื่อนไขอื่นๆ ผู้ใช้ไม่ได้ส่งเป็นข้อความ $textReplyMessage = 'สวัสดีครับ คุณ '.$typeMessage; $replyData = new TextMessageBuilder($textReplyMessage); } break; } } } ?>
ในส่วนของ ไฟล์ bot_action.php เราจะตัดในส่วนของ type ที่ส่งเข้ามาแบบ text ให้เหลือเงื่อนไขเฉพาะที่จะทดสอบสำหรับ
การใช้งาน quick reply คือ เมือผู้ใช้เพิ่ม qr เข้ามา
ดูเฉพาะส่วนของการกำหนด quick reply
case "qr": // การใช้งาน postback action $postback = new PostbackTemplateActionBuilder( 'Postback', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'buy', 'item'=>100 )), // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event 'Buy' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ); // การใช้งาน message action $txtMsg = new MessageTemplateActionBuilder( 'ข้อความภาษาไทย',// ข้อความแสดงในปุ่ม 'thai' // ข้อความที่จะแสดงฝั่งผู้ใช้ เมื่อคลิกเลือก ); // การใช้งาน datetime picker action $datetimePicker = new DatetimePickerTemplateActionBuilder( 'Datetime Picker', // ข้อความแสดงในปุ่ม http_build_query(array( 'action'=>'reservation', 'person'=>5 )), // ข้อมูลที่จะส่งไปใน webhook ผ่าน postback event 'datetime', // date | time | datetime รูปแบบข้อมูลที่จะส่ง ในที่นี้ใช้ datatime substr_replace(date("Y-m-d H:i"),'T',10,1), // วันที่ เวลา ค่าเริ่มต้นที่ถูกเลือก substr_replace(date("Y-m-d H:i",strtotime("+5 day")),'T',10,1), //วันที่ เวลา มากสุดที่เลือกได้ substr_replace(date("Y-m-d H:i"),'T',10,1) //วันที่ เวลา น้อยสุดที่เลือกได้ ); // การสร้างปุ่ม quick reply $quickReply = new QuickReplyMessageBuilder( array( new QuickReplyButtonBuilder(new LocationTemplateActionBuilder('Location')), new QuickReplyButtonBuilder(new CameraTemplateActionBuilder('Camera')), new QuickReplyButtonBuilder(new CameraRollTemplateActionBuilder('Camera roll')), new QuickReplyButtonBuilder($postback), new QuickReplyButtonBuilder($datetimePicker), new QuickReplyButtonBuilder( $txtMsg, "https://www.ninenik.com/images/ninenik_page_logo.png" ), ) ); $textReplyMessage = "ส่งพร้อม quick reply "; $replyData = new TextMessageBuilder($textReplyMessage,$quickReply); break;
สังเกตในส่วนของการสร้างปุ่ม quick reply ในตัวอย่างด้านบน เราสร้างแค่ 6 ปุ่ม โดย 3 ปุ่มแรกจะเป็น location , camera
และ camera roll ซึ่ง action ของทั้ง 3 แบบจะใช้รูปค่าเริ่มต้น ไม่สามารถแก้ไขรูปไอคอนได้ เราสามารถเปลี่ยนข้อความ
ที่จะแสดงเป็นค่าที่ต้องการเช่น
new LocationTemplateActionBuilder('เลือกตำแหน่ง') new CameraTemplateActionBuilder('ถ่ายรูป') new CameraRollTemplateActionBuilder('เลือกรูปภาพ')
รูปตัวอย่างปุ่ม quick reply
ปุ่มที่ 4 กับ 5 เรากำหนด action เป็น postback กับ datatime picker โดยแยก action มากำหนดเป็นตัวแปร
แล้วค่อยเรียกใช้ในการสร้างปุ่ม quick reply
ปุ่มทั้งสองนี้เราไม่ได้กำหนดรูปไอคอน ปุ่มจึงไม่มีไอคอนแสดงด้านหน้า
รูปตัวอย่างปุ่ม quick reply
สำหรับปุ่มสุดท้ายเป็นปุ่มที่ 6 จะเห็นว่า เรากำหนดรูปไอคอนเพิ่มเข้าไป และใช้ action เป็น message action
ผลลัพธ์ก็จะแสดงตามรูปด้านบน
หวังว่าแนวทางการใช้งาน quick reply จะสามารถเป็นไอเดียสำหรับนำไปประยุกต์ต่อไป