LINE Messaging API SDK for PHP 安裝到 synology NAS

今天想使用之前串接的 LINE 機器人來賣eSIM 發現不會動了,原來是改版了

https://github.com/line/line-bot-sdk-php

首先,這是官方的 github ,有大部分的教學文件

接下來發現 NAS 似乎無法使用建議的安裝方式

composer require linecorp/line-bot-sdk

而且目前該API 需要 php 8.1 以上的版本

Requirements
PHP 8.1 or later

這邊使用macbook 來先下指令

mkdir line
cd line

vi composer.json
內容填入
{
    "require": {
        "linecorp/line-bot-sdk": "^11.0",
        "line/openapi": "^1.0"
    }
}
來指定版本(這應該是非必要的)

composer require linecorp/line-bot-sdk

之後將會在line 資料夾內得到一個vendor的資料夾

到此最麻煩的一步已經處理完畢。

接下來到NAS 上安裝php 8.1 以上的版本,並指定到webhook 的服務上即可。

這是簡單的lineHook.php,可以直接拿來串接,autoload.php 會幫忙處理幾乎所有串接的東西,下方use 的部分需要根據需求自行加上

<?php
require_once __DIR__ . '/vendor/autoload.php';

use GuzzleHttp\Client;
use LINE\Clients\MessagingApi\Configuration;
use LINE\Clients\MessagingApi\Api\MessagingApiApi;
use LINE\Clients\MessagingApi\Model\ReplyMessageRequest;
use LINE\Clients\MessagingApi\Model\TextMessage;
use LINE\Clients\MessagingApi\Model\ImageMessage;
use LINE\Clients\MessagingApi\Model\TemplateMessage;
use LINE\Clients\MessagingApi\Model\ButtonsTemplate;
use LINE\Clients\MessagingApi\Model\PostbackAction;
use LINE\Clients\MessagingApi\Model\ConfirmTemplate;
use LINE\Clients\MessagingApi\Model\URIAction;
use LINE\Clients\MessagingApi\Model\MessageAction;
use LINE\Clients\MessagingApi\Model\CarouselTemplate;
use LINE\Clients\MessagingApi\Model\CarouselColumn;
use LINE\Constants\MessageType;

$channelSecret = "你的channelSecret";
$channelToken = "你的channelToken";

// 設定 HTTP 客戶端和配置
$client = new Client();
$config = new Configuration();
$config->setAccessToken($channelToken);
$messagingApi = new MessagingApiApi($client, $config);

// 接收並驗證 webhook 請求
$signature = $_SERVER['HTTP_' . 'X_LINE_SIGNATURE'];
$body = file_get_contents('php://input');

// 簡單驗證 signature (手動檢查)
$hash = hash_hmac('sha256', $body, $channelSecret, true);
$signatureCheck = base64_encode($hash);

if ($signature !== $signatureCheck) {
    error_log("Invalid signature");
    http_response_code(400);
    exit;
}

// 解析事件 (手動處理 JSON)
$events = json_decode($body, true);

