My bot on Telegram is looping on messages

3

Hello,

I have the following code:

<?php
function readUpdate($updateId) {
    $fh = fopen(basename(__FILE__, '.php').'.txt', 'a');
    fwrite($fh, $updateId.' ');
    fclose($fh);
}
function sendMessage($chatId, $text) {
    if(!empty($chatId) && !empty($text)) {
        file_get_contents('https://api.telegram.org/botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/sendMessage?text='.$text.'&chat_id='.$chatId);
    }
}
for($i = 0; $i = 1; $i++) {
    $getUpdates = json_decode(file_get_contents('https://api.telegram.org/botXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/getUpdates'), true);
    $count = count($getUpdates['result']) - 1;
    readUpdate($getUpdates['result'][$count]['message']['message_id']);
    if(strpos(file_get_contents(basename(__FILE__, '.php').'.txt'), $getUpdates['result'][$count]['message']['message_id']) !== true) {
        foreach($getUpdates['result'] as $result) {
            $updateId = $result['update_id'];
            $messageId = $result['message']['message_id'];
            $userId = $result['message']['from']['id'];
            $firstName = $result['message']['from']['first_name'];
            $lastName = $result['message']['from']['last_name'];
            $userName = $result['message']['from']['username'];
            $chatId = $result['message']['chat']['id'];
            $type = $result['message']['chat']['type'];
            $text = $result['message']['text'];
            if($text == '/start') {
                sendMessage($chatId, 'Olá '.$firstName);
                echo '[START] Mensagem de boas vindas enviada.<br>';
                continue;
            }
        }
    } else {

    }
    $i--;
}
?>

The return of /getUpdates is:

{"ok":true,"result":[{"update_id":444612040,
"message":{"message_id":1,"from":{"id":330782177,"first_name":"Brayan","last_name":"Noxious","username":"STRILEXLIVE"},"chat":{"id":330782177,"first_name":"Brayan","last_name":"Noxious","username":"STRILEXLIVE","type":"private"},"date":1492270909,"text":"/start","entities":[{"type":"bot_command","offset":0,"length":6}]}},{"update_id":444612041,
"message":{"message_id":2,"from":{"id":330782177,"first_name":"Brayan","last_name":"Noxious","username":"STRILEXLIVE"},"chat":{"id":330782177,"first_name":"Brayan","last_name":"Noxious","username":"STRILEXLIVE","type":"private"},"date":1492270972,"text":"Ol\u00e1"}}]}

The functions are working perfectly, everything is okay, however, when I access the script URL, the script starts sending the messages to the people who sent messages to the bot, and after it sends the messages to the people who sent the messages to him, he starts to send another message, and so it goes, then goes spamming the chat.

The function readUpdate is for the script to get a unique ID of the message and save it in a .txt file for the bot to mark it as a "read message", so as not to spell it, but it still spams the chat. >

I looked for everything on the internet, how to read line by line from the .txt file and see if that string is on the line, etc., to try to solve this error, but I did not succeed.

Thank you in advance.

    
asked by anonymous 15.04.2017 / 23:49

1 answer

0

Use offset of Telegram to just get new messages, bypassing previously read messages, see link . .

  

Identifier of the first update to be returned. Must be greater by one of the highest among the identifiers of previously received updates. By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id. The negative offset can be specified to retrieve updates starting from -offset update from the end of the updates queue. All previous updates will be forgotten.

That way you get:

{  
   "ok":true,
   "result":[  
      {  
         "update_id":444612040,
         "message":"..."
      },
      {  
         "update_id":444612041,
         "message":"..."
      }
   ]
}

At the next request for /getUpdates you must enter offset=444612042 .

You can use multiple ways to get the highest update_id and add one, for example:

  • max(array_column($result, 'update_id')) + 1
  • $result[count($result) - 1]['update_id'] + 1

For this I used this:

function saveUpdateOffset(array $result){

   file_put_contents(LOCAL_HISTORY, (max(array_column($result, 'update_id')) + 1));

}

