Как отлаживать написанного на PHP telegram бота?
Дано: Сделал helloworld-бота. Я могу ему послать сообщение, он дёргает телеграм, телеграм дёргает php скрипт, который отсылает сообщение обратно юзеру (тоже посредством дёргания телеграма). Задача: Я хочу видеть (удобно и реалтайм) те json , кои мне присылает телеграм и которые я ему обратно отправляю. Возможное решение: В данный момент я либо пишу из php скрипта нужные данные в файл и подгружаю его вручную с сервера в IDE (или просто файлом на комп) после каждого запроса. Это работает, но аццки не удобно. Вопрос: Как мне максимально удобно организовать отладку? Я привык к выводу явы в консоль sout -ом)
Отслеживать
задан 30 апр 2016 в 12:01
69.8k 9 9 золотых знаков 66 66 серебряных знаков 123 123 бронзовых знака
tail -f /path/to/log.log
30 апр 2016 в 13:58
@Etki, и как и куда это вбивать.
30 апр 2016 в 15:45
на сервере, где выполняется код. будет выводить вам файл лога по мере его обновления
30 апр 2016 в 21:46
@Etki, если у меня платный хостер это тоже можно сделать. В смысле у меня там, насколько я знаю, не полный доступ ко всему. Хост сайта, БД, PHP, вроде и всё.
30 апр 2016 в 22:03
Это уже к хостеру скорее вопрос. Но я подозреваю, что хостер стоит дороже vps на том же vscale
Как сделать уведомления в телеграм на PHP
Привет! Сегодня поговорим о том, как можно отправить себе сообщение в телеграмме с помощью PHP. Это удобно использовать, когда нужно получить уведомление о каком-то событии, произошедшем на бэкенде. Например, я таким образом получаю уведомления о новых комментариях к урокам.
Первое, что нам нужно сделать — это зарегать в телеге нового бота. Это делается при помощи другого бота, которого зовут @BotFather. Пишем ему команду:
/newbot
В ответ он попросит написать ему имя бота. Я назвал своего PhpZoneNotifier. Пишем, отправляем.
После этого он попросит прислать username для бота — это адрес, используемый в телеге для поиска пользователей. Username бота должен заканчиваться словом bot. Я выбрал в качестве юзернейма phpzonenotifier_bot. Отправляем.
- Курс HTML для начинающих
- Курс PHP для начинающих
- Курс MySQL для начинающих
- Курс ООП в PHP

В ответ получаем токен вида 123:ABCDEF. С помощью этого токена мы можем авторизоваться в телеге от имени этого бота.
Теперь нужно узнать наш собственный id в телеграме. По нему бот будет отправлять нам сообщения. Чтобы узнать этот айдишник, нужно написать боту @userinfobot команду /start.
- Тест на знание основ HTML
- Тест на знание основ PHP
- Тест на знание ООП в PHP

После того, как мы получили auth token бота и наш id, можно приступать к написанию кода для отправки. Телеграм предоставляет довольно простой API для этого дела. Всё что нужно — это отправить POST-запрос на адрес:
https://api.telegram.org/bot/sendMessage
Где вместо подставить токен бота, полученный выше.
В теле запроса нужно передать 2 параметра:
- chat_id — сюда передаём наш id пользователя
- text — сюда передаём текст сообщения
Для отправки запроса я использовал Guzzle.
post('https://api.telegram.org/bot1869549332:AAGhlRm5*************/sendMessage', [ RequestOptions::JSON => [ 'chat_id' => 298160970, 'text' => $text, ] ]); > catch (\Exception $e) < var_dump($e->getMessage()); > > >
После чего пытаемся отправить сообщение, вызвав:
TelegramNotifier::notify('lol kek cheburek');
И видим, что произошло исключение. var_dump вывел следующее:
Так происходит потому что у бота нет чата с вами. Это защита телеги от рассылки спама — чтобы боту было позволено вам писать, вы сначала должны сами написать боту. Так что просто пишем нашему новому боту /start и снова пробуем запустить наш PHP-скриптик.
Получаем наше заветное уведомление.