if (isset($events['events'])) {
    foreach ($events['events'] as $event) {
    	$tmpMsg = "";
        if ($event['type'] === 'message' && $event['message']['type'] === 'text') { //文字訊息
            $replyToken = $event['replyToken'];
            $text = $event['message']['text'];
		
            $tmpMsg = "你所輸入的: ".$text;
            // 準備回覆訊息
            $message[] = new TextMessage([
                'type' => 'text',
                'text' => $tmpMsg
            ]);
		        
        	
            $request = new ReplyMessageRequest([
                'replyToken' => $replyToken,
                'messages' => $message
            ]);

            // 發送回覆
            try {
                $response = $messagingApi->replyMessage($request);
                error_log("Reply succeeded");
            } catch (\LINE\Clients\MessagingApi\ApiException $e) {
                error_log("Reply failed: " . $e->getCode() . " " . $e->getResponseBody());
            }
        }
        else  if ($event['type'] === 'postback') {
            $replyToken = $event['replyToken'];
            $data = $event['postback']['data']; // e.g. "plan=A"
            $userId = $event['source']['userId'] ?? "NO"; // 取得 userId
            $message = array();
                $replyText = "你選的選項".$data;
                $message[] = new TextMessage([
                    'type' => 'text',
                    'text' => $replyText
                ]);
            

            $request = new ReplyMessageRequest([
                'replyToken' => $replyToken,
                'messages' => $message
            ]);

            try {
                $response = $messagingApi->replyMessage($request);
                error_log("Reply succeeded");
            } catch (\LINE\Clients\MessagingApi\ApiException $e) {
                error_log("Reply failed: " . $e->getCode() . " " . $e->getResponseBody());
            }
        }
        else if($event['type'] === 'follow'){  //加為好友觸發
            // 準備回覆訊息
            $message = new TextMessage([
                'type' => 'text',
                'text' => '您好,這裡是QuantoShop eSIM 自助機器人\n請輸入您所要查詢的 Order ID'
            ]);
            $request = new ReplyMessageRequest([
                'replyToken' => $replyToken,
                'messages' => [$message]
            ]);

            // 發送回覆
            try {
                $response = $messagingApi->replyMessage($request);
                error_log("Reply succeeded");
            } catch (\LINE\Clients\MessagingApi\ApiException $e) {
                error_log("Reply failed: " . $e->getCode() . " " . $e->getResponseBody());
            }
        }
    }
}
?>

目前這個版本我可以做到直接回應、主動傳送訊息,但是免費的主動傳送一個月只有200則。

附上我的vendor資料夾,這應該可以直接拿來用。

以下是 Carousel 可用的範例

function createCarouselMessage_Country($plans){
    $message = array();
    if(count($plans) == 0){
        $message[] = new TextMessage([
            'type' => 'text',
            'text' => '目前沒有任何方案'
        ]);
    }else{
        $columnAry = array();
        for($i = 0;$i < count($plans); $i++){
            $column = new CarouselColumn();
            $column->setThumbnailImageUrl("https://quantoyo.com/國家.png");
            $column->setImageBackgroundColor("#F0F0F0");
            $column->setTitle($plans[$i]['location']);
            $column->setText('請選擇方案類型');
            $column->setActions([
                new PostbackAction([
                    'type' => 'postback',
                    'label' => "流量型方案",
                    'data' => $plans[$i]['locationCode']
                ])
            ]);
            $columnAry[] = $column;
            if(count($columnAry) == 10){        //Carousel 最多10個
                break;
            }
        }
        // 建立 Carousel Template
        $carousel = new CarouselTemplate();
        $carousel->settype('carousel');
        $carousel->setColumns($columnAry);

        // 加入要發送的訊息陣列
        $message[] = new TemplateMessage([
            'type' => 'template',
            'altText' => '請選擇國家',
            'template' => $carousel
        ]);
    }
    return $message;
}

以下是 Template 可用範例


function createTemplateMessage_Country($plans){
    $message = array();
    if(count($plans) == 0){
        $message[] = new TextMessage([
            'type' => 'text',
            'text' => '目前沒有任何方案'
        ]);
    }else{
        $locationMsgAry = array();
        $plansMsgAry = array();
        for($i = 0;$i < count($plans); $i++){
            $tmpPostback = new PostbackAction([
                'type' => 'postback',
                'label' => limitStr($plans[$i]['location'],20),
                'data' => $plans[$i]['locationCode']
            ]);
            $plansMsgAry[] = $tmpPostback;
            if(count($plansMsgAry) == 4  || $i == count($plans) -1){
                $locationMsgAry[] = $plansMsgAry;
                $plansMsgAry = array();
            }
        }
        for($i = 0;$i < count($locationMsgAry); $i++){
            $message[] = new TemplateMessage([
                'type' => 'template',
                'altText' => '請選擇國家',
                'template' => new ButtonsTemplate([
                    'type' => 'buttons',
                    'title' => '國家選擇',
                    'text' => '請選擇你要的國家:',
                    'actions' => $locationMsgAry[$i]
                ])
            ]);
            if(count($message) > 4)break;
        }
    }
    return $message;
}

發佈留言