Телеграм бот на PHP

Передо мной появилась задача сделать телеграм бота на PHP. Я нашел два варианта решения этой задачи. Первый вариант, используя библиотеку telegram api, второй вариант без использования каких-либо библиотек. Сначала я будут инструкции, которые применимы к этим двум вариантам, а после рассмотрим каждый вариант более подробно

Обратите внимание, что действия указанные в этой статье, я делал на реальном сервере и домене у которого есть сертификат безопасности ssl, т.е. домен доступен по https. Телеграм требует этот сертификат.

Итак для начала нам необходимо создать нашего телеграм бота, для этого в телеграме необходимо найти телеграм бота @BotFather, в диалоге с этим ботом введите команду /newbot, после чего задайте имя и никнейм вашего бота. Вам будет предоставлен уникальный токен, сохраните его куда-нибудь, он вам еще пригодится.

Если вы хотите использовать вашего бота в чатах, то необходимо изменить его приватность. Для этого в диалоге с @BotFather введите команду /setprivacy, вам надо установить значение приватности в Disable.

Теперь перейдем к вариантам создания телеграм бота.

Первый вариант. Библиотека telegram api

Для работы с телеграм ботом, вам надо выбрать папку на вашем сервере, в которой вы будете с ним работать, у меня это будет - mysite.ru/botinfo.

Установим библиотеку telegram api, которая упростит нам взаимодействие с ботом. Откройте консоль, перейдите в папку, которую вы выбрали и выполните следующие команды:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"

Этими командами вы установите composer, при помощи которого мы и скачаем библиотеку для работы с телеграмом. Выполните команду:

php composer.phar require telegram-bot/api

Этой командой вы установили библиотеку.

Теперь в папке, в моем случае это папка botinfo, создадим файл index.php в этом файле будем писать код для работы с нашим ботом.

Пример моего php кода в файле index.php

header('Content-Type: text/html; charset=utf-8');

// подключим API
require_once("vendor/autoload.php");

$token = "token"; //Ваш токен, который вы получили при создании бота
$bot = new \TelegramBot\Api\Client($token);
if(!file_exists("registered.trigger")){ 	
	 
	// URl текущей страницы
	$page_url = "https://".$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
	
	$result = $bot->setWebhook($page_url);
	
	if($result){
		file_put_contents("registered.trigger",time()); // создаем файл дабы прекратить повторные регистрации
	}
}

$bot->command('start', function ($message) use ($bot) {
    $answer = 'Привет!';
    $bot->sendMessage($message->getChat()->getId(), $answer);
});

$bot->on(function($Update) use ($bot){
	$message = $Update->getMessage();
	$mtext = $message->getText();
	$cid = $message->getChat()->getId();
	
	if($mtext == "+"){
		$bot->sendMessage($message->getChat()->getId(), "-");
	}
	
}, function($message) use ($name){
	return true; 
});


$bot->run();

В моем примере бот, на команду /start будет отвечать "Привет!", а на сообщение +, будет отвечать "-".

Условие if(!file_exists("registered.trigger")) нужно для того, чтобы телеграм бот понимал куда ему обращаться на вашем сайте, вам надо будет запустить этот файл из браузера, один раз, чтобы появился файл registered.trigger

Вы можете полазить по папкам библиотеки, которую вы скачали и посмотреть какую информацию может получить ваш бот. Ниже я приведу пару примеров таких функций и расскажу, что ими можно делать. Все эти функции я буду использовать в блоке $bot->on

$message->getFrom()->getId() - Уникальный идентификатор пользователя;

$message->getFrom()->getFirstName() - Имя пользователя;

$message->getFrom()->getLastName() - Фамилия пользователя;

$message->getFrom()->getUsername() - Никнейм пользователя;

$message->getChat()->getTitle() - Название чата;

$message->getChat()->getId() - Уникальный идентификатор чата;

$message->getDate() - Дата сообщения, в формате unix;

Пример получения координат, которые пользователь передал, отправив геолокацию в телеграме:

if($message->getLocation()){
	$coord1 = $message->getLocation()->getLatitude();
	$coord2 = $message->getLocation()->getLongitude();
}

Пример получения фото, которое отправил в телеграм пользователь:

$photoInfo = $message->getPhoto();
if($photoInfo){
	$photoId = $photoInfo[0]->getFileId();
	$file = $bot->getFile($photoId);
	$furl = $bot->getFileUrl().'/'.$file->getFilePath();
	file_put_contents(basename($furl), file_get_contents( $furl ) );
}
file_put_contents("/",$text);

Данный код, сохранит отправленную пользователем в телеграме картинку, к вам на сервер. Если вас не устраивает размер картинки, то можете поэксперементировать и заменить $photoInfo[0] на $photoInfo[1]. Как я понял в этом массиве содержатся разные размеры изображения.

Пример кода, для отправки фото

	$pic = "https://mysite.ru/img/myphoto.jpg;
    $bot->sendPhoto($message->getChat()->getId(), $pic);

Этот код отправит фото, в тот чат, откуда был задан вопрос - $message->getChat()->getId(). В переменной $pic содержится ссылка на фото, которое вы хотите отправить.

Второй вариант. Создание телеграм бота, без библиотек.

Прежде всего рекомендую вам ознакомиться с документацией, которую дает телеграм - https://core.telegram.org/api

Для начала я приведу вам пример кода двух файлов, после чего разберу и поясню, что написано в каждом из этих файлов.

Файл telegrambot.php:

$body = file_get_contents('php://input'); 
$arr = json_decode($body, true); 
 
include_once ('telegramgclass.php');   

$tg = new tg('токен который вы получили');

$chat_id = $arr['message']['chat']['id'];
$userTgId = $arr['message']['from']['id'];
$text = $arr['message']['text'];
$coord1 = $arr['message']['location']['latitude'];
$coord2 = $arr['message']['location']['longitude'];

$tg->send($chat_id, "Нас не догонят!");

Файл telegramgclass.php:

class TG {
  
    public $token = '';
  
    public function __construct($token) {
        $this->token = $token; 
    }
      
    public function send($id, $message,$keyboard) {   
		
		//Удаление клавы
		if($keyboard == "DEL"){		
			$keyboard = array(
				'remove_keyboard' => true
			);
		}
		if($keyboard){
			//Отправка клавиатуры
			$encodedMarkup = json_encode($keyboard);
			
			$data = array(
				'chat_id'      => $id,
				'text'     => $message,
				'reply_markup' => $encodedMarkup
			);
		}else{
			//Отправка сообщения
			$data = array(
				'chat_id'      => $id,
				'text'     => $message
			);
		}
       
        $out = $this->request('sendMessage', $data);       
        return $out;
    }         
	
	public function getPhoto($data){
		$out = $this->request('getFile', $data);        
        return $out;
	}  
	
	public function savePhoto($url,$puth){
		$ch = curl_init('https://api.telegram.org/file/bot' . $this->token .  '/' . $url);
		$fp = fopen($puth, 'wb');
		curl_setopt($ch, CURLOPT_FILE, $fp);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_exec($ch);
		curl_close($ch);
		fclose($fp);
	}
	
    public  function request($method, $data = array()) {
        $curl = curl_init(); 
          
        curl_setopt($curl, CURLOPT_URL, 'https://api.telegram.org/bot' . $this->token .  '/' . $method);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 
          
        $out = json_decode(curl_exec($curl), true); 
          
        curl_close($curl); 
          
        return $out; 
    }
}

После того как создадите эти файлы, дайте знать телеграму куда ему слать информацию, это делается ссылкой: https://api.telegram.org/botВАШТОКЕН/setWebhook?url=ССЫЛКА_НА_telegrambot.php

Используя эти два файла, ваш телеграм бот на любое сообщение будет отвечать "Нас не догонят!" Разберемся, что у нас написано в файле telegrambot.php.

Переменная $body содержит информацию в json формате, которая приходит от телеграм. Как вы наверное уже догадались в переменной $chat_id у нас находится id чата, в переменной $userTgId - id пользователя, который послал сообщение, в $text - текст сообщения, которое послал пользователь, в переменных $coord1 и $coord2 будет информация о координатах, в случае если пользователь отправил геолокацию.

Если вам интересны все данные, которые приходят от телеграм, то советую эти данные записать в какой-нибудь файл, к примеру:

$fp = fopen("test.txt", "w+");

fwrite($fp, $body);

После чего можете отослать сообщение своему боту, затем открыть файл test.txt и посмотреть информацию в json формате, которая пришла когда вы отправили своему боту сообщение.

Пример такой информации:

{
	"update_id":5489999,
	"message":{
		"message_id":199,
		"from":{
			"id":246667777,
			"is_bot":false,
			"first_name":"Stanislav",
			"last_name":"Korobkin",
			"username":"Korobkin_tg",
			"language_code":"ru"
		},
		"chat":{
			"id":246667777,
			"first_name":"Stanislav",
			"last_name":"Korobkin",
			"username":"Korobkin_tg",
			"type":"private"
		},
		"date":1564644489,
		"photo":[
			{
				"file_id":"AgADAgADdawxG_xHEErcM5mS2f7jD8ABuA8ABAEAgwIlA2jAA7-_AQABFgQ",
				"file_size":13083,
				"width":320,"height":227
			},
			{
				"file_id":"AgADAgADXawxG_xHEErcM5mS2v7jD8ABuA8ABAEAAwhUT3gAA8C_AQABFgQ",
				"file_size":36568,
				"width":639,"height":453
			}
		]
	}
}

Как вы могли заметить, в этом примере, есть "photo", что говорит нам о том, что боту послали фото. Для того, чтобы сохранить фото, которое послали вашему боту, необходимо в файле telegrambot.php использовать следующий код:

$ardata = array('file_id' => $arr['message']['photo'][0]['file_id']);
$zz = $tg->getPhoto($ardata);
$filename = "/myimages/tg".strtotime(date("y-m-d H:i:s")).".jpg"; //Путь и название картинки, которую вы сохраняете
$tg->savePhoto($zz["result"]["file_path"],$filename);

Кстати, если мы говорим о фото, которые вы посылаете телеграму, то имейте ввиду, что он их сжимает. Если вам надо получить информацию о фото, например какие-нибудь exif данные, то советую отправлять фото, как файл.

У вас также есть возможность отправить клавиатуру или кнопки в чат. Пример отправки кнопок в чат:

$arInfo["inline_keyboard"][0][0]["callback_data"] = 1;
$arInfo["inline_keyboard"][0][0]["text"] = "Кнопка 1";
$arInfo["inline_keyboard"][1][0]["callback_data"] = 2;
$arInfo["inline_keyboard"][1][0]["text"] = "Кнопка 2";
$tg->send($chat_id, "Примеры кнопок",$arInfo);

Пример отправки клавиатуры в чат:

$arInfo["keyboard"][0][0]["text"] = "Кнопка";
$tg->send($chat_id, "Посмотрите у вас должна появиться клавиатура!",$arInfo);

Для удаления клавиатуры, напишите вот это:

$tg->send($chat_id, "Удалили кнопку", "DEL");

В заключение могу сказать, что мне оказался ближе второй вариант, потому что достаточно прочитать документацию https://core.telegram.org/api и при этом не надо доплонительно изучать как работает какая-то сторонняя библиотека. Если у вас есть вопросы, пишите их в комментарии, я постараюсь ответить.