Изи. Не забываем убрать отладочный var_dump из кода и добавить корректную обработку исключений.
Добавляем веб-интерфейс к телеграм-боту
Продолжаем показывать, как работают вместе бэкенд и фронтенд. У нас уже вышло про это две статьи — как сделать простой проект телеграм-бота и как запустить с ним полноценный бэкенд. Вот краткое содержание:
- У нас есть скрипт на Python, который играет роль бэкенда — он записывает некие данные в базу и потом их выводит.
- Скрипт получает данные из фронтенда — Телеграма. В Телеграме для этого работает бот, а мостиком между Телеграмом и нашим скриптом служит специальная библиотека Python.
- На фронтенде пользователь отчитывается, что он сделал за сегодня. Эти отчёты прилетают на бэкенд, наш скрипт их принимает и записывает в базу данных.
- По специальной команде скрипт выплёвывает то, что у него сейчас есть в базе данных. Выплёвывает в бота.
При этом бэкенд не зависит от фронтенда — ему всё равно, куда отдавать данные и как их будут отображать. Воспользуемся этим и сделаем ещё один фронтенд для проекта — на этот раз в виде веб-страницы. Предположим, что это для менеджера, который хочет контролировать работу команды.
Что делаем
- Веб-страницу, внутри которой будет работать второй фронтенд.
- Внутри неё — PHP-скрипт, который будет получать данные из бэкенда.
Почему PHP? Потому что он подходит для этой простой задачи: вывести все данные из базы один раз.
Если бы нам нужно было закрыть эту страницу паролем, выдавать разные ключи разным людям, выводить данные по разным пользователям и т. д. — нужно было бы использовать Python и фреймворк Django. Но это большой труд: развернуть всё это хозяйство на сервере, а потом изучить конструкции и паттерны Django. Это имеет смысл для большого долгоиграющего проекта и не имеет для одноразовой странички.
И так всю жизнь: сначала делаешь что-то на костылях, а потом эти костыли подпирают огромные проекты за много миллиардов рублей.
Исходный Python-код телеграм-бота
# подключаем модуль для Телеграма import telebot # модуль работы со временем from datetime import datetime, timezone, timedelta # модуль для работы с базой данных import sqlite3 as sl # указываем токен для доступа к боту bot = telebot.TeleBot('6285051364:AAGG2iZ77NIeWj0YjqIs791qxPhvcS3Yu0s') # приветственный текст start_txt = 'Привет! Это журнал «Код». \n\nТеперь у бота появился бэкенд.' # подключаемся к файлу с базой данных con = sl.connect('reports.db') # открываем файл with con: # получаем количество таблиц с нужным нам именем data = con.execute("select count(*) from sqlite_master where type='table' and name='reports'") for row in data: # если таких таблиц нет if row[0] == 0: # создаём таблицу для отчётов with con: con.execute(""" CREATE TABLE reports ( datetime VARCHAR(40) PRIMARY KEY, date VARCHAR(20), id VARCHAR(200), name VARCHAR(200), text VARCHAR(500) ); """) # обрабатываем старт бота @bot.message_handler(commands=['start']) def start(message): # выводим приветственное сообщение bot.send_message(message.from_user.id, start_txt, parse_mode='Markdown') # обрабатываем команду /now @bot.message_handler(commands=['now']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем сегодняшнюю дату now = datetime.now(timezone.utc) date = now.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос к базе data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # перебираем все результаты for row in data: # формируем строку в общем отчёте s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за сегодня if s == '': # формируем новое сообщение s = 'За сегодня ещё нет записей' # отправляем общий отчёт обратно в телеграм bot.send_message(message.from_user.id, s, parse_mode='Markdown') # обрабатываем команду /yesterday @bot.message_handler(commands=['yesterday']) def start(message): # подключаемся к базе con = sl.connect('reports.db') # получаем вчерашнюю дату yesterday = datetime.today() - timedelta(days=1) y_date = yesterday.date() # пустая строка для будущих отчётов s = '' # работаем с базой with con: # выполняем запрос data = con.execute('SELECT * FROM reports WHERE date = :Date;',) # смотрим на результат for row in data: # если результат пустой — ничего не делаем if row[0] == 0: pass # если вчера были какие-то отчёты else: # добавляем их в общий список отчётов s = s + '*' + row[3] + '*' + ' → ' + row[4] + '\n\n' # если отчётов не было за вчера if s == '': # формируем новое сообщение s = 'За вчерашний день нет записей' # отправляем пользователю это новое сообщение bot.send_message(message.from_user.id, s, parse_mode='Markdown') # обрабатываем входящий отчёт пользователя @bot.message_handler(content_types=['text']) def func(message): # подключаемся к базе con = sl.connect('reports.db') # подготавливаем запрос sql = 'INSERT INTO reports (datetime, date, id, name, text) values(?, ?, ?, ?, ?)' # получаем дату и время now = datetime.now(timezone.utc) # и просто дату date = now.date() # формируем данные для запроса data = [ (str(now), str(date), str(message.from_user.id), str(message.from_user.username), str(message.text[:500])) ] # добавляем с помощью запроса данные with con: con.executemany(sql, data) # отправляем пользователю сообщение о том, что отчёт принят bot.send_message(message.from_user.id, 'Принято, спасибо!', parse_mode='Markdown') # запускаем бота if __name__ == '__main__': while True: # в бесконечном цикле постоянно опрашиваем бота — есть ли новые сообщения try: bot.polling(none_stop=True, interval=0) # если возникла ошибка — сообщаем про исключение и продолжаем работу except Exception as e: print('❌❌❌❌❌ Сработало исключение! ❌❌❌❌❌')
Запускаем скрипт бэкенда на сервере
Сейчас наш скрипт работает локально на компьютере. Если компьютер выключить или пропадёт интернет, скрипт и бот перестанут работать. Это плохо для бэкенда — он должен работать всё время и без перебоев.
Мы можем запустить скрипт на сервере — то есть на чужом компьютере, который мы арендуем за деньги. Разница в том, что сервер всё время работает и редко перезагружается.
Для запуска скрипта на сервере нам потребуется собственно арендованный виртуальный сервис. А дальше воспользуемся рецептом из нашей старой статьи про запуск бота:
- Запускаем SSH-клиент и входим на наш сервер как администраторы.
- В SSH-терминале пишем по очереди такие команды (вместо .thecode можно написать название каталога, которое вам по душе):
virtualenv .thecode
source .thecode/bin/activate - Установим Python-модуль для работы с Телеграмом:
pip install pytelegrambotapi - Когда установка закончится, пишем такую команду (не забывайте поменять путь к файлу на свой):
python3 osebe/public_html/projects/front/backend.py - Если хотите, чтобы после закрытия SSH-клиента или терминала бот продолжал работать, в последней команде в начале напишите nohup
Проверим работу бота после запуска на сервере:

