четверг, 20 февраля 2020 г.

Как создать telegram бота используя PHP без использования библиотек

В интернете есть множество статей про создание телеграм ботов. Часть из этих статей написана про ботов на PHP и почти все они являются инструкциями по созданию ботов с использованием специальных библиотек, которые устанавливаются по SSH через composer. Если у вас есть в наличии выделенный сервер или на худой конец платный хостинг с возможностью подключения по SSH то проблем нет, я же использую хостинг бесплатный и там такого нет. Я вообще когда читаю те инструкции в голове происходит каша. Впрочем и инструкции ботов без библиотек вызывают почти аналогичные мысли: вот хорошая инструкция, но я мало что понял из нее (в плане кода), а вот эта даже на английском прояснила больше, и я решил ее перевести сюда.
  • Второй шаг: создаем webhook для вашего бота
На этом этапе создания бота Telegram производится установка webhook, который будет общаться с вашим ботом. Webhooks - это то, как API сообщают вам о том, что что-то произошло, это лишает вас необходимости запрашивать API каждые несколько минут (или секунд), чтобы выяснить, например, было ли отправлено новое сообщение. (прим. переводчика по сути, это механизм оповещения одной системы о событиях в другой. Далее все мои примечания будут подчеркнутые).
Telegram использует только один тип webhook, который отправляет вам объект обновления всякий раз, когда что-то происходит
Настроить webhook довольно просто. Вам нужно знать только две вещи: ваш токен API (вы должны получить его с первого шага) и URL-адрес, по которому вы будете размещать своего бота. URL-адрес будет выглядеть примерно так: https://yourdomain.com/yourbot.php. Убедитесь, что вы включили https в начале URL; в противном случае Telegram не отправит вебхук.
Теперь в обычном веб-браузере перейдите по адресу https://api.telegram.org/bot<yourtoken>/setwebhook?url=https://yourdomain.com/yourbot.php Вуаля, ваш webhook теперь работает!
  • Шаг третий: пишем логику для бота.
Время для веселья! На данный момент у вас есть все, что нужно, чтобы написать логику для своего бота Telegram. Вот как я буду продолжать ... Я слишком мало занимаюсь программированием, чтобы даже иметь IDE на своем компьютере, поэтому я просто открою Блокнот и буду писать свой код там. Так как это PHP, убедитесь, что вы обрамили логику в <? Php?>. Первое, что нужно сделать, это инициализировать переменную, которая облегчит нам вызов API Telegram. Просто добавить код $path="https://api.telegram.org/bot <yourtoken>";
(когда мы отправляем сообщение пользователю через api эта часть адреса всегда будет одинаковая, меняться будет только текст, который расположен в конце адреса)
Поскольку мы будем получать обновления с помощью вебхука, давайте создадим и заполним массив этими данными обновления: $update = json_decode (file_get_contents ("php: // input"), TRUE);
(когда мы настраивали бота в первом шаге, мы пользовались функцией getupdate и телеграм выдавал массив данных, который содержал кучу информации в том числе и  ID чата, данные пользователя, а так же текст отправленного последнего сообщения. Весь этот массив сейчас записывается в переменную $ update)
Теперь, для удобства, давайте извлечем две важные части данных из этого обновления (как я говорил массив данных)- идентификатор чата и сообщение (если обновление не вызвано новым сообщением, это поле может быть пустым, и мы будем писать код для этого позже)

$chatId = $update["message"]["chat"]["id"];
$message = $update["message"]["text"];

(то есть $chatId это ID чата $message - текст сообщения которое юзер отправил боту)

Если вы еще не догадались, что этот бот должен делать, я хочу, чтобы он сообщал мне текущую погоду для моего выбора. Для этого я создам команду / weather [location].Чтобы сделать это, давайте создадим оператор if, чтобы увидеть, начинается ли сообщение с / weather. Мы можем сделать это с помощью функции strpos (), которая сообщает нам положение подстроки в строке:
if (strpos($message, "/weather") == 0) {
}

В фигурных скобках оператора if напишем код для извлечения местоположения, отрубив первые девять символов сообщения (сколько символов используется командой / weather, а также пробел, который последует за ним):
if (strpos($message, "/weather") == 0) {
$location = substr($message, 9);
}

(то есть если условие выполнено и бот увидел слово /weather он начнет искать место, где смотреть погоду, и чтобы это сделать он берет из текста (помните он у нас записан в переменной $message) остальные символы кроме 9 которые относятся к команде /weather.И весь этот текст он записывает в переменную $location)
Если бы этот бот использовался в производстве, нам пришлось бы добавить некоторую очистку ввода, чтобы убедиться, что местоположение принимает правильный формат. Но это не так, поэтому мы не будем беспокоиться об этом.

