Site icon Soul & Shell Blog

用 PHP 實現 Line Message API 接收系統訊息

簡單的 PHP Line Message API 串接教學

其實我不是要開發 Chat Bot,只是以前寫了很多系統管理 Linux Shell Script,會每天發送系統狀態,或者當系統發生錯誤時就會發送 Email 等等動作。久而久之越來越覺得 Email 不好用,有時候只是想要被主動通知每天系統的資源狀態、備份狀態、統計報表等等。每天發送一封 Email 實在有些擾人,想說改用 IM 來解決這個問題好了,這樣每天起床看一下就好。其實用 Slack 也是一個好方法,Slack 發送訊息可以參考我以前的廢文 (整合 Slack 發送訊息取代傳統 Email 通知),但後來發現,有時候訊息想要送給沒有裝 Slack 的人,就有困難了。Line 算是台灣最普遍的通訊 App,接 Line 算是比較方便的做法。接上系統後順便分享一下作法,這個作法透過 PHP 實現,而且只需要 PHP Curl Library 就可以進行串接,算是非常乾淨與簡單的作法。

註冊 Line Developer 與啟用 Message API

開始前先到 Line Developers 申請開發者帳號,進入後選取「Add new provider」按鈕,如下:

輸入一個「Provider name」然後按下「Create」

接著選取「Messaging API」

輸入 App name, App description... 等等相關資料後,選擇「Developer Trial」試用版,按下「Create」即可。映像中試用版好像可以有 50 個使用者加入,如下:

 

建立好「Messaging API」之後接著進行設定,點選「Configuration not yet complete」進入設定畫面,如下:

先將畫面拉到下面「Messaging settings」Block,設定這裡有幾件事要做:

  1. 按下 Issue 產生 Access Token
  2. 啟用 Webhooks
  3. 輸入你的 Webhooks URL (必須要支援 HTTPS 連線,可以使用免費的 Let’s Encrypt 架設,這裡剛好也有一篇免費憑證教學廢文可以參考)

首先要產生讓 API 進行驗證的權杖 (Token),按下「Issue」後選擇 0 hours 產生一個不會過期的 Access Token,如下:

接著設定 WebHooks, Webhook URL 設定一個有 HTTPS 的網址,當 Line 收到訊息時,會呼叫這個網址,我們等等會透過 PHP 實作這裡的程式碼。設定畫面如下:

如何設計 Line Bot Login?

由於我其實只是要用來接收一些日常的系統 Notification,但我也不希望沒事就有人透過「加入好友」來接收我的訊息。Line 不像 WeChat 有 HTML5 API 可以用,想了想只好透過問答的方式進行「認證」,有點像是玩遊戲與 NPC 對話解任務的概念。

以下認證的範例其實很簡單,設計的想法有點像是「芝麻開門」的概念,只要說出通關密語,Server 就會把這個使用者的 User ID 存起來,未來透過 Push API 發送訊息的時候就送給這些有認證的使用者。認證後使用者可以輸入「bye」來取消註冊,未來就不會再收到 Push Message 了。

設計 PHP 程式透過 Reply API 取得 User ID

以下是接收訊息的 Webhooks 伺服器端 PHP 程式碼,實作了 NPC 通關密語對話功能 (下面的 reply.php 可以由 GitHub 取得)。

<?php

$channelAccessToken = '{Your_Access_Token}';
$password = '{Login_Password}';      // user login password
$dbFilePath = 'line-db.json';        // user info database file path

if (!file_exists($dbFilePath)) {
   file_put_contents($dbFilePath, json_encode(['user' => []]));
}
$db = json_decode(file_get_contents($dbFilePath), true);

$bodyMsg = file_get_contents('php://input');

file_put_contents('log.txt', date('Y-m-d H:i:s') . 'Recive: ' . $bodyMsg);

$obj = json_decode($bodyMsg, true);

file_put_contents('log.txt', print_r($db, true));

foreach ($obj['events'] as &$event) {

   $userId = $event['source']['userId'];

   // bot dirty logic
   if (!isset($db['user'][$userId])) {
       if ($event['message']['text'] === $password) {
           $db['user'][$userId] = [
               'userId' => $userId,
               'timestamp' => $event['timestamp']
           ];
           file_put_contents($dbFilePath, json_encode($db));
           $message = 'Login Success! Wellcome!';
       } else {
           $message = 'Input password please.';
       }
   } else {
       if (strtolower($event['message']['text']) === 'bye') {
           unset($db['user'][$userId]);
           file_put_contents($dbFilePath, json_encode($db));
           $message = 'bye';
       } else {
           $message = 'Already logged in. You can send \'bye\' to logout.';
       }
   }

   // Make payload
   $payload = [
       'replyToken' => $event['replyToken'],
       'messages' => [
           [
               'type' => 'text',
               'text' => $message
           ]
       ]
   ];

   // Send reply API
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, '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_SSL_VERIFYHOST, false);
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
   curl_setopt($ch, CURLOPT_HTTPHEADER, [
       'Content-Type: application/json',
       'Authorization: Bearer ' . $channelAccessToken
   ]);
   $result = curl_exec($ch);
   curl_close($ch);
   
}

當有使用者說出「密碼」登入時,UserID 會在儲存於 line-db.json 這個檔案中,接下來就可以透過 push.php 發送訊息給使用者了。

透過 Line Push API 發送訊息

剛剛示範 Reply API 可以接收使用者個訊息進行回覆,當我們有了 User ID 以後,就可以透過 Push API 推送訊息,推送的 PHP 程式碼如下 (程式碼可以從 GitHub 取得 push.php):

 

<?php

$channelAccessToken = '{Your_Access_Token}';
$userIds = [];
$message = isset($argv[1]) ? $argv[1] : 'Hello!';
$dbFilePath = __DIR__ . '/line-db.json';  // user info database file path

// open json database
if (!file_exists($dbFilePath)) {
   file_put_contents($dbFilePath, json_encode(['user' => []]));
}
$db = json_decode(file_get_contents($dbFilePath), true);

if (count($db['user']) === 0) {
   echo 'No user login.';
   exit(1);
} else {
   foreach ($db['user'] as &$userInfo) {
       $userIds[] = $userInfo['userId'];
   }
}

// make payload
$payload = [
   'to' => $userIds,
   'messages' => [
       [
           'type' => 'text',
           'text' => $message
       ]
   ]
];

// Send Request by CURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.line.me/v2/bot/message/multicast');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
   'Content-Type: application/json',
   'Authorization: Bearer ' . $channelAccessToken
]);
$result = curl_exec($ch);
curl_close($ch);

發送訊息的方法超簡單,像這樣執行即可發送訊息:

php push.php 'Hello World!'

測試 Line Bot 與訊息發送

有圖有真相,首先我們先掃描 QRCode 加入好友:

這裡的密碼設定為「opendoor」,輸入密碼後可以登入:

然後我們在 Server 端可以執行 push.php 發送訊息,如下:

輸入 bye 可以刪除儲存於 Server 的 UserID,以後就收不到訊息囉。想測試的人可以掃描以下 QRCode 玩看看:

下次見... 啊掰~

Exit mobile version