Бот реагирует на команды и запоминает то, что мы ему пишем, значит, бот на сервере работает как нужно.
По идее нам нужно было отправить бота в защищённую папку, например cgi-bin, чтобы никто не мог получить доступ к базе. Но для простоты проекта мы не стали тратить на это время — сделаем это отдельно и расскажем, как это работает.
Создаём страницу
Наш новый фронт — это веб-страница, поэтому напишем простой код, который создаст обычную страницу с заголовком. Создадим новый файл front.php (не HTML, это важно!) и запишем в него такой код. Это весь HTML-код, который нам понадобится, — всё остальное будем делать на PHP. Если не знаете, что такое PHP, — вот подборка для начала:
А вот код страницы:
Простой фронтенд к базе данных Отчёты
Теперь кладём этот файл на сервер в ту же папку, где и python-скрипт, чтобы всё было в одном месте, и открываем страницу в браузере.

Подключаемся к базе данных
Сразу после заголовка добавляем PHP-вставку, вся магия будет происходить внутри.
Чтобы подключиться к базе данных, используем команду SQLite3() и сразу выведем сообщение об успешном подключении. Если мы его увидим — всё работает, можно двигаться дальше.
// подключаемся к базе данных $connection = new SQLite3('reports.db'); // если подключились if($connection)< // выводим сообщение echo "✅ Подключились к базе данных
"; >

