Содержание статьи
Подготовительные мероприятия
Саму библиотеку MadelineProto устанавливать и обновлять не нужно. Скрипты устроены таким образом, что, если файл библиотеки отсутствует, он будет загружен автоматически. Однако тебе нужно позаботиться о двух вещах:
- Библиотека требует PHP 8.2+, поэтому, если у тебя его нет, придется где‑то раздобыть. Как правило, в последних версиях Ubuntu именно эта версия — скачай и разверни образ последней Ubuntu в виртуальной машине. Если Linux — твоя основная система и переустанавливать тебе ее совсем не хочется, я расскажу, как обновиться.
- Тебе нужно создать свое приложение Telegram. Для этого зарегистрируйся на
my.
, перейди в раздел API development tools и заполни форму. Далее ты получишьtelegram. org api_id
иapi_hash
— сохрани эти значения, они тебе пригодятся.
С регистрацией приложения разберешься сам, там все просто, а вот для обновления PHP до нужной версии тебе надо подключить репозиторий Ondřej Surý PPA. Введи следующие команды:
sudo apt install software-properties-common -y && sudo add-apt-repository ppa:ondrej/php -ysudo apt update && sudo apt upgrade
После этого введи команду установки PHP 8.2:
sudo apt install php8.2
Если у тебя развернут Apache, то установи еще один пакет и перезапусти веб‑сервер:
sudo apt install libapache2-mod-php8.2
sudo systemctl restart apache2
Затем введи команду php
. Ты должен увидеть примерно такой вывод:
PHP 8.2.0 (cli) (built: Dec 10 2022 10:52:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies
Как видишь, ничего сложного.
Авторизация
Напишем простейший сценарий, выполняющий авторизацию пользователя. Для этого нам понадобится Telegram-аккаунт. Можешь тренироваться на своем аккаунте: не беспокойся, ты всегда сможешь поменять пароль и библиотека точно не угонит твою учетку.
<?php$userDir = '';$api_id = 11111; // Добавь сюда api_id$api_hash = 'xxxxxxx'; // Добавь сюда api_hash$phone = 'твой номер телефона'; // Номер телефонаif (!file_exists($userDir . '/madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');}include_once $userDir . '/madeline.php';$settings = (new \danog\MadelineProto\Settings\AppInfo) ->setApiId($api_id) ->setApiHash($api_hash);use danog\MadelineProto\Tools;$MadelineProto = new \danog\MadelineProto\API($userDir . "/session", $settings);$MadelineProto->phoneLogin($phone);$authorization = $MadelineProto->completePhoneLogin(Tools::readLine('Enter the phone code: '));if ($authorization['_'] === 'account.needSignup') { echo "needSignup for $phone"; die();}if ($authorization['_'] === 'account.password') { $authorization = $MadelineProto->complete2falogin(Tools::readLine('Please enter your password (hint '.$authorization['hint'].'): '));}
Теперь разберемся, что мы делаем. Для начала мы задаем необходимые переменные: $api_id
, $api_hash
, $userDir
. С первыми двумя все ясно, а $userDir
ты можешь использовать, если нужно, чтобы madeline.
загружался в какой‑то другой, а не текущий каталог. Если эта переменная содержит пустое значение, madeline.
будет загружаться в текущий каталог и оттуда инклудиться.
Далее мы создаем объект с параметрами. В старых версиях MadelineProto для указания параметров приложений использовался ассоциативный массив, поэтому в интернете ты сможешь найти устаревшие скрипты с использованием этой библиотеки, которые работать не будут как раз по этой самой причине — вместо массива теперь используется объект с параметрами.
Этот объект нужно передать конструктору \
. Первый его параметр — название каталога с сессией входящего в учетку пользователя, а второй — это как раз объект с параметрами. Обрати внимание: мы также используем $userDir
, чтобы каталог с сессией мог находиться в другой папке, если тебе так будет удобнее. Когда ты пишешь Telegram-клиент для одного пользователя, то никаких проблем не возникает. Но если ты планируешь использовать клиент для входа многих пользователей, для поддержания порядка нужно будет держать сессии в разных каталогах — для каждого пользователя придется создавать отдельную папку. Думаю, это понятно.
Метод phoneLogin(
применяется для входа с использованием номера телефона. Укажи номер телефона в том формате, в котором ты указываешь его при входе в Telegram, но без +
.
После этого на твой телефон будет отправлено сообщение с 2FA-кодом. Как правило, оно отправляется уже не по SMS, а в твой Telegram, поэтому открой приложение на телефоне и перейди к чату с названием Telegram.
Если мессенджер на твоем телефоне не установлен, скрипт сообщит об этом и умрет — сработает вызов die(
.
Если для твоего аккаунта установлен пароль, скрипт запросит его. Разумеется, если пароль правильный, то все хорошо, а вот если нет, ты получишь соответствующее сообщение от самой библиотеки. Отдельно обрабатывать исключение неправильно введенного пароля не стану — ты при желании справишься сам.
После входа в аккаунт ты сможешь выполнять всевозможные действия, например запрашивать список контактов, отправлять им сообщения, читать диалоги (чаты), удалять сообщения и диалоги. Библиотека MadelineProto позволяет в этом плане выполнять много различных действий. Для начала попробуем получить список контактов.
Получаем список контактов
Метод getContacts(
получает список контактов из твоего Telegram-аккаунта. Рассмотрим фрагмент кода, выводящий контакты на экран:
$contacts = $MadelineProto->contacts->getContacts();$users = $contacts['users'];foreach ($users as $user) { $firstname = $user['first_name'] ?? ''; $lastname = $user['last_name'] ?? ''; $username = $user['username'] ?? ''; $uphone = $user['phone'] ?? ''; echo "$user[id]\t$firstname\t$lastname\t$username\t$uphone\n";}
Что делать с контактами дальше? Да что угодно. Например, можно сохранить все эти контакты в таблице базы данных, чтобы они никуда не потерялись. А еще можно отправить каждому контакту сообщение.
Сохраняем контакты в базу данных
Не будем изобретать велосипед и установим MySQL для работы с базой данных:
sudo apt install mysql-server mysql-client
Открой клиент MySQL, например так:
mysql -u root
Если ты уже успел задать пароль для пользователя root
, добавь к предыдущей команде параметр -p
, чтобы программа запросила пароль пользователя.
Мы не будем создавать новую базу данных, а станем использовать уже имеющуюся с именем test
:
use test;
Создай таблицу contacts:
CREATE TABLE `contacts` ( `id` bigint NOT NULL AUTO_INCREMENT,
`uid` varchar(50) NOT NULL,
`fname` varchar(200) DEFAULT NULL,
`lname` varchar(200) DEFAULT NULL,
`username` varchar(200) DEFAULT NULL,
`tid` varchar(250) DEFAULT NULL,
`phone` varchar(50) DEFAULT NULL,
PRIMARY KEY(id));
Назначение полей:
-
id
— просто счетчик контакта, он же первичный ключ, чтобы было удобнее работать с таблицей; -
uid
— номер пользователя, которому принадлежит текущая учетная запись (чтобы контакты от разных пользователей не перемешивались); -
fname
— имя контакта (first_name
); -
lname
— фамилия контакта (last_name
); -
username
— имя пользователя контакта; -
tid
— Telegram ID контакта; -
phone
— телефон контакта (если доступен для считывания).
Теперь нужно выйти из MySQL и продолжить кодинг:
exit
Вернемся к нашему фрагменту вывода контактов. Расширим его, добавив код вставки контактов в таблицу contacts
:
$contacts = $MadelineProto->contacts->getContacts();$users = $contacts['users'];foreach ($users as $user) { $firstname = $user['first_name'] ?? ''; $lastname = $user['last_name'] ?? ''; $username = $user['username'] ?? ''; $uphone = $user['phone'] ?? ''; // Настоятельно рекомендуется перед добавлением в БД: $firstname = $mysqli->real_escape_string($firstname); $lastname = $mysqli->real_escape_string($lastname); $username = $mysqli->real_escape_string($username); $uphone = $mysqli->real_escape_string($uphone); echo "$user[id]\t$firstname\t$lastname\t$username\t$uphone\n"; // Проверяем, есть ли контакт в списке $sql = "select * from contacts where uid = "$phone" and tid = $user[id]"; $result = $mysqli->query($sql) or die($mysqli->error); if ($result->num_rows == 0) { // Создаем новый контакт $sql = "insert into contacts values(0, "$phone", "$firstname", "$lastname", "$username", "$user[id]", "$uphone")"; $mysqli->query($sql) or die($mysqli->error); }}
Разумеется, где‑то в скрипте до этого цикла ты должен подключиться к БД, но я все‑таки рассчитываю, что минимальные навыки программирования на PHP у тебя есть:
$mysqli = new mysqli($dbhost,$dbuser,$dbpass,$db);if ($mysqli->connect_errno) { die($mysqli->connect_error);}
Когда ты взглянешь на этот код, станет понятно, зачем мы сохраняли Telegram ID в списке контактов — по нему мы проверяем, добавлен такой контакт для текущего пользователя или нет. А поле uid
мы добавили с одной целью — чтобы наша табличка могла хранить контакты разных аккаунтов: не создавать же для этого отдельные таблицы (хотя при необходимости тоже можно).
Так вот, если для текущего пользователя контакт с заданным Telegram ID не существует в таблице contacts
, мы выполняем SQL-оператор insert
для вставки контакта в таблицу.
Отправляем сообщения пользователям из контакт-списка
Первым делом хочу предостеречь: чтобы твой аккаунт не заблокировали за спам, лучше не устраивать массовую рассылку всем сразу. Для отправки сообщения используется метод sendMessage
, которому нужно передать два параметра — ID пользователя Telegram, которому отправляется сообщение (обрати внимание: не номер телефона), а также само сообщение:
$MadelineProto->messages->sendMessage([ 'peer' => $user['id'], 'message' => "$firstname, с Новым годом!" ]);
Если контактов в твоем списке не очень много, можешь запускать этот код без проблем. А вот если контактов хотя бы несколько десятков, придумай, как изменить алгоритм, чтобы он отправлял сообщения не всем сразу, а поочередно — при первом запуске первым десяти контактам, при втором — следующим десяти и так далее. Делай перерывы между запусками клиента. В общем, все индивидуально: иногда ты можешь отправить тысячу сообщений и тебя не заблокируют за спам, а можешь отправлять с перерывами, осторожничать, и твою учетку заблокируют на пятисотом сообщении.
Собираем все вместе
А вот полный код клиента, получающего список контактов и сохраняющего его в таблицу contacts
:
<?php$userDir = '';$api_id = 11111; // Добавь сюда api_id$api_hash = 'xxxxxxx'; // Добавь сюда api_hash$phone = 'твой номер телефона'; // Номер телефона$dbhost = 'localhost';$dbuser = 'root';$dbpass = '';$db = 'test';// Подключаемся к БД$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $db);if ($mysqli->connect_errno) { die($mysqli->connect_error);}// Загружаем библиотекуif (!file_exists($userDir . '/madeline.php')) { copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');}include_once $userDir . '/madeline.php';// Формируем объект с параметрами$settings = (new \danog\MadelineProto\Settings\AppInfo) ->setApiId($api_id) ->setApiHash($api_hash);use danog\MadelineProto\Tools;$MadelineProto = new \danog\MadelineProto\API($userDir . "/session", $settings);// Вход под именем пользователя$MadelineProto->phoneLogin($phone);$authorization = $MadelineProto->completePhoneLogin(Tools::readLine('Enter the phone code: '));if ($authorization['_'] === 'account.needSignup') { echo "needSignup for $phone"; die();}if ($authorization['_'] === 'account.password') { $authorization = $MadelineProto->complete2falogin(Tools::readLine('Please enter your password (hint '.$authorization['hint'].'): '));}// Получаем список контактов$contacts = $MadelineProto->contacts->getContacts();$users = $contacts['users'];foreach ($users as $user) { $firstname = $user['first_name'] ?? ''; $lastname = $user['last_name'] ?? ''; $username = $user['username'] ?? ''; $uphone = $user['phone'] ?? ''; // Настоятельно рекомендуется перед добавлением в БД: $firstname = $mysqli->real_escape_string($firstname); $lastname = $mysqli->real_escape_string($lastname); $username = $mysqli->real_escape_string($username); $uphone = $mysqli->real_escape_string($uphone); echo "$user[id]\t$firstname\t$lastname\t$username\t$uphone\n"; // Проверяем, есть ли контакт в списке $sql = "select * from contacts where uid = "$phone" and tid = $user[id]"; $result = $mysqli->query($sql) or die($mysqli->error); if ($result->num_rows == 0) { // Создаем новый контакт $sql = "insert into contacts values(0, "$phone", "$firstname", "$lastname", "$username", "$user[id]", "$uphone")"; $mysqli->query($sql) or die($mysqli->error); }}
Итак, наш скрипт вполне работоспособен, но возможностей у него пока еще не слишком много. В следующий раз мы продолжим изучение библиотеки и рассмотрим, как можно получить и сохранить в базу данных диалоги (чаты) из Telegram.
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее