【PHP Telegram Bot】Day10 - Long Polling、持续接收与发送讯息

昨天有讲到一个叫做 getUpdates 的方法,但我们没有填任何参数,今天要利用 offset 与 timeout 达成 Long Polling

Long Polling

先再执行一次昨天最後的程序,你会看到有个叫做 update_id 东西
https://ithelp.ithome.com.tw/upload/images/20210919/20132916U0Kmy0N4SV.png
把它填到 offset 的值,然後 timeout 先填 60,表示 60 秒以内 TG 服务器要回应你
https://ithelp.ithome.com.tw/upload/images/20210919/20132916c5Wb4vDInx.png
填好之後按下执行,你会发现和刚刚拿到的东西一模一样,这是因为它会从你设定的 update_id 开始取讯息

我们把刚刚填的值加一,再执行看看
https://ithelp.ithome.com.tw/upload/images/20210919/20132916XgIVr5NVMn.png
你会发现程序跑了整整一分钟才跑完,而且啥都没有,只有印出一个空阵列 Array()
https://ithelp.ithome.com.tw/upload/images/20210919/201329164fnHwmHwae.png
这是因为 540834396 就是最後一则讯息了,并没有 540834397 这则讯息

再执行一次程序,这次执行之後私讯机器人一则讯息
https://ithelp.ithome.com.tw/upload/images/20210919/201329169o05isQCyE.png
你会发现发送讯息後,TG 服务器立刻就回应了,而且程序也马上跑完了
https://ithelp.ithome.com.tw/upload/images/20210919/20132916Yl6vSBHKjZ.png
这个就是 Long Polling

发出请求时,服务器会一直到有新讯息时才会回应,或是到达时间限制(timeout)时回应空讯息

这样不仅不用一直发送请求,而且有新讯息时也能立刻收到


我们再来试个东西,如果把 540834397 改回 540834396 看看会发生什麽事
https://ithelp.ithome.com.tw/upload/images/20210919/20132916c5Wb4vDInx.png
按下执行後,你会发现 540834396 不见了,只剩 540834397

这是因为 TG 服务器会把小於 offset 的 update_id 都当作是你已经处理过的了,并且将这些讯息舍弃,所以你就没办法再次读取了
https://ithelp.ithome.com.tw/upload/images/20210919/20132916zyRUCNSfG6.png


处理收到的讯息

我们要用到 processMessage 这个官方范例里的一个函式,这个函式里要填的是 message,但是要怎麽把它取出来呢?

首先第一步,把 print_r() 删除,改成 $response =,记得後面的括号要删掉一个
https://ithelp.ithome.com.tw/upload/images/20210919/20132916MnZfAX6LFT.png
把它照着层数接在 $response 的後面,message 是字串,所以要用引号 ' 包起来
https://ithelp.ithome.com.tw/upload/images/20210919/20132916kXornvR58N.png
接好之後会像这样
https://ithelp.ithome.com.tw/upload/images/20210919/20132916ZnMr7dHDbv.png
最後把 processMessage() 加上去,别忘了後面的小括号 ) 和分号 ;
https://ithelp.ithome.com.tw/upload/images/20210919/20132916yMuNFDcuA6.png
按下执行後你会发现它印出了一坨东西

{"chat_id":127355800,"reply_to_message_id":24,"text":"Cool","method":"sendMessage"}

这是因为它用了第三种发送讯息的方式,但现在程序并不是在 Webhook 模式下运作,所以就直接 echo 到终端机上了

我们只需要将第 139 行的 apiRequestWebhook 改成 apiRequest 就行了
https://ithelp.ithome.com.tw/upload/images/20210919/20132916mnLnurAr7U.png
改完再次执行程序,此时 TG 「叮咚」了一声
https://ithelp.ithome.com.tw/upload/images/20210919/201329165u4UDHJ1QX.png
成功用官方的函式处理了讯息


处理每则讯息

其实不只是 $response[0] 里面有 message$response[1], $response[2]... 也会有 message,至於会到数字多少,这取决於一次取到了多少则讯息