Выводим отчёты
Мы будем выводить две группы отчётов: за сегодня и за остальные дни. Для этого нам нужно сделать так:
- Получить дату в нужном формате.
- Выгрузить все сегодняшние отчёты.
- Посмотреть, есть ли они вообще, если нет — выдать сообщение, что их нет.
- Если есть — вывести даты и отчёты.
- То же самое сделать для отчётов за остальные дни.
Запишем это всё на PHP — мы добавили комментарий к каждой строчке, чтобы было понятнее, как это всё работает:
// получаем дату в нужном формате $date = date('Y-m-d'); // выводим подзаголовок echo 'За сегодня
'; // получаем сегодняшние отчёты из базы $results = $connection->query("SELECT * FROM 'reports' WHERE 'date' == $date"); // получаем количество отчётов $row=$results->fetchArray(SQLITE3_ASSOC); // если они есть if ($row != false) < // заново получаем отчёты из базы $results = $connection->query("SELECT * FROM 'reports' WHERE 'date' == $date"); // пока есть записи в результатах поиска — выводим их while($row=$results->fetchArray(SQLITE3_ASSOC))< echo '' . $row['date'] . '
'; echo 'Ник: ' . $row['name'] . '
'; echo 'Отчёт: ' . $row['text'] . '
'; echo '
'; > // если отчётов нет > else < echo "За сегодня записей нет
"; > // выводим подзаголовок echo 'Остальные отчёты
'; // выгружаем остальные отчёты из базы $results = $connection->query("SELECT * FROM 'reports' WHERE 'date' != $date"); // пока есть записи в результатах поиска — выводим их while($row=$results->fetchArray(SQLITE3_ASSOC))< echo '' . $row['date'] . '
'; echo 'Ник: ' . $row['name'] . '
'; echo 'Отчёт: ' . $row['text'] . '
'; echo '
'; >
Добавляем этот код в PHP-блок после подключения к базе, заливаем файл front.php на сервер и обновляем страницу:

Получается, что у нашего телеграм-бота появился второй фронтенд, который берёт те же данные, что и бот, но отображает их в другом месте и в другом формате.
Что дальше
Технически у нас всё сделано:
- есть бэкенд на сервере, который принимает отчёты и сохраняет их в базе;
- есть фронтенд — телеграм-бот со стандартным интерфейсом;
- есть ещё один фронтенд — веб-страница со всеми отчётами;
- всё это работает на сервере без нашего участия.
Но внутри много шероховатостей: всё ещё неоптимизированный код, небезопасное расположение базы, нет кнопок выбора дня на странице и так далее. Это можно исправлять в будущем.
Ещё один шаг в Python
Мы сделали проект с фронтом на PHP, а бэкенд работает на Python и SQLite. Если вам интересно делать такое, возможно, это ваше призвание. Приходите в Практикум: нам нужны такие, как вы.
Телеграм-бот на сервере: загрузка, настройка и запуск
В предыдущей статье мы рассказали, как создать простого бота на Node.js, однако он работал только на локальном компьютере. Эта статья о том, как загрузить бота на сервер, запустить его и проверить, что всё работает.
Шаг 1. Выбрать хостинг
Как правило, на shared-хостинге отсутствует поддержка Node.js, поэтому нам понадобится как минимум виртуальный сервер. Существуют сервисы, предлагающие VPS бесплатно, но с заметными ограничениями: например на количество трафика или нагрузку на сервер. Можно выделить несколько известных зарубежных провайдеров (но стоит отметить, что для новичков они могут оказаться сложными):
- Google Cloud
- Oracle Cloud
- Amazon Web Services
Преимущество платных VPS в более высоких лимитах или их отсутствии, а также в гарантии стабильной работы сервера. Вместе с этим вы получаете активную поддержку и всегда можете рассчитывать на помощь хостинг-провайдера, если возникнут проблемы.
Для примера мы закажем облачный VPS в REG.RU, вы можете воспользоваться любым VPS-хостингом. Он удобен для тестового проекта тем, что оплата почасовая. При выборе тарифа мы рекомендуем ориентироваться на несколько параметров:
- Прогнозируемая нагрузка — зависит от сложности вашего бота и количества запросов к нему.
- Количество оперативной памяти — это зависит от многих факторов, как, например, уровень оптимизации кода и общий масштаб вашего проекта.
Так как наш бот использует только одну основную библиотеку и состоит из нескольких строк кода, мы выбираем самый младший тариф — Cloud-0. В будущем, если возникнет необходимость, можно перейти на более дорогой тариф.
Шаг 2. Заказать хостинг
Переходим по ссылке: https://www.reg.ru/vps/cloud/, выбираем тариф, операционную систему и шаблон «Чистая ОС». Если у вас нет особых предпочтений, рекомендуем выбрать Ubuntu 18.04. Хотя у REG.RU есть шаблон c Node.js, для чистоты эксперимента всё необходимое ПО мы установим сами. Нажимаем кнопку «Заказать»:

