MQH Blog

Writing Telegram Bot with PHP using Guzzle

Introduction

Featured

PHP Telegram Bot

Writing Telegram Bot with PHP using Guzzle

Posted by Mohammed Q. Hussain on .

Several months ago Telegram started to support bots which is, in my opinion, really an interesting feature for a chat application to come with. Anyone could create his/her own bot and of course to make the bot functional a code should be written for it :-). In this post I’m going to explain how to write a simple Telegram bot with PHP using Guzzle HTTP Client. Your bot’s code must reside on your own server which must support HTTP connections and obviously PHP scripts; a shared host is enough but you will need a SSL/TLS if you’re planning to use web hook for you bot, more details about web hook will be presented in this post. You can read the official guide if you don’t know what exactly bots are.

Creating a new Bot

As a first step you’ll need to create a new bot which is a really easy step. There is an official bot called BotFather; by using it you could create you own bot. Just add BotFather to your Telegram contact list by clicking here then follow the instructions. It’s probably easier to use Telegram Desktop Client while you’re developing your bot.

After adding BotFather to your contact list use the command “/newbot” to create your new bot. BotFather will ask you few questions about the name of your new bot and after answering the questions the new bot will be created and a token for Web API of your bot will be provided to you. Keep the token in a secure place we will need it later when we start to write bot’s code.

Start Coding

Telegram provides us a HTTP API to program our bots and instead of using curl to consume those APIs we’re going to use Guzzle here. The installation guide of Guzzle can be found here. I assume that you will use Composer to install Guzzle so the path of Guzzle’s files in our examples will start with the directory “vendor”.

Initializing the HTTP Client

I assume that you installed Guzzle successfully in a directory which is dedicated to our bot’s code; Let’s create a new php file in this directory and call it “bot.php”. The first thing that we need to do is including the file autoload.php from Guzzle package; after that we’re going to use the keyword “use” to get rid of Guzzle’s namespace as the following:

require_once( 'vendor/autoload.php' );
use GuzzleHttp\Client;

Guzzle has a class called Client which helps us to open a connection with HTTP API’s URL and send requests to the server and receive the responses. Our bot URL has the following form: https://api.telegram.org/bot[Bot’s Token]/[To be called Method]. For the start we don’t care about the method’s part of the URL; we only need the first part which involves the bot’s token; by using it we could initialize the HTTP Client’s object.

$apiKey = ''; // Put your bot's API key here
$apiURL = 'https://api.telegram.org/bot' . $apiKey . '/';

$client = new Client( array( 'base_uri' => $apiURL ) );

In the first two lines we construct the API’s URL for our newly-created bot; then we create a new object of the class Client which is provided to use by Guzzle; in this object there are all needed methods to communicate with Telegram’s servers and consume the APIs. You can see that the constructor of class Client requires one parameter which is an array; this array has an element with the key “base_uri” which is the URL of the HTTP APIs. Well, we now initialized the HTTP client which resides in the object $client. Let’s start with the real work :-).

Getting Updates

(AKA: Is there anything new?)

Well, what we want to do now is getting the updates. When anybody sends a new message to our bot we call this message an “update”. There are two ways to get updates, the first one by using Telegram’s API method getUpdates. By using this way we need to manually refresh the page - which has the php code that handles the updates - which is of course not suitable way for production but it is a good way to be used in the development phase.

The other way is using the WebHook, in this way we write our code which handles the updates and set the page which has this code as a WebHook for our bot - by using the Telegram’s method setWebHook -, When our bot receives any new update, Telegram’s server is going to call the page which has been set as a WebHook instantly so the bot will response automatically to the updates.

For now we are going to talk about the first way - getUpdates - and later we are going to modify our code to be suitable to be used as WebHook.

getUpdates() method

Client class of Guzzle provides us the method “get” which sends a GET request to the URL which already initialized and because the Telegram’s method “getUpdates” is a GET method so we are going to use Guzzle’s “get”. We already initialized the client’s object and we stored this object in a variable called $client.

$response = $client->get( 'getUpdates' );
$updates = json_decode( $response->getBody() );

In the first line we call the method getUpdates which provides us the list of new messages. The method “get” returns an object which represents server’s response and if everything goes smoothly in the second line we’re going to get the body of the response which is a JSON that contains the list of all new messages, and by using PHP’s function json_decode we convert JSON to a PHP object which will be stored in “$updates”.

If you try to send a text message to your bot using Telegram then try to print the object $updates using var_dump( $updates ) you will get something like that:

object(stdClass)[32]
  public 'ok' => boolean true
  public 'result' =>
    array (size=1)
      0 =>
        object(stdClass)[30]
          public 'update_id' => int 475557067
          public 'message' =>
            object(stdClass)[27]
              ...

The format of var_dump may be shown differently with you and that’s because I use Xdebug in my development environment but anyway we can see from var_dump’s result that $updates object has two fields; first one has the name “ok” which is a boolean that shows if everything is fine or not, the second one which is more important has the name “result” which is an array of the new messages which have been sent to our bot. Each entry in this array represents an Update. We want to traverse through the list of results:

foreach ( $updates->result as $update )
{
	// Our next code will be here
}

At each iteration of foreach we will have an object “$update” which represents one update, and there are two fields in this object, the first one is “$update->update_id” which contains the identifier number of the current update, the second one which is more interesting is “$update->message” which is an object of Message and obviously this object represents the message which has been sent to our bot. It has many interesting fields which are all decribed on the official guide. Take a look here.

Sending Messages

(AKA: Responding to Updates)

