token = $_ENV['TELEGRAM_BOT_TOKEN'] ?? getenv('TELEGRAM_BOT_TOKEN');
}
public function sendMessage(int $chatId, string $text, ?array $keyboard = null, ?string $parseMode = 'HTML'): array
{
$data = [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => $parseMode
];
if ($keyboard) {
$data['reply_markup'] = json_encode($keyboard);
}
return $this->request('sendMessage', $data);
}
public function editMessageText(int $chatId, int $messageId, string $text, ?array $keyboard = null, ?string $parseMode = 'HTML'): array
{
$data = [
'chat_id' => $chatId,
'message_id' => $messageId,
'text' => $text,
'parse_mode' => $parseMode
];
if ($keyboard) {
$data['reply_markup'] = json_encode($keyboard);
}
return $this->request('editMessageText', $data);
}
public function sendPhoto(int $chatId, string $photo, ?string $caption = null, ?array $keyboard = null): array
{
$data = [
'chat_id' => $chatId,
'photo' => $photo
];
if ($caption) {
$data['caption'] = $caption;
$data['parse_mode'] = 'HTML';
}
if ($keyboard) {
$data['reply_markup'] = json_encode($keyboard);
}
return $this->request('sendPhoto', $data);
}
public function sendMediaGroup(int $chatId, array $photos, ?string $caption = null): array
{
$media = [];
foreach ($photos as $index => $photo) {
$media[] = [
'type' => 'photo',
'media' => $photo,
'caption' => $index === 0 ? $caption : null,
'parse_mode' => 'HTML'
];
}
$data = [
'chat_id' => $chatId,
'media' => json_encode($media)
];
return $this->request('sendMediaGroup', $data);
}
public function deleteMessage(int $chatId, int $messageId): array
{
return $this->request('deleteMessage', [
'chat_id' => $chatId,
'message_id' => $messageId
]);
}
public function answerCallbackQuery(string $callbackQueryId, string $text, ?bool $showAlert = false)
{
return $this->request('answerCallbackQuery', [
'callback_query_id' => $callbackQueryId,
'text' => $text,
'show_alert' => $showAlert
]);
}
public function getChat(int $chatId): array
{
return $this->request('getChat', ['chat_id' => $chatId]);
}
public function getChatAdministrators(int $chatId): array
{
return $this->request('getChatAdministrators', ['chat_id' => $chatId]);
}
public function leaveChat(int $chatId): array
{
return $this->request('leaveChat', ['chat_id' => $chatId]);
}
public function setChatMenuButton(?int $chatId = null, ?array $menuButton = null): array
{
$data = [];
if ($chatId !== null) {
$data['chat_id'] = $chatId;
}
if ($menuButton !== null) {
$data['menu_button'] = json_encode($menuButton);
}
return $this->request('setChatMenuButton', $data);
}
public function createInlineKeyboard(array $buttons): array
{
$keyboard = ['inline_keyboard' => []];
foreach ($buttons as $button) {
$buttonData = ['text' => $button['text']];
if (isset($button['callback_data'])) {
$buttonData['callback_data'] = $button['callback_data'];
} elseif (isset($button['url'])) {
$buttonData['url'] = $button['url'];
}
$keyboard['inline_keyboard'][] = [$buttonData];
}
return $keyboard;
}
public function createReplyKeyboard(array $buttons, ?bool $resize = true, ?bool $oneTime = false): array
{
$keyboard = [
'keyboard' => [],
'resize_keyboard' => $resize,
'one_time_keyboard' => $oneTime
];
foreach ($buttons as $row) {
$rowButtons = [];
foreach ($row as $button) {
$rowButtons[] = [
'text' => $button['text'],
'request_contact' => $button['request_contact'] ?? false,
'request_location' => $button['request_location'] ?? false
];
}
$keyboard['keyboard'][] = $rowButtons;
}
return $keyboard;
}
public function removeKeyboard(): array
{
return ['remove_keyboard' => true];
}
private function request(string $method, array $data)
{
$url = $this->baseUrl . $this->token . '/' . $method;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// answerCallbackQuery returns true (boolean) on success
if ($response === 'true') {
return true;
}
$result = json_decode($response, true);
if (!$result || !($result['ok'] ?? false)) {
throw new \Exception("Telegram API Error: " . ($result['description'] ?? 'Unknown error'));
}
return $result['result'];
}
/**
* Parsear HTML y dividirlo en segmentos manteniendo el orden
* Retorna array de ['type' => 'text|image', 'content' => '...', 'src' => '...']
*/
public function parseContent(string $html): array
{
$segments = [];
// Usar regex para encontrar todas las etiquetas
$pattern = '/
]+src=["\']([^"\']+)["\'][^>]*>/i';
$parts = preg_split($pattern, $html, -1, PREG_SPLIT_DELIM_CAPTURE);
// El array parts alterna entre: [texto, src_imagen, texto, src_imagen, texto...]
for ($i = 0; $i < count($parts); $i++) {
if ($i % 2 === 0) {
// Es texto
$text = $this->htmlToPlainText($parts[$i]);
if (!empty(trim($text))) {
$segments[] = [
'type' => 'text',
'content' => $text
];
}
} else {
// Es una imagen (el src capturado)
$segments[] = [
'type' => 'image',
'src' => $parts[$i],
'content' => ''
];
}
}
return $segments;
}
/**
* Enviar contenido con texto e imágenes en el orden correcto
*/
public function sendContentWithOrderedImages(int $chatId, array $segments): void
{
foreach ($segments as $segment) {
if ($segment['type'] === 'text') {
// Enviar texto
if (!empty(trim($segment['content']))) {
$this->sendMessage($chatId, $segment['content']);
}
} elseif ($segment['type'] === 'image') {
$imagePath = $segment['src'];
if (file_exists($imagePath)) {
// Es un archivo local
$this->sendPhoto($chatId, $imagePath);
} elseif (strpos($imagePath, 'http') === 0) {
// Es una URL remota
$this->sendPhoto($chatId, $imagePath);
}
}
}
}
/**
* Convertir HTML a texto plano manteniendo saltos de línea
*/
private function htmlToPlainText(string $html): string
{
// Reemplazar
,
, etc. con saltos de línea
$text = preg_replace('/
/i', "\n", $html);
$text = preg_replace('/<\/p>/i', "\n", $text);
$text = preg_replace('/
]*>/i', '', $text); $text = preg_replace('/