После заказа и оплаты дождёмся настройки сервера:

В течение минуты статус сервера сменится с «В процессе» на «Активен». После этого отобразятся реквизиты доступа к серверу, они также будут отправлены на почту:

Шаг 3. Загрузить бота
Приступим к загрузке бота на сервер. Это можно сделать разными способами — с помощью FTP, SFTP, панели управления или, к примеру, rsync. Мы выберем самый быстрый вариант — SFTP, так как для него нужна только возможность подключения к серверу по SSH, которая обычно присутствует на всех VPS сразу после заказа.
Мы подключимся к серверу с помощью FileZilla. Укажем IP-адрес сервера, а также логин root и пароль в настройках клиента:

При первом подключении появится окно с предупреждением:

Ставим галочку «Всегда доверять этому хосту» и нажимаем «Ок».
Переходим на директорию выше ( . ), затем в каталог /opt и создаём папку с произвольным названием (мы выбрали keksbot ):

Переходим в созданную папку и загружаем файлы index.js и package.json :

Шаг 4. Зайти на сервер по SSH
Теперь нужно подключиться к серверу по SSH, чтобы установить Node.js и запустить бота. Для этого необходим SSH-клиент, например Putty, XShell, Bitvise SSH или любой другой. Функциональность программ может немного отличаться, но большой разницы в использовании между ними нет. Мы выбрали PuTTY как самый популярный и бесплатный SSH-клиент для Windows.
Открываем PuTTY, указываем IP-адрес сервера, порт 22 уже указан по умолчанию:

Нажимаем «Соединиться». Откроется окно с запросом логина:

Вводим root , после чего появится запрос пароля, при вводе которого символы не отображаются. Не стоит переживать, это особенность работы Linux — пароль нужно вводить вслепую. Чтобы не делать этого вручную, можно скопировать пароль и нажать правой кнопкой мыши в окне PuTTY. Убедитесь, что вы скопировали пароль без пробелов!
Шаг 5. Установить Node.js
Теперь займёмся установкой. Обратите внимание, что команды для установки Node.js отличаются в зависимости от операционной системы. В наших примерах указаны команды для Ubuntu, Debian и CentOS — мы будем вводить их в консоли SSH-клиента.
Если вы не знаете, какая ОС установлена на сервере, можете проверить это командой:
cat /etc/os-release
Вывод будет примерно таким:
NAME="Ubuntu" VERSION="16.04.6 LTS (Xenial Xerus)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 16.04.6 LTS" VERSION_ID="16.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" VERSION_CODENAME=xenial UBUNTU_CODENAME=xenial
Нас интересует поле NAME , в котором указано название дистрибутива.
Помимо Node.js нам понадобится утилита Screen, чтобы бот продолжал работать, когда мы отключимся от сервера. Также нужен менеджер пакетов npm для установки зависимостей.
apt -y install nodejs npm screen
yum -y install nodejs npm screen
Подождём завершения установки и проверим, что Node.js работает:
nodejs -v
Если в ответе отобразилась версия установленного пакета, то всё прошло успешно.
Теперь перейдём в папку с файлом бота и установим зависимости:
cd /opt/keksbot npm install
Возможные ошибки при установке, и как их решить
При установке могут появиться ошибки вида:
Existing lock /var/run/yum.pid: another copy is running as pid 9571. Another app is currently holding the yum lock; waiting for it to exit.
E: Could not get lock /var/lib/dpkg/lock – open (11: Resource temporarily unavailable) E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
Обычно это связано с тем, что у пользователя недостаточно прав для установки пакетов на сервере, либо предыдущий процесс установки завершён некорректно.
В первом случае необходимо убедиться, что вы подключились к серверу под именем суперпользователя root — при необходимости зайдите на сервер заново.
Во втором случае для решения проблемы нужно завершить процесс менеджера пакетов и удалить lock -файлы. Чтобы это сделать, запустите команды:
ps aux | grep ‘apt\|apt-get’ | awk ‘’ | xargs kill -9 rm -f /var/cache/apt/archives/lock rm -f /var/lib/dpkg/lock rm -rf /var/lib/dpkg/lock-frontend
ps aux | grep ‘yum’ | awk ‘’ | xargs kill -9 rm -f /var/cache/apt/archives/lock rm -f /var/lib/dpkg/lock
После этого попробуйте заново запустить установку.
Шаг 6. Запустить и проверить бота
Пришло время запустить бота. Для начала запустим утилиту Screen простой командой:
screen
Перейдём в каталог с файлом бота:
cd /opt/keksbot
npm install
После этого можем запустить бота:
nodejs index.js
Заходим в Telegram, проверяем бота:

Отлично! Всё работает.
Теперь можно отключиться от сервера и закрыть окно PuTTY, бот продолжит работу.
Шаг 7. Обеспечить автоматический перезапуск бота
Из-за ошибок в коде бот может «упасть» в самый неожиданный момент. Чтобы этого не случилось, настроим автозапуск бота при старте сервера и его автоматический перезапуск при ошибках.
Это позволит боту стабильно работать даже в случае обнаружения багов. Вы сможете оперативно их исправить, а бот в это время продолжит отвечать на запросы.
Большинство современных Linux-систем используют systemd для управления службами, поэтому следующая инструкция подойдёт для последних версий Ubuntu, Debian и CentOS.
Для начала отключим бота командой:
killall node
Нам понадобится создать собственную службу, для этого в каталоге /lib/systemd/system создадим файл:
имя_бота.service
В нашем случае это будет файл /lib/systemd/system/keksbot.service . В файл поместим следующий код:
[Unit] Description=Keksbot - Telegram bot After=network.target [Service] ExecStart=/usr/bin/node index.js ExecReload=/usr/bin/node index.js WorkingDirectory=/opt/keksbot/ KillMode=process Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
Текст в некоторых строках необходимо отредактировать относительно вашего проекта. Разберём строки, на которые нужно обратить внимание.
В поле Description указывается описание службы. Вы можете указать в ней краткую информацию о боте.
Description=Keksbot - Telegram bot
Команда для запуска бота.
ExecStart=/usr/bin/node index.js ExecReload=/usr/bin/node index.js
Её следует поменять, если имя скрипта вашего бота отличается от index.js . В таком случае нужно будет указать следующие значения:
ExecStart=/usr/bin/node имя_файла.js ExecReload=/usr/bin/node имя_файла.js
Папка со скриптом, который мы запускаем. В нашем случае это /opt/keksbot/ .
WorkingDirectory=/opt/keksbot/
Сохраняем файл. В примерах далее мы будем использовать имя службы keksbot — если вы указали другое имя, не забудьте поменять его. Для установки службы воспользуемся командами:
systemctl enable keksbot
Теперь запустим бота командой:
systemctl start keksbot
Готово. Теперь бот будет автоматически запускаться при старте сервера или при возникновении ошибок. Можно проверить это, завершив процесс node:
killall node
Через пять секунд бот автоматически перезапустится.
Помимо запуска мы можем управлять ботом командами:
systemctl stop keksbot
systemctl restart keksbot
systemctl status keksbot
Ещё о создании бота:
- Как написать Телеграм-бота на JavaScript
- Как настроить работу Телеграм-бота с Google Sheets
«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.