На сайте telegram я наткнулся на ссылку на неофициальный opensource php клиент. Да-да! Можно использовать telegram под php, и там даже есть поддержка звонков! Это чудо называется madelineProto. Оно может подключаться к серверам используя криптографическую магию и отдавать нужные мне данные в виде нормального, человеческого ассоциативного массива.


1. Регистрация своего клиента.

Нам всеже потребуется регистрация и смс авторизация в телеграме…

Если аккаунт в телеграме уже есть, остается зарегистрировать свое приложение/клиент, и получить ключи для доступа к серверам telegram.

Это стандартная процедура, похожая на аналогичную у соц. сетей для доступа к API. Инструкция для создания своих ключей.

После регистрации клиента нам потребуются только «App api_id» и «App api_hash» со страницы my.telegram.org/apps

2. Установка madelineProto.

Для работы требуется php7, но в Readme написано, что есть способ запустить на php5.6.

С запуском на MacOs с php7 из пакета Mamp, и простеньком хостинге за 150 руб в мес проблем не возникло.

Процесс не хитрый: скачать релиз, установить зависимости через composer и можно приступать к настройке.

Для уменьшения размера я удалил лишние зависимости и оставил только danog, paragonie и phpseclib. На работе клиента это никак не сказалось.

3. Настройка madelineProto и первый запуск.

Все примеры по использованию и настройке описаны в репозитории клиента, но я приведу свой код с комментариями.

На этом этапе потребуется авторизовать новое подключение и ввести код верификации, который придет в ранее авторизованный telegram клиент. Запускать код желательно из консоли (но есть и веб режим). Если настраиваете клиент для другого человека, то нельзя пересылать код авторизации через telegram, иначе он будет аннулирован. Но можно пересылать его в виде скриншота или писать текстом.

Количество авторизаций, которые можно запросить, ограничено. Если что-то не срабатывает — не стоит много раз подряд запускать код, иначе Телеграм заблокирует отправку подтверждений на сутки или более.

Я, к сожалению, узнал об этой особенности на своей шкуре. Обычной тех. поддержки у телеграма, кстати, тоже нет, так что в случае блокировки придется ждать 🙂

//мой список настроек минимален, остальные - по умолчанию. Cписок всех значений по умолчанию можно посмотреть в ReadMe клиента на github.
$settings = [
    'app_info' => [ // Эти данные мы получили после регистрации приложения на https://my.telegram.org
        'api_id' => XXXXX,
        'api_hash' => XXXXXXXXXX,
    ],
    'logger' => [ // Вывод сообщений и ошибок
        'logger' => 3, // выводим сообещения через echo
        'logger_level' => 4, // выводим только критические ошибки.
    ],
    //для доступа может потребоваться socks5 прокси
    //если прокси не требуется, то этот блок можно удалить.
    'connection_settings' => [
        'all' => [
            'proxy' => '\SocksProxy',
            'proxy_extra' => [
                'address' => 'xxx.xxx.xxx.xxx',
                'port' => 1234,
                'username' => '',//Можно удалить если логина нет
                'password' => '',//Можно удалить если пароля нет
            ],
        ],
    ],
    'serialization' => [
        'serialization_interval' => 300,
        //Очищать файл сессии от некритичных данных. 
        //Значительно снижает потребление памяти при интенсивном использовании, но может вызывать проблемы
        'cleanup_before_serialization' => true,
    ],
];

$MadelineProto = new \danog\MadelineProto\API('session.madeline', $settings);
$MadelineProto->start();     

В корне проекта будут создан файл «session.madeline», в котором, в бинарном виде, будут храниться данные нашей сессии. При повторном запуске авторизовываться заново не придется. Возобновление сессии работает довольно быстро. У меня на инициализацию клиента уходит около 800 мс на зарубежном сервере.

Для обновления настроек достаточно обновить массив и перезапустить скрипт. Удалять файл сессии не требуется.

4. Получение постов из произвольного открытого telegram канала.

После того как

            
            $data = array(
                    'peer' => '@'.$val['url'], //название_канала, должно начинаться с @, например @breakingmash, все остальные параметры, кроме limit, можно оставить равными 0
                    'offset_id' => $val['offset_id']?:0, 
                    'offset_date' => $val['offset_date']?:0, 
                    'add_offset' => $val['add_offset']?:0, 
                    'limit' => $val['limit']?:10, //Количество постов, которые вернет клиент
                    'max_id' => $val['max_id']?:0, //Максимальный id поста
                    'min_id' => $val['min_id']?:0, //Минимальный id поста - использую для пагинации, при  0 возвращаются последние посты.
                    'hash' => 0
             );

             $response = $MadelineProto->messages->getHistory($data);
             

Так как у меня обновляется много каналов за один раз, то имеет смысл использовать одну и туже сессию, а не тратить по 2 секунды на каждый канал.

После выполнения мы получаем массив с нужным нам количеством сообщений/постов, разбитых по каналам. Так же передаются данные о медиа-вложениях.

Дальше остается сохранить текст поста, при наличии фото/видео получить превью и подпись к медиа файлу и сформировать ссылку для просмотра поста.

4. Получение медиа-вложений.

К счастью, с недавнего времени, telegram внедрил html превью постов, поэтому можно не сохранять на свой сервер бинарные данные, полученные из клиента, а просто взять ссылку на фото и видео, хранящееся на серверах телеграма.

По названию канала и id поста формируем ссылку формата: t.me/НАЗВАНИЕ_КАНАЛА/ID_ПОСТА?embed=1, например t.me/breakingmash/4193?embed=1

Ну а дальше все просто:

private function telegram_media_parse($posts_data, $source){
        include_once(ROOT_DIR.'/libs/phpQuery.php'); //для парсинга html использую очень быструю  и удобную библиотеку phpQuery

        foreach ($posts_data as &$post_data) {
            if (!empty($post_data['media'])){
                $file_contents = self::loader($post_data['post_url'],'site');//Через curl получаем html код страницы поста.
                $document = phpQuery::newDocumentHTML($file_contents); //Формируем dom-дерево из html строки

                $post_data['post_image'] = preg_replace('/[\s\S]*background-image:[ ]*url\(["\']*([\s\S]*[^"\'])["\']*\)[\s\S]*/u','$1',$document->find($source['rules']['post_img_path'])->eq(0)->attr('style')); //адрес изображения хранится в background-image свойстве.
                $post_data['post_description'] = $document->find($source['rules']['post_text_path'])->eq(0)->text(); //Получаем caption медиафайла. 
            }
            unset($post_data['media']);
        }
        unset($post_data);
        
        return $posts_data;
}

На этом парсинг закончен и можно сохранять посты в базу или вывести на странице.

Надеюсь, что мой первый пост будет кому нибудь полезен. Ссылку на свой агрегатор не оставляю, так как не уверен, разрешено ли это.

Источник

By Ruslan Novikov

Интернет-предприниматель. Фулстек разработчик. Маркетолог. Наставник.