如果你发送了两则讯息才执行一次程序,此时就会出现两个 message,那要如何每个 message 都处理到呢,这时候就要用到 foreach 这个函式,它会一个个的把里面的东西交给你,直到全部完成为止

来稍微修改一下刚刚的程序,把 $response 交给 foreach,中间的 $update 就是 $response[0], $response[1]...(你可以用 print_r($update); 印出来看看),然後把 $update['message'] 填进 processMessage() 函式中,记得加分号~
https://ithelp.ithome.com.tw/upload/images/20210919/20132916JBm4TrZEP0.png
这样每则讯息就都会处理到了


让程序持续运作

聪明的你应该已经发现了,不管执行几次它都会重复处理讯息,因为它总是从 offset 开始处理

每次执行一次程序就要改一次 offset,这样多麻烦,当然是要让程序自己设定

首先要找出这很多则讯息的最後一则讯息,我们可以用 count($response) 知道总共有几则讯息,count($response) - 1 表示最後一则(因为是从 0 开始数),我们先将这个值存进一个叫做 $latest 的变数里
https://ithelp.ithome.com.tw/upload/images/20210919/20132916mT0RnqbF9E.png
然後把 $latest 填进 $response 的第一个框框里,第二个框框填上 'update_id',update_id 是字串,所以要用引号 ' 包起来
https://ithelp.ithome.com.tw/upload/images/20210919/20132916ynGSBDJqaJ.png
这样就取得了最後一则讯息的 update_id

我们是要把 offset 的值填下一则讯息的 update_id,这样才不会一直重复读取同一则讯息,这边只要在後方多打个 + 1 就行了,之後把计算的结果存进 $update_id 变数里
https://ithelp.ithome.com.tw/upload/images/20210919/20132916LQlG3hEXfI.png
还记得会有没取到讯息的时候对吧,没取到讯息时 $latest 的值会变成 -1,但是框框里不能出现负数,这时就要加个 if 条件 $latest !== -1,有读取到讯息时才把 update_id 取出来
https://ithelp.ithome.com.tw/upload/images/20210919/20132916HXA3FPbL1d.png
再来就是把 $update_id 填到 offset 的值里,还有加上 while (true) {},让程序不断重复执行
https://ithelp.ithome.com.tw/upload/images/20210919/20132916C84LxYMmOh.png
最後的最後,在最前面加上一行 $update_id = 0;
https://ithelp.ithome.com.tw/upload/images/20210919/20132916kZv3I27CQS.png
这样就大功告成啦

执行程序後,试着跟机器人说 Hi、Hello 吧

对了,如果想要停止程序的话,就对着终端机按下 Ctrl + C,程序就会停止了


结尾

今天的内容可能有点困难,看不太懂没关系

如果没办法照着做出来的话,欢迎直接复制下方程序码来玩玩:

$update_id = 0;
while (true) {
    $response = apiRequest("getUpdates", array('offset' => $update_id, 'timeout' => 60));
    foreach ($response as $update) {
        processMessage($update['message']);
    }
    $latest = count($response) - 1;
    if ($latest !== -1) {
        $update_id = $response[$latest]['update_id'] + 1;
    }
}

最後,再来考考你

如果少加了 $update_id = 0; 会发生什麽事?

在底下留言你的答案吧!


<<:  认识HTML(二)

>>:  IIFEs 立即函式:不需呼叫即可执行

Day13 参加职训(机器学习与资料分析工程师培训班),人工智慧与机器学习概论

今天老师讲了一些数学的东西,传统演算法与机器学习的演算法差异,机器学习演算法有哪些方式去回测参数,但...

判断选取哪个radio button

var item = $('input:radio[name="radio_name&qu...

Day 17: AWS Config、Config rules、Dashboard建立

如何布建AWS Config? 1.找到Config 2.侧边选单选择Settings 3.还没有任...

水深火热CSS Day 1

不难发现,问题在於该用什麽标准来做决定呢?梁晓声曾讲过,友谊,好比一瓶酒,封存的时间越长,价值则越高...

第17天~ListView再练一个

ListView再练一个 先新增模组: 要V generate...... activity_mai...