284 lines
7.8 KiB
PHP
284 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* Telegram Bot API client for posting images and text
|
|
* Compatible with PHP 7.2+
|
|
*/
|
|
|
|
class TelegramBot
|
|
{
|
|
private $botToken;
|
|
private $baseUrl = 'https://api.telegram.org/bot';
|
|
private $defaultChannels = [];
|
|
|
|
public function __construct($botToken)
|
|
{
|
|
$this->botToken = $botToken;
|
|
}
|
|
|
|
/**
|
|
* Set default channels for posting
|
|
*
|
|
* @param array $channels Array of channel usernames or IDs
|
|
*/
|
|
public function setDefaultChannels($channels)
|
|
{
|
|
$this->defaultChannels = $channels;
|
|
}
|
|
|
|
/**
|
|
* Make API request to Telegram
|
|
*
|
|
* @param string $method API method
|
|
* @param array $params Parameters
|
|
* @return array Response
|
|
*/
|
|
private function request($method, $params = [])
|
|
{
|
|
$url = $this->baseUrl . $this->botToken . '/' . $method;
|
|
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => $params,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 60,
|
|
CURLOPT_SSL_VERIFYPEER => true,
|
|
]);
|
|
|
|
$response = curl_exec($ch);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error) {
|
|
throw new RuntimeException("Telegram API error: {$error}");
|
|
}
|
|
|
|
$data = json_decode($response, true);
|
|
|
|
if (!$data['ok']) {
|
|
throw new RuntimeException("Telegram API error: " . (isset($data['description']) ? $data['description'] : 'Unknown error'));
|
|
}
|
|
|
|
return isset($data['result']) ? $data['result'] : [];
|
|
}
|
|
|
|
/**
|
|
* Send a text message
|
|
*
|
|
* @param string $chatId Chat/Channel ID or username
|
|
* @param string $text Message text
|
|
* @param string $parseMode Parse mode (HTML, Markdown, MarkdownV2)
|
|
* @param bool $disablePreview Disable link preview
|
|
* @return array Message info
|
|
*/
|
|
public function sendMessage($chatId, $text, $parseMode = 'HTML', $disablePreview = false)
|
|
{
|
|
return $this->request('sendMessage', [
|
|
'chat_id' => $chatId,
|
|
'text' => $text,
|
|
'parse_mode' => $parseMode,
|
|
'disable_web_page_preview' => $disablePreview,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Send a single photo
|
|
*
|
|
* @param string $chatId Chat/Channel ID
|
|
* @param string $photo Photo URL or file_id
|
|
* @param string $caption Photo caption
|
|
* @param string $parseMode Parse mode for caption
|
|
* @return array Message info
|
|
*/
|
|
public function sendPhoto($chatId, $photo, $caption = '', $parseMode = 'HTML')
|
|
{
|
|
$params = [
|
|
'chat_id' => $chatId,
|
|
'photo' => $photo,
|
|
];
|
|
|
|
if ($caption) {
|
|
$params['caption'] = $caption;
|
|
$params['parse_mode'] = $parseMode;
|
|
}
|
|
|
|
return $this->request('sendPhoto', $params);
|
|
}
|
|
|
|
/**
|
|
* Send multiple photos as media group (album)
|
|
*
|
|
* @param string $chatId Chat/Channel ID
|
|
* @param array $photos Array of photo URLs
|
|
* @param string $caption Caption for first photo
|
|
* @param string $parseMode Parse mode
|
|
* @return array Messages info
|
|
*/
|
|
public function sendMediaGroup($chatId, $photos, $caption = '', $parseMode = 'HTML')
|
|
{
|
|
$media = [];
|
|
|
|
foreach ($photos as $index => $photo) {
|
|
$item = [
|
|
'type' => 'photo',
|
|
'media' => $photo,
|
|
];
|
|
|
|
// Caption only on first photo
|
|
if ($index === 0 && $caption) {
|
|
$item['caption'] = $caption;
|
|
$item['parse_mode'] = $parseMode;
|
|
}
|
|
|
|
$media[] = $item;
|
|
}
|
|
|
|
return $this->request('sendMediaGroup', [
|
|
'chat_id' => $chatId,
|
|
'media' => json_encode($media),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Post photos with text to a channel
|
|
* Smart method that chooses best approach based on content
|
|
*
|
|
* @param string $chatId Chat/Channel ID
|
|
* @param array $photos Array of photo URLs
|
|
* @param string $text Post text
|
|
* @param string $parseMode Parse mode
|
|
* @return array Result info
|
|
*/
|
|
public function post($chatId, $photos, $text = '', $parseMode = 'HTML')
|
|
{
|
|
$photoCount = count($photos);
|
|
|
|
// Text only
|
|
if ($photoCount === 0) {
|
|
return ['type' => 'text', 'message' => $this->sendMessage($chatId, $text, $parseMode)];
|
|
}
|
|
|
|
// Single photo
|
|
if ($photoCount === 1) {
|
|
return ['type' => 'photo', 'message' => $this->sendPhoto($chatId, $photos[0], $text, $parseMode)];
|
|
}
|
|
|
|
// Multiple photos (2-10) - use media group
|
|
if ($photoCount <= 10) {
|
|
return ['type' => 'album', 'messages' => $this->sendMediaGroup($chatId, $photos, $text, $parseMode)];
|
|
}
|
|
|
|
// More than 10 photos - split into multiple albums
|
|
$results = [];
|
|
$chunks = array_chunk($photos, 10);
|
|
|
|
foreach ($chunks as $index => $chunk) {
|
|
$caption = ($index === 0) ? $text : '';
|
|
$results[] = $this->sendMediaGroup($chatId, $chunk, $caption, $parseMode);
|
|
}
|
|
|
|
return ['type' => 'multiple_albums', 'messages' => $results];
|
|
}
|
|
|
|
/**
|
|
* Post to multiple channels at once
|
|
*
|
|
* @param array $chatIds Array of Chat/Channel IDs
|
|
* @param array $photos Array of photo URLs
|
|
* @param string $text Post text
|
|
* @param string $parseMode Parse mode
|
|
* @return array Results for each channel
|
|
*/
|
|
public function postToMultiple($chatIds, $photos, $text = '', $parseMode = 'HTML')
|
|
{
|
|
$results = [];
|
|
|
|
foreach ($chatIds as $chatId) {
|
|
try {
|
|
$results[$chatId] = [
|
|
'success' => true,
|
|
'result' => $this->post($chatId, $photos, $text, $parseMode),
|
|
];
|
|
} catch (Exception $e) {
|
|
$results[$chatId] = [
|
|
'success' => false,
|
|
'error' => $e->getMessage(),
|
|
];
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Get bot info
|
|
*
|
|
* @return array Bot info
|
|
*/
|
|
public function getMe()
|
|
{
|
|
return $this->request('getMe');
|
|
}
|
|
|
|
/**
|
|
* Get chat info
|
|
*
|
|
* @param string $chatId Chat/Channel ID
|
|
* @return array Chat info
|
|
*/
|
|
public function getChat($chatId)
|
|
{
|
|
return $this->request('getChat', ['chat_id' => $chatId]);
|
|
}
|
|
|
|
/**
|
|
* Validate that bot has access to a channel
|
|
*
|
|
* @param string $chatId Channel ID or username
|
|
* @return array Validation result
|
|
*/
|
|
public function validateChannel($chatId)
|
|
{
|
|
try {
|
|
$chat = $this->getChat($chatId);
|
|
return [
|
|
'valid' => true,
|
|
'title' => isset($chat['title']) ? $chat['title'] : (isset($chat['username']) ? $chat['username'] : $chatId),
|
|
'type' => $chat['type'],
|
|
];
|
|
} catch (Exception $e) {
|
|
return [
|
|
'valid' => false,
|
|
'error' => $e->getMessage(),
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format text for Telegram HTML mode
|
|
*
|
|
* @param string $text Plain text
|
|
* @return string Escaped HTML
|
|
*/
|
|
public static function escapeHtml($text)
|
|
{
|
|
return htmlspecialchars($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Format text for Telegram MarkdownV2 mode
|
|
*
|
|
* @param string $text Plain text
|
|
* @return string Escaped Markdown
|
|
*/
|
|
public static function escapeMarkdown($text)
|
|
{
|
|
$chars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'];
|
|
foreach ($chars as $char) {
|
|
$text = str_replace($char, '\\' . $char, $text);
|
|
}
|
|
return $text;
|
|
}
|
|
}
|