Теперь мы получим данные о погоде для этого местоположения из OpenWeatherMap:
$weather = json_decode(file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=".$location."&appid=mytoken"), TRUE)["weather"]["main"];
(обратите внимание что для выделения данных из ответа сервера погоды используется такая же конструкция как и для  api telegram. И да, на сервере погоды нужно получить свой токен для использования их API)
Здесь мы должны реализовать какую-то обработку ошибок, но я не буду беспокоиться. Вместо этого давайте надеяться на лучшее и соберем ответ нашего бота с помощью Telegram API:
file_get_contents($path."/sendmessage?chat_id=".$chatId."&amp;text=Here's the weather in ".$location.": ". $.weather);
полный код будет выглядеть так:

<?php
$path = "https://api.telegram.org/bot<yourtoken>";
$update = json_decode(file_get_contents("php://input"), TRUE);
$chatId = $update["message"]["chat"]["id"];
$message = $update["message"]["text"];
if (strpos($message, "/weather") == 0) {
$location = substr($message, 9);
$weather = json_decode(file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=".$location."&appid=mytoken"), TRUE)["weather"][0]["main"];
file_get_contents($path."/sendmessage?chat_id=".$chatId."&text=Here's the weather in ".$location.": ". $weather);
}
?>


  • Шаг четвертый: загрузи бота на сервак
(короче тупо копируешь последний код, сохраняешь как php и кладешь php файл в папку на сервере куда настроил вебхук во втором шаге)

UPDATE: проверил все на практике и появилось несколько уточнений. В конструкции if с функцией strpos лучше использовать не двойное равно ==, а тройное ===, тогда можно добавить несколько аналогичных конструкций для разных условий. Я например тупо добавил боту команды (через отца бота) и теперь конкретная команду показывает погоду в конкретном городе. Удобно тем что не нужно вводить команду и локацию, а можно тупо щелкнуть по подсказке команды и сразу получить результат.
В API сайта погоды, можно извлечь температуру, для этого нужно в квадратных скобках поместить ["main"]["temp"], а для того чтобы температура отображалась в цельсиях, то в адрес нужно добавить еще и &units=metric
Можно добавить язык, и тогда описание погоды может быть переведено на русский язык. И кстати сами запросы городов тоже можно писать по-русски. Чтобы так сделать надо добавить через амперсанд &lang=ru
Можно нагуглить json decode online и подсунуть туда все то, что выдает api сайта погоды. Все это потом появится на выходе декодера в структурированном виде и потом будет проще понять как извлечь эти данные. Кстати в той статье в самом начале(ссылка на  инструкцию на русском языке) эти расшифровки json кода даются и уже прочитав статью второй раз я многое из нее понял. И даже добавил из нее конструкцию по сохранению входящего запроса в текстовый файл. Буквально 4 строчки кода, которые тупо копипастятся:

ob_start();
print_r($update);
$out = ob_get_clean(); 
file_put_contents(__DIR__ . '/message.txt', $out);

Потом я прочитал еще пару статей и нашел там тоже несколько идей. Например конструкция switch:
switch($message) {
    case '/start':
file_get_contents($path. '/sendMessage?chat_id='.$chatId.'&text='.urlencode('😄 бот на связи!'));
    break;
// если в чат написали /start то бот присылает что бот на связи
case '/moscow':
$location ='moscow';
        $weather_query = json_decode(file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=".$location."&units=metric&appid=тут-ваш-токен&lang=ru"), TRUE);
$temper = $weather_query["main"]["temp"];
$weather = $weather_query["weather"][0]["description"];
file_get_contents($path."/sendmessage?chat_id=". $chatId ."&text=Температура в Москве: ". $temper."°C. ".$weather);
    break;
// если приходит команда /moscow то бот присылает погоду в москве
case '/help':
file_get_contents($path."/sendmessage?chat_id=".$chatId."&text=Наберите команду /pogoda и через пробел город, чтобы узнать погоду в этом городе. Например: /pogoda London");
    break;
case '/curs':
$usd = $kzt = 0;
$xml = simplexml_load_file('http://www.cbr.ru/scripts/XML_daily.asp?date_req=' . date('d/m/Y'));
if (!empty($xml)) {
foreach ($xml->Valute as $item) {
if ($item['ID'] == 'R01235') {
$usd = $item->Value;
elseif ($item['ID'] == 'R01335') {
$kzt = $item->Value;
}
}
if (!empty($usd) && !empty($kzt)) {
$usd = round(str_replace(',', '.', $usd),2);
$kzt = round(100/str_replace(',', '.', $kzt),2);
}
}
file_get_contents($path."/sendmessage?chat_id=".$chatId."&text=Курс USD ".$usd." руб за доллар.%0AKZT ".$kzt." тенге за рубль");
    break;
    default:
        $timetext = (date("d M H:i:s")."  ".$ttext);
        file_get_contents($path."/sendmessage?chat_id=тутIDчата&text=".$timetext);
    break;
}

В условии default - это то, что бот отправит, если ни одно из условий не выполнится, то есть любое сообщение боту. То же произойдет и если тупо открыть этот php файл в браузере. И вот тут довольно интересно: если post запросом передать какой-либо текст, то бот сможет переслать этот текст в указанный чат. Я сделал так: добавил в начало  $ttext = $update["type"]; 
Теперь если запустить на своем компьютере скрипт vbs c таким содержимым:

Dim objHTTP
strJSONToSend = "{""type"": ""ваш текст""}"

Set objHTTP = CreateObject("Microsoft.XMLHTTP")
Call objHTTP.Open("POST", "https://yourdomain.com/yourbot.php", false)
objHTTP.setRequestHeader "Content-Type", "application/json"
objHTTP.Send strJSONToSend

то бот отправит вам сообщение с вашим текстом. Таким образом можно использовать этого бота в том числе и для уведомлений о каких-либо событиях.

Ну и под конец, отправка картинки с сервера: в папку с ботом добавляем картинку с именем image.png а в код бота этот код, в нужное место и с нужными опциями
$response = array(
'chat_id' => $data['message']['chat']['id'],
'photo' => curl_file_create(__DIR__ . '/image.png')
);

$ch = curl_init('https://api.telegram.org/bot' . $token . '/sendPhoto');  
curl_setopt($ch, CURLOPT_POST, 1);  
curl_setopt($ch, CURLOPT_POSTFIELDS, $response);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_exec($ch);
curl_close($ch);

1 комментарий:

  1. https://golos.io/@tristamoff/sozdat-svoego-bota-v-telegram-prosto-kak-dvazhdy-dva
    https://www.net4me.net/php/telegram-bot-php/

    ОтветитьУдалить