Now let’s see how to let our bot to send messages to the users who contacted it. As an example we want our bot to send the message “Welcome to MQH Blog’s Bot” when the user sends “Hello” to it. In the previous code the object $update has the field “message” which, as we said previously, represents the message which has been sent by the user; the message’s object itself has many useful fields, but in our situation we’re interested in two of them. The first one is “text” and the second one is “chat”.

Obviously the field “text” contains the text of the message which has been sent by the user. The first step in our example is checking whether the user sent the message “Hello” to our bot and we can do that simply as the following (Note that the following code must be inside foreach’s block of the previous code which we already wrote in this post):

if ( $update->message->text == 'Hello' )
{
	echo 'Hello has been received';

	// Response's code will be here
}

Well, the second step is sending a response to the user and to do that we must use Telegram’s API method sendMessage which requires two parameters; the first one is “chat_id” which is a unique key that represents the user who we would like to send the message to. In our case the value of “chat_id” must be the id of the user who sent the message “Hello” to our bot and we could grab his/her id by using the field “chat” of the object “message”, “chat” itself is an object which has a field called “id” and that’s exactly the id which we need. The second parameter which is required by the method “sendMessage” is “text” which is the message we would like to send to the user who has been specified in the first parameter:

$client->post( 'sendMessage', array( 'query' => array( 'chat_id' => $update->message->chat->id, 'text' => "Welcome to MQH Blog's Bot" ) ) );

First of all, “sendMessage” is a POST method and because of that we used Guzzle’s method “post”. The first parameter is the name of the Web API method which we want to call. The second parameter is an array of one element that has the key “query” which is an array that contains the parameters that is required by the method “sendMessage”. You can see that we sent the two parameters “chat_id” and “text” to the method “sendMessage”.

The complete code until now:

<?php

require_once( 'vendor/autoload.php' );
use GuzzleHttp\Client;

$apiKey = ''; // Put your bot's API key here
$apiURL = 'https://api.telegram.org/bot' . $apiKey . '/';

$client = new Client( array( 'base_uri' => $apiURL ) );

$response = $client->get( 'getUpdates' );
$updates = json_decode( $response->getBody() );

foreach ( $updates->result as $update )
{
	if ( $update->message->text == 'Hello' )
	{
		echo 'Hello has been recieved';

		$client->post( 'sendMessage', array( 'query' => array( 'chat_id' => $update->message->chat->id, 'text' => "Welcome to MQH Blog's Bot" ) ) );
	}
}

?>

Responding Automatically with WebHook

Using WebHook we could set the page - which handles the new updates - to our bot and Telegram’s servers are going to call this page whenever a user sends a message to our bot. You can observe that the previous code need to be executed manually each time to let our bot to response to new “Hello” messages. With WebHook there is no need to execute the code manually; Telegram’s servers is going to call the code with every new message. The code will be the same with slight changes.

The first step is to use setWebHook to set the URL of the PHP page as a web hook for our bot. Note that the URL must starts with HTTPS which means TLS/SSL must be enabled in your server.

Let’s create a new PHP file and call it “SetWebHook.php”. In this file we’re going to call setWebHook which is a simple method that takes the URL of update’s handler page - the web hook - as a parameter.

<?php

require_once( 'vendor/autoload.php' );
use GuzzleHttp\Client;

$apiKey = ''; // Put your bot's API key here
$apiURL = 'https://api.telegram.org/bot' . $apiKey . '/';

$client = new Client( array( 'base_uri' => $apiURL ) );

$webHookURL = ''; // Your Web Hook's URL
$response = $client->post( 'setWebhook', array( 'query' => array( 'url' => $webHookURL ) ) );

?>

There is nothing new here. We created our HTTP Client object “$client” then we used it to call the POST method “setWebHook”. The variable “$webHookURL” must be filled with the URL of our bot’s web hook. Now let’s create a new PHP file and call it “WebHook.php” which will be the web hook of our example bot. The coming code will be same as the code from previous part with some modifications. First we include Guzzle and create the HTTP Client object as we did previously:

<?php

require_once( 'vendor/autoload.php' );
use GuzzleHttp\Client;

$apiKey = ''; // Put your bot's API key here
$apiURL = 'https://api.telegram.org/bot' . $apiKey . '/';

$client = new Client( array( 'base_uri' => $apiURL ) );

We mentioned many times earlier that Telegram’s servers are going to call our bot’s web hook when a new message recieved. And that will be done of course be sending a HTTP request (POST) to your server. The body of the request contains a Update object of the new message.

$update = json_decode( file_get_contents( 'php://input' ) );

Now we have Update object in the variable “$update” and we already dealt with this object in the previous part. No we can examine the content of the recieved message using “$update” as we did previously.

if ( $update->message->text == 'Hello' )
		$client->post( 'sendMessage', array( 'query' => array( 'chat_id' => $update->message->chat->id, 'text' => "Welcome to MQH Blog's Bot" ) ) );

The complete code of WebHook:

<?php

require_once( 'vendor/autoload.php' );
use GuzzleHttp\Client;

$apiKey = ''; // Put your bot's API key here
$apiURL = 'https://api.telegram.org/bot' . $apiKey . '/';

$client = new Client( array( 'base_uri' => $apiURL ) );

$update = json_decode( file_get_contents( 'php://input' ) );

if ( $update->message->text == 'Hello' )
		$client->post( 'sendMessage', array( 'query' => array( 'chat_id' => $update->message->chat->id, 'text' => "Welcome to MQH Blog's Bot" ) ) );

?>
user

Mohammed Q. Hussain

http://www.maastaar.net

A Programmer.