Эта заметка не про Bot API, а про Core API Telegram, с помощью которого можно создавать полноценные клиенты для месседжера, и конечно же любой другой софт, например для сбора данных из Телеграма. Основная проблема заключается в том, что общение с серверами Telegram осуществляется по специальному протоколу разработанным внутри компании — MTProto. Именно благодаря этому протоколу данный месседжер и славится своей безопасностью и шифрование данных.
Вас мучают вопросы: как использовать Telegram Api на PHP? Как вызывать функции? Очень много примеров использования telegram api для бота, а как использовать обычное api telegram? Зарегистрировал приложение, получил api_id и api_hash, как получить все сообщения из телеграм-канала? https://core.telegram.org/method/messages.getHistory
Как вызвать этот метод? Как реализовать авторизацию с помощью API Telegram? Тогда эта статья для вас!
Естественно, разбирать нюансы протокола MTProto в данной заметке я не буду. Для работы с ним буду пользоваться PHP-библиотекой MadelineProto, доступной всем желающим на GitHub. Однако, нельзя просто так взять и воспользоваться библиотекой. Есть как минимум три нюанса, которые нужно решить.
Подготовка к установке MadelineProto
Во-первых, нужен установленный Python, будет достаточно версии 2.7.
Во-вторых, библиотека не помечена как стабильная, поэтому для подключения её через composer к существующему проекту нужно немного отредактировать composer.json:
"minimum-stability": "dev",
Для того, чтобы composer не ругался на отсутствие стабильных версий зависимостей. Без указания этой директивы во время установки библиотеки будет получена примерно такая ошибка:
Your requirements could not be resolved to an installable set of packages. Problem 1 - Installation request for danog/madelineproto ^2.0 -> satisfiable by danog/madelineproto[2.0]. - danog/madelineproto 2.0 requires danog/primemodule dev-master -> satisfiable by danog/primemodule[dev-master] but these conflict with your requirements or minimum-stability. Installation failed, reverting ./composer.json to its original content.
Затем нужно указать git-репозиторий библиотеки:
"repositories": [
{
"type": "git",
"url": "https://github.com/danog/phpseclib"
}
],
и только затем можно устанавливать саму либу:
composer require danog/madelineproto
Если во время установки зависимостей появится ошибка на подобии такой:
github Failed to clone via https, ssh protocols, aborting.
error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
То вам нужно обновить версию git.
Регистрация приложения для Telegram API
Теперь нужно зарегистрировать приложение в разделе API development tools и получить App api_id и App api_hash.
Как правильно использовать MadelineProto с Laravel
В-третьих, на сегодняшний день (2017-02-10) мне не удалось запустить MadelineProto из коробки, т.к. начинали сыпаться ошибки типа:
DataCenter: Connecting to DC 2 (main server, ipv4, tcp_full)... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 443... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 80... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 88... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 443 without the proxy... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 80 without the proxy... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 DataCenter: Connection failed, retrying connection on port 88 without the proxy... Exception: stream_set_timeout() expects parameter 1 to be resource, null given in Socket.php:153 Exception: Undefined offset: 2 in MsgIdHandler.php:77 CallHandler: An error occurred while calling method help.getNearestDc: Undefined offset: 2 in MsgIdHandler on line 77. Recreating connection and retrying to call method... Exception: Undefined offset: 2 in MTProto.php:641 In MTProto.php line 641: Undefined offset: 2
На самом деле здесь нет ничего фатального, просто фреймворк Laravel по-умолчанию перехватывает все ошибки и при отсуствии должных обработчиков завершает скрипт даже при наличии не критичных ошибок. Возможно такое поведение присутствует и в других фреймворках. Можно изменить уровень ошибок, добавив в метод \App\Providers\AppServiceProvider::boot() строку:
error_reporting(0);
Но тогда есть вероятность пропустить некритичные ошибки своего приложения.
Вторым способом устранения ошибок будет правка исходника /vendor/danog/madelineproto/src/danog/MadelineProto/Connection.php, а именно нужно закомментировать 3 строки в конструкторе в условии
case 'tcp_full':
// $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
// $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
// $this->sock->setBlocking(true);
В коммите 56c0d431768c04009ae9aa3151715b5e6399ec4d эти строки находятся на 105-107 строках файла. Источник проблемы был найден с помощью отладчика xDebug. Проблема заключалась в том, что методы $this->sock->setOption() и $this->sock->setBlocking() пытались работать с ещё не созданным объектом $this->sock->sock. Если у вас возникнут другие ошибки, то с помощью отладчика вы их легко обнаружите и исправите.
Также в библиотеку могут быть зашиты устаревшие или не актуальные IP-адреса серверов Телеграма. Их всегда можно посмотреть на странице API development tools и передать в ModelineProto через конструктор \danog\MadelineProto\API().
Список всех параметров которые можно изменить в этой библиотеке можно посмотреть в массиве $default_settings метода \danog\MadelineProto\MTProto::parse_settings().
В идеале нужно зарегистрировать для приложения новую чистую учётную запись, но для тестирования и отладки вполне сгодится любая уже имеющаяся учётка Телеграма.
Пример работы MadelineProto на Laravel
Как делать запросы к Telegram API на PHP?
Приведу простой пример кода на базе консольной команды для Laravel:
public function handle() {
// Если файл с сессией уже существует, использовать его
if(file_exists( env('TELEGRAM_SESSION_FILE') ) ) {
$madeline = new API( env('TELEGRAM_SESSION_FILE') );
} else {
// Иначе создать новую сессию
$madeline = new API([
'app_info' => [
'api_id' => env('TELEGRAM_API_ID'),
'api_hash' => env('TELEGRAM_API_HASH'),
]
]);
// Задать имя сессии
$madeline->session = env('TELEGRAM_SESSION_FILE');
// Принудительно сохранить сессию
$madeline->serialize();
// Начать авторизацию по номеру мобильного телефона
$madeline->phone_login( env('TELEGRAM_PHONE') );
// Запросить код с помощью консоли
$code = readline('Enter the code you received: ');
$madeline->complete_phone_login($code);
}
$messages = $madeline->messages->getHistory(['peer' => '@ANY_CHANNEL_ID', 'offset_id' => 0, 'offset_date' => 0, 'add_offset' => 0, 'limit' => 10, 'max_id' => 0, 'min_id' => 0, 'hash' => 0, ]);
foreach($messages['messages'] as $msg) {
dump($msg);
}
}
Для тех, кто не умеет в Laravel, кратко поясню. Вызовы env() — это запросы значений из файла конфигурации, можно заменить их на константы или захардкодить. Собственно:
TELEGRAM_SESSION_FILE — любое значение, которое можно использовать в качестве имени файла.
TELEGRAM_API_ID и TELEGRAM_API_HASH — Данные из API development tools.
TELEGRAM_PHONE — мобильный номер существующий учётки, например, +7XXXXXXXXXX.
Теперь пояснения о происходящем в коде. Сессия — достаточно важный объект клиента, без него при каждом запуске скрипта авторизовываться и вводить код из сообщения, который Telegram высылает либо в смс либо через сам месседжер. Также на этапе авторизации происходит вся знаменитая шифровочная телеграм-магия. Процесс не быстрый, на моём тестовом стенде он мог затягиваться на минуты.
В результате работы скрипта в консоль будет выведено огромное количество отладочной информации, на которую можно не обращать внимания. При первом запуске сессии нужно будет авторизоваться в месседжере:
API: Running APIFactory... API: MadelineProto is ready! API: Serializing MadelineProto... Login: Sending code... Login: Code sent successfully! Once you receive the code you should use the complete_phone_login function. Enter the code you received: ... Login: Logging in as a normal user... MTProto: Trying to copy authorization from dc 2 to dc 1 MTProto: Trying to copy authorization from dc 2 to dc 3 MTProto: Trying to copy authorization from dc 2 to dc 4 ResponseHandler: Parsing updates received via the socket...
После чего можно полноценно использовать все возможности Telegram Core API, например, $messages = $madeline->messages->getHistory().
Данный метод возвращает сообщения из канала в обратном хронологическом порядке, т.е. начиная с самых свежих. Подробнее о параметрах этого метода можно узнать на страницах официальной документации MadelineProto. Заметьте, параметры MadelineProto могут отличаться от параметров официальной документации самого Telegram.