Telegram Bots - Example bot for Telegram built using PHP

Example implementation of Telegram Bot in PHP - easy and simple to follow along

I will demonstrate a simple Telegram bot that will allow the users to monitor web URLs for changes and will notify users when any changes are found.

It will have few commands: /seturl to set URL for monitoring, /setinterval to change interval to wait before checking again.

I'll first show you the code first:

define('BOT_TOKEN', '12345678:replace-me-with-real-token');
define('API_URL', 'https://api.telegram.org/bot'.BOT_TOKEN.'/');

function apiRequestWebhook($method, $parameters) {
  //same as in previous article
}

function exec_curl_request($handle) {
  //same as in previous article
}

function apiRequest($method, $parameters) {
  //same as in previous article
}

function apiRequestJson($method, $parameters) {
  //same as in previous article
}

function apiSend($method, $parameters, $file, $param, $thumb="") {
  //same as in previous article
}

//function to fetch a URL using a User Agent and SSL verification disabled
function fetchURL($url) {
    $options = array(
        'http'=>array(
            'method'=>"GET",
            'header'=>"Accept-language: en\r\n" .
            "User-Agent: Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.102011-10-16 20:23:10\r\n" // i.e. An iPad 
        ),
        "ssl"=>array(
            "verify_peer"=>false,
            "verify_peer_name"=>false,
        ),
    );
    ini_set('default_socket_timeout', 10);
    $context = stream_context_create($options);
    return file_get_contents($url, false, $context);
}

/*Custom functions for database: Just structure is shown, implement them on your own please*/
function getChatPreference($chat_id, $pref) {
    return null;
}
function setChatPreference($chat_id, $pref, $value) {
    return null;
}
function addUser($chat_id) {
    return null;
}
function getData($chat_id) {
    return null;
}
function putData($chat_id, $data = '') {
    return null;
}
/*End of custom functions*/

//actual function
function processMessage($message) {
    // process incoming message
    $message_id = $message['message_id'];
    $chat_id = $message['chat']['id'];
    if (isset($message['text'])) {
        // incoming text message
        $text = $message['text'];
        $message = 'I can help you monitor web pages for changes. You can control me by sending these commands:'.PHP_EOL.'/refresh - Refresh the URL for changes manually'.PHP_EOL.'/settings - Change preferences for bot'.PHP_EOL.'/seturl - Set URL to watch'.PHP_EOL.'/setinterval - Adjust time between checks'.PHP_EOL.'/cancel - Remove URL from watch list or cancel current operation'.PHP_EOL.'/help - Show this message';
        if (substr($text, 0, 6) == '/start') {
            //add this user to database
            addUser($chat_id);
            apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Welcome!'.PHP_EOL.$message));
        } else if (substr($text, 0, 5) == '/help') {
            apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>$message));
        } else if (substr($text, 0, 9) == '/settings') {
            $info = 'Change preferences for bot'.PHP_EOL.'/seturl - Set URL to watch'.PHP_EOL;
            $data = getChatPreference($chat_id, 'url');
            if ($data) $info .= 'Currently checking: '.$data.PHP_EOL;
            $info .= '/setinterval - Adjust time between checks'.PHP_EOL;
            $data = getChatPreference($chat_id, 'interval');
            if ($data) $info .= 'Current interval: '.$data.' hour'.($hour>1?'s':'').PHP_EOL;
            $info .= '/help - Show help';
            apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>$info));
        } else if (substr($text, 0, 7) == '/seturl') {
            setChatPreference($chat_id, 'status', 'seturl');
            apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Okay, send me the URL you want to monitor for changes'.PHP_EOL.'See /help if you want to clear the current URL'.PHP_EOL.'Send /cancel if you want to cancel current operation'));
        } else if (substr($text, 0, 12) == '/setinterval') {
            setChatPreference($chat_id, 'status', 'setinterval');
            apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Okay, send me the duration in hours you want me to wait between subsequent checks'.PHP_EOL.'Send /cancel if you want to cancel current operation', 'reply_markup'=>array('keyboard'=>array(array('1', '2'), array('4', '8'), array('12', '24')), 'one_time_keyboard'=>true, 'resize_keyboard'=>true)));
        } else if (substr($text, 0, 7) == '/cancel') {
            $status = getChatPreference($chat_id, 'status');
            switch ($status) {
                case 'seturl':
                    apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Setting URL cancelled!'));
                    setChatPreference($chat_id, 'status', '');
                    break;
                case 'setinterval':
                    apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Setting update interval cancelled!'));
                    setChatPreference($chat_id, 'status', '');
                    break;
                case 'cancel':
                    apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'URL has been cleared!'));
                    setChatPreference($chat_id, 'url', '');
                    setChatPreference($chat_id, 'status', '');
                    putData($chat_id); //clear the data as well
                    break;
                default:
                    apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Send /cancel again to unset the URL for monitoring'));
                    setChatPreference($chat_id, 'status', 'cancel');
                    break;
            }
        } else if (substr($text, 0, 8) == '/refresh') {
            //force refresh the feed and also check last refresh to disallow frequent refresh
            $url = getChatPreference($chat_id, 'url');
            if (!$url) apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'No URL set for monitoring.'.PHP_EOL.'Set a url using /seturl command now to monitor!'));
            else {
                $fetched = getChatPreference($chat_id, 'last_refresh');
                if (time() - $fetched < 5 * 60) apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Sorry! You need to wait for a while before you refresh again!'));
                else {
                    $data = fetchURL($url);
                    if ($data == getData($chat_id)) apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'No changes were found!'));
                    else {
                        putData($chat_id, $data);
                        apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'URL updated! Check the latest version now:'.PHP_EOL.$url));
                    }
                }
            }
        } else {
            $status = getChatPreference($chat_id, 'status');
            switch ($status) {
                case 'seturl':
                    if (substr($text, 0, 7) != 'http://' && substr($text, 0, 8) != 'https://') { apiRequestWebhook('sendMessage', 'You need to provide a valid HTTP URL for monitoring'); die(); }
                    $data = fetchURL($text);
                    if (!$data) apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Sorry! It does not appear to be a valid URL (or the response received was empty).'.PHP_EOL.'Please try again'.PHP_EOL.'Send /cancel if you want to cancel current operation'));
                    else {
                        setChatPreference($chat_id, 'url', $text);
                        setChatPreference($chat_id, 'status', '');
                        putData($chat_id, $data);
                        apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'URL set successfully!'));
                    }
                    break;
                case 'setinterval':
                    if (!is_numeric($text)) apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'You need to provide a valid numeric value between 1 to 24 (including) to set the update interval'.PHP_EOL.'Please try again'.PHP_EOL.'Send /cancel if you want to cancel current operation', 'reply_markup'=>array('keyboard'=>array(array('1', '2'), array('4', '8'), array('12', '24')), 'one_time_keyboard'=>true, 'resize_keyboard'=>true)));
                    else {
                        setChatPreference($chat_id, 'interval', $text);
                        setChatPreference($chat_id, 'status', '');
                        apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Interval set successfully!'));
                    }
                    break;
                default:
                    apiRequestJson('sendMessage', array('chat_id'=>$chat_id, 'text'=>'Sorry! I cannot understand that.'.PHP_EOL.'Try /help for help regarding this bot'));
            }
        }
    }
    else {
        apiRequest("sendMessage", array('chat_id' => $chat_id, "text" => 'Sorry, but I understand only text messages!'));
    }
}