Комменатрии
Дмитрий 20.11.2019 03:18:35
Бьюсь уже два дня. Не получается. Бот создал адрес и token прописал, получил ответ: {"ok":true,"result":true,"description":"Webhook was set"} Но до выполнения php как то не доходит. Если руками запускаю из браузера , ошибок не выдает. Главное не понятно где искать ошибку
Ответить
Станислав 22.11.2019 10:05:22
Дмитрий, Напиши пожалуйста, что именно у тебя не работает на php (какой кусок кода)?
Ответить
Алексей 04.06.2020 19:01:51
Я тоже создал два этих файла, положил на хостинк, Webhook телеграму передал, но если что-то пишу боту, ничего не происходит(( в чем может быть ошибка?
Ответить
Станислав 15.06.2020 12:24:07
Алексей, Для начала проверьте правильно ли вы установили Webhook
Ответить
Алексей 04.06.2020 19:02:51
То есть бот вообще никак не реагирует на мое сообщение! И еще вопрос, куда он будет выводить написанное в боте сообщение?
Ответить
Станислав 15.06.2020 12:23:24
Алексей, Смотрите то, что вы пишите в телеграм боте отправляется на тот файл, на который вы установили WebHook
Ответить
Витя 05.07.2020 20:27:20
Спасибо большое, создал бота за 5 минут по вашей инструкции, вместе с созданием бесплатного хостинга). В примере есть ошибка в строке $tg->send($chat_id, "Нас не догонят!"); там вы используете два аргумента, а пхп ругается что надо 3, для новичков будет не понятно)
Ответить
Денис 28.07.2020 14:30:34
Возможно ли изменить стиль кнопки?
Ответить
Станислав 28.07.2020 16:09:14
Денис, Там два варианта на сколько я знаю: 1. Это когда под сообщением кнопки появляются 2. Это когда клавиатура с кнопками появляется
Ответить
Денис Скрипник 10.09.2020 08:57:29
Здравствуйте. Интересует, как делать реакцию на callback кнопки? В частности, изменением сообщения и созданием нового? Благодарю.
Ответить
Станислав 14.09.2020 16:24:41
Денис Скрипник, Здравствуйте, не совсем понял ваш вопрос. Пример добавление кнопок, в статье есть. Если вы хотите сделать какое-то действие при нажатии на кнопку, то посмотрите, что у вас приходит json данные которые к вам приходят при нажатии на кнопку, выцепите какой-нибудь уникальный идентификатор, например название кнопки и делайте, что вам необходимо. Для изменения существующего сообщения есть метод editMessageText, если интересен именно этот метод, то напишите, я расскажу вам о нем подробнее.
Ответить
Денис Скрипник 14.09.2020 20:15:55
Станислав, Благодарю. Я после того, как написал комментарий, изучил JSON. Вопрос другой: Мне объяснили, что такой метод плох по сравнению с использованием очереди сообщений (или как-то так - не помню точный термин), т.к. при использовании данного метода нет гарантии, что сообщение дойдёт до получателя. Это так, и если да, как этого избежать? Сейчас пишу ботов, которые работают, как приложения (постоянно в фоновом режиме), но это неоптимально, если бот диалоговый. Но и чтоб пропускались сообщения не хочется... Благодарю.
Ответить
Станислав 28.09.2020 20:53:47
Денис, Не совсем понял про очередь сообщений. Вы по идее можете проверять отправилось ваше сообщение или нет, при отправке ботом сообщения, тоже есть результат в виде JSON который можно посмотреть. Если не сложно можете обьяснить почему нет гарантии, что сообщение не дойдет до получателя, проверка JSON при отправке о которой я написал не решит эту проблему?
Ответить
Денис Скрипник 28.09.2020 21:45:04
Станислав, Если так, хорошо. Я просто пересказывал то, что мне сказали. Благодарю за информацию.
Ответить
Behruz 28.10.2020 10:42:32
Гду указать путь (папку) сохранения фото?
Ответить
Behruz 28.10.2020 10:44:05
$filename = "/myimages/tg".strtotime(date("y-m-d H:i:s")).".jpg"; создал папку /myimages, но это не работает, фото не появляются вообще
Ответить
Петро 02.01.2021 11:40:46
Подскажите пожалуйста как делать круглое видео VideoNote без библиотеки, тоесть на сервере должны в папке быть квадратные видео а при запросе должны получаться круглы подскажите все мозги запарил
Ответить
Денис 27.04.2021 09:40:44
Здравствуйте. Добавил функцию для отправки sendPhoto. В photo передаю url на изображение. Странность заключается в том, что некоторые изображения в браузере открываются, а Telegram отвечает ошибкой... Названия полностью совпадают с тем, что в Telegram передаются... В чём может быть причина? Или я неправильно передаю? Благодарю.
Ответить
Денис скрипник 17.08.2021 13:49:12
Здравствуйте. Хочу сделать прикрепление чата к боту, но не могу понять, как это сделать... Если пересылать сообщение из чата, то отображается инфа только по тому, от кого пересылаем. Если пересылать сообщение канала, которое пересылалось пользователем чата, берутся данные канала... Суть задачи: Хочу дать возможность пользователю бота в лличке, если он админ чата или владелец, выполнять некоторые настройки. Благодарю за ответ.
Ответить
Дмитрий 23.09.2021 21:31:23
Проблема с этим $keyboard Убрал его - стало работать
Ответить
Денис 26.11.2021 08:52:07
Дмитрий, никаких проблем. Просто надо сделать чуть по другому public function send($id, $message,$keyboard=null) {
Ответить
Александр 03.03.2022 17:28:01
Спасибо, мне помогла ваша статья
Ответить
Денис Скрипник 07.05.2022 08:15:37
Здравствуйте. Можно ли при помощи второго варианта запустить веб бота? Благодарю.
Ответить
Добавить комментарий