Telegram бот на PHP. Как сохранять состояние ответа пользователя?
Только начинаю знакомиться с Telegram API для ботов (до этого весь опыт разработки ботов сводился к написанию простейших полезняшек для себя, вроде по команде /stat отправить некоторую сводную информацию, собранную PHP скриптом из разных источников) поэтому хотел бы уточнить следующее. Допустим мы пишем простейшего бота на PHP без использования сторонних библиотек и классов. Возможно ли реализовать функционал "опроса" пользователя с сохранением состояний ответов без использования MySQL, сохранения в файлы и т.п. Если утрированно, то постановка задачи такая:
- Имеем хост с установленным Apache + PHP, поддержка SSL настроена, бот запущен и настроен через setWebhook.
- Реализовать простейший опрос пользователя, например, спросить у него имя, год рождения и знак зодиака, после чего вывести ему в ответ какую-нибудь картинку (например его имя на красивом фоне с наложением знака зодиака).
И вот тут, даже на "теоретической стадии", у меня возник следующий вопрос. Фактически мы должны узнать у пользователя три входных параметра param1 (name), param2 (year), param3 (zodiac). "Опрос" пользователя считается завершенным если он корректно ввел все три параметра, только после этого выдается результат - картинка (ну или с введенными данными осуществляются какие-то другие действия). Какие варианты отслеживания текущего состояния пользователя в опросе из скрипта существуют? Сервер Telegram "дергает" скрипт каждый раз, когда пользователь присылает какое-либо сообщение и при этом абсолютно не знает о том что следующее сообщение пользователя относится к какому-либо этапу выполнения сценария скрипта.
Например, пользователь дал команду /poll и тем самым начал участие в опросе. После чего бот задает ему первый вопрос, а-ля введите param1. Если введенные пользователем данные прошли валидацию, то бот переходит к следующему шагу и задает второй вопрос, введите param2 и т.п. Если же параметр введен неверно, например указан 3027 год, то бот должен "переспросить" пользователя, т.е. запросить повторный ввод данных. Так вот, вопрос в следующем - как лучше всего отслеживать состояние (на каком этапе он находится, ввод имени, ввода года, ввод знака зодиака) пользователя в этом опросе?
Если бы у нас была MySQL, то можно было бы хранить id пользователя и некое значение state в БД и исходя из этого строить логику работы бота. Т.е. если значение state=1, например, значит пользователь участвует в опросе и отвечает на первый вопрос, если state=2, то отвечает на второй и т.п. То же самое применимо и к хранению состояний в файлах. По-крайней мере это самое логичное что мне пришло в голову. Но может быть есть какое-то более оптимальное решение (например, можно как-то передать серверу Telegram некий параметр state, который придет вместе со следующим сообщением пользователя) или еще что-нибудь в этом духе?
Как бы вы реализовали подобное в описанных стартовых условиях? (напомню что задача носит "учебный" характер, наверняка есть какие-то библиотеки, классы и т.п. использующие БД и позволяющие реализовать все описанное в одну строчку кода, но мне куда интереснее понять принцип как сохранять "состояние пользователя" и определять на каком шаге "сценария" он находится без их использования, т.е. как это реализуют в большинстве ботов, использующих интерактивные диалоги с пользователем).
Метод отправки сообщения sendMessage() не предлагает никакого параметра, который бы «пробрасывался» клиенту для последующих запросов. Кроме клавиатур.
Наверное, можно попробовать давать Inline Keyboard для последующих ответов, содержащих в своих параметрах его предыдущие ответы (до 64 байт).
Например, первым вопросом спрашивать что-то длинное типа имени-фамилии, чтобы он ввёл текстом. А последующие ответы принимать только через заготовленные кнопки.
Но всё это попахивает ржавым велосипедом. Вам лучше подумать, как хранить state на сервере. Пусть во временном in-memory хранилище – Memcached или Redis.
Сергей Соколов, спасибо за ответ. Сейчас как раз читаю про Inline Keyboard и уже попробовал набросать простенький пример (правда анализировать callback_data еще не пробовал, но общий смысл я уловил, что после того как пользователь нажимает inline кнопку от сервера приходит CallbackQuery с полем data). Но это все хорошо в кейсах с выбором только какого-то определенного параметра.
То что я хочу реализовать, скорее напоминает обычную web-форму с param1, param2, param3 и кнопкой Submit. В случае если нам нужно просто обработать введенные данные и вывести результат пользователю - хранить где-либо нам их не обязательно, достаточно того чтобы они попали в скрипт обработчик. Проблема с ботом Telegram заключается в том, что как раз "единого submit'а" то и нет, т.е. данные в любом случае придут в трех разных сообщениях и нам действительно как-то нужно сохранять state на сервера обработчика.
С memcached к сожалению никогда не работал, о redis весьма посредственное представление (т.е. знаю что такое есть и для чего оно, но на практике никогда использовал его). К тому же задача осложняется еще и тем, что речь в данном случае идет о дешевом shared-хостинге, на котором не то что redis'ы, а даже лишние модули к PHP не подключить.
Какой на ваш взгляд в данной ситуации будет метод хранения state'ов? Может их в json запихивать и в текстовые файлы через file_put_contents класть или кто-нибудь посоветует более "гуманный" способ?
Decker: Memcache и Redis просто хранилища для пар ключ-значение. Ключом у вас будет id пользователя, значением - строка JSON с состоянием. Можно и в файлах держать, но это чуть медленнее и тяжелее: будут накаплаиваться файлы. А в Redis можете сразу указывать время жизни. Ведь через сутки уже не понадобятся данные человека, который забросил диалог с ботом.
Если хранить нужно будет не только состояния и понадобится SQL, можно посмотреть в сторону SQLite который хранит всю базу просто в файле и работает без собственного сервера.