$content = file_get_contents("php://input");
$update = json_decode($content, true);

if (!$update) {
    // receive wrong update, must not happen
    exit;
}

if (isset($update["message"])) {
    processMessage($update["message"]);
}

Now, that the code is in front of you, you should try to figure it out first how it works.

The whole code for demo is available here. But, I must warn you this is not production-ready code. This is just an example for you to test.

So, let's understand what this code does.

The functions apiRequestWebhook, exec_curl_request, apiRequest, apiRequestJson and apiSend are same as they were in previous articles.

The other functions are given as:

  • The function fetchURL fetches a given URL and returns the content.
  • The function getChatPreference returns value of preference saved for given user (chat).
  • The function setChatPreference updates the value of preference saved for given user (chat).
  • The function addUser adds a new user to database with some default values.
  • The function getData returns the data saved for given URL.
  • The function putData saves the data fetched from given user URL.

Function processMessage

This is the main function that checks for messages received.

It will check the message and act based on what the message is.

If the message is /start, the user will be added to saved to database. And the message is /help, default help message will be shown to the user. If the message is /settings command, then the user will be shown available settings and option to update them.

If the message is /seturl, the user will be prompted to send the URL and if it is /setinterval, the user will be prompted to update the interval to wait for.

When the above messages are sent by the user, the status of bot will be set to url and interval respectively. This status variable will later tell what the bot is performing.

If the message is /cancel, it will be checked if any status is set i.e. if the bot is performing a task then it will be cancelled otherwise another message will be sent to user to send /cancel again to clear the URL.

If the message is /refresh, the URL will be checked for updates. This check will be performed only if the last check was more than five minutes ago, other wise the user will be displayed a message to wait for some time.

If the message does not match any of the above cases, it will be checked if status is set to either url or interval.

If the status is url, then it will be checked if given text is a URL or not, and then it will be set.

Similarly, if status is interval, it will be checked if the given text is numeric and within range, and then it will be set.

Otherwise a message will be given that the bot did not understand the message.

Here, you can create a new CRON job to check the URL for changes in another script. And on changes you can notify the user by sending her a message using the same functions, that you used in above script.

This article concludes the Telegram series. I hope that you learned something and will be able to implement a Telegram bot on you own now.

You can also refer to the Telegram Bot API for further reference.