function getUpdateOffset(){

    if(file_exists(LOCAL_HISTORY) && is_readable(LOCAL_HISTORY)) {
        return (int)file_get_contents(LOCAL_HISTORY);
    }

    return 0;

}

So calling by getUpdateOffset will get the last id , if it exists. And when you call by saveUpdateOffset , informing the data of the current request, it will update the file to the most recent id , which will be obtained on the next call.

Example:

You can either store offset and use it on the next call or another option is simply make a new request for /getUpdates to ignore what has already been read (and therefore processed and sent a response) .

Anyway, you can use this:

const TELEGRAM_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxx';
const TELEGRAM_URL = 'https://api.telegram.org/bot'.TELEGRAM_TOKEN;
const LOCAL_HISTORY = 'historico.txt';

function getUpdates($offset = 0){

   $jsonNotificacoes = sendRequest(TELEGRAM_URL.'/getUpdates?offset='.$offset);

    if($jsonNotificacoes == false){
        return false;
    }

    return json_decode($jsonNotificacoes, true)['result'];

}

function getMessages($getUpdates_result){

    return array_column($getUpdates_result, 'message');

}

function saveUpdateOffset($getUpdates_result){

   file_put_contents(LOCAL_HISTORY, (max(array_column($getUpdates_result, 'update_id')) + 1));

}

function getUpdateOffset(){

    if(file_exists(LOCAL_HISTORY) && is_readable(LOCAL_HISTORY)) {
        return (int)file_get_contents(LOCAL_HISTORY);
    }

    return 0;

}

function sendMessage($chatId, $text){

    if(empty($chatId) && empty($text)) {
       return false;
    }

    return sendRequest(TELEGRAM_URL.'/sendMessage?text='.$text.'&chat_id='.$chatId);

}

function sendRequest($url){

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_SSL_VERIFYPEER => 1,
        CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
        CURLOPT_FOLLOWLOCATION => 0,
        CURLOPT_MAXREDIRS => 0,
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_CONNECTTIMEOUT => 2,
        CURLOPT_TIMEOUT => 5,
        CURLOPT_LOW_SPEED_LIMIT => 500,
        CURLOPT_LOW_SPEED_TIME => 1,
        CURLOPT_FAILONERROR => 1
    ]);

    return curl_exec($ch);

}

$updates = getUpdates( getUpdateOffset() );

if($updates) {

    saveUpdateOffset($updates);

    $mensagens = getMessages($updates);

    foreach ($mensagens as $mensagem) {

        $id     = $mensagem['chat']['id'];
        $nome   = $mensagem['from']['first_name'];
        $texto  = $mensagem['text'];

        if($texto === '/start'){

            if(sendMessage($id, 'Olá, ' . $nome)) {
                echo 'Mensagem enviada';
            }
        }

    }

}

Changes:

Using cURL, restricted to HTTPS ( CURLOPT_PROTOCOLS ), without following redirect ( CURLOPT_FOLLOWLOCATION ) and checking authenticity of SSL ( CURLOPT_SSL_VERIFYPEER ), with connection timeout of 2 seconds ( CURLOPT_CONNECTTIMEOUT ) and one timeout of 5 seconds to get the full result ( CURLOPT_TIMEOUT ) and in case of slow connections the timeout is 1 second ( CURLOPT_LOW_SPEED_TIME ) and in case of an HTTPCode other than 200 ~ 300 it will return false ( CURLOPT_FAILONERROR ).

getUpdates(int $offset) makes the request to get all information of TELEGRAM_URL/getUpdates .

The getMessages(array $getUpdates_result) expects the result of getUpdates , where it will return only the data of the messages.

The saveUpdateOffset and getUpdateOffset was described above, where only save and get the offset of a historico.txt file, the first function expects the result getUpdates as the first parameter.

The% of% was basically unchanged.

    
17.04.2017 / 19:33