apiToken = $apiToken ?: (defined('TELEGRAM_BOT_TOKEN') ? TELEGRAM_BOT_TOKEN : ''); if (empty($this->apiToken) || $this->apiToken === 'YOUR_TELEGRAM_BOT_TOKEN' || $this->apiToken === 'YOUR_TELEGRAM_BOT_TOKEN_PLACEHOLDER') { // Log or throw an exception if the token is missing or still a placeholder error_log("Telegram API Token is missing or is a placeholder. Please configure it in config/telegram_config.php"); // Depending on strictness, you might throw an exception here: // throw new \Exception("Telegram API Token is not configured."); } $this->apiUrlBase = "https://api.telegram.org/bot{$this->apiToken}/"; } /** * Sends a GET request to the Telegram API. * @param string $method Telegram API method name (e.g., "getMe"). * @param array $params Optional parameters for the method. * @return array|false Decoded JSON response as an associative array, or false on failure. */ private function apiRequest(string $method, array $params = [], string $requestType = 'POST') { if (empty($this->apiToken) || $this->apiToken === 'YOUR_TELEGRAM_BOT_TOKEN' || $this->apiToken === 'YOUR_TELEGRAM_BOT_TOKEN_PLACEHOLDER') { error_log("Cannot make API request: Telegram API Token is not properly configured."); return false; } $url = $this->apiUrlBase.$method; $ch = curl_init(); if ($requestType === 'POST') { curl_setopt($ch, CURLOPT_POST, true); // Send data as JSON payload $jsonData = json_encode($params); curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: '.strlen($jsonData) ]); } else { // GET request if (!empty($params)) { $url .= "?".http_build_query($params); } } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 10 seconds timeout curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // Should be true in production $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { error_log("Telegram API cURL Error for method {$method}: {$curlError}"); return false; } if ($httpCode !== 200) { error_log("Telegram API HTTP Error for method {$method}: Code {$httpCode}. Response: {$response}"); // Attempt to decode response anyway, it might contain error details from Telegram $decodedResponse = json_decode($response, true); return $decodedResponse ?: false; // Return decoded error or false } $decodedResponse = json_decode($response, true); if (json_last_error() !== JSON_ERROR_NONE) { error_log("Telegram API JSON Decode Error for method {$method}: ".json_last_error_msg().". Response: {$response}"); return false; } return $decodedResponse; } /** * A simple method to test connection, like "getMe". * @return array|false Bot information or false on failure. */ public function getMe() { return $this->apiRequest('getMe', [], 'GET'); } /** * Sends a text message to a specific chat. * @param int $chatId Target chat_id. * @param string $text Text of the message to be sent. * @param ?array $replyMarkup Optional. Inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. * @param ?string $parseMode Optional. Mode for parsing entities in the message text. See formatting options for more details. (e.g., MarkdownV2, HTML) * @return array|false API response or false on failure. */ public function sendMessage(int $chatId, string $text, ?array $replyMarkup = null, ?string $parseMode = null) { $params = [ 'chat_id' => $chatId, 'text' => $text ]; if ($replyMarkup !== null) { $params['reply_markup'] = $replyMarkup; } if ($parseMode !== null) { $params['parse_mode'] = $parseMode; } return $this->apiRequest('sendMessage', $params); } /** * Edits text of a message sent by the bot. * @param int $chatId Target chat_id where the message to edit is located. * @param int $messageId Identifier of the message to edit. * @param string $text New text of the message. * @param ?array $replyMarkup Optional. Inline keyboard. * @param ?string $parseMode Optional. Mode for parsing entities in the message text (e.g., MarkdownV2, HTML). * @return array|false API response or false on failure. */ public function editMessageText(int $chatId, int $messageId, string $text, ?array $replyMarkup = null, ?string $parseMode = null) { $params = [ 'chat_id' => $chatId, 'message_id' => $messageId, 'text' => $text ]; if ($replyMarkup !== null) { $params['reply_markup'] = $replyMarkup; } if ($parseMode !== null) { $params['parse_mode'] = $parseMode; } return $this->apiRequest('editMessageText', $params); } /** * Sets the webhook for the bot. * @param string $webhookUrl HTTPS URL to send updates to. * @param ?array $options Optional parameters like certificate, allowed_updates etc. * @return array|false API response or false on failure. */ public function setWebhook(string $webhookUrl, ?array $options = []) { $params = array_merge(['url' => $webhookUrl], $options); return $this->apiRequest('setWebhook', $params); } /** * Deletes the currently set webhook. * @return array|false API response or false on failure. */ public function deleteWebhook() { return $this->apiRequest('deleteWebhook'); } /** * Gets the current webhook information. * @return array|false API response or false on failure. */ public function getWebhookInfo() { return $this->apiRequest('getWebhookInfo', [], 'GET'); } /** * Answers callback query to remove the loading state from inline keyboard buttons. * @param string $callbackQueryId Unique identifier for the callback query to be answered. * @param ?string $text Optional. Text of the notification (max 200 characters). * @param ?bool $showAlert Optional. If true, an alert will be shown instead of a notification. * @return array|false API response or false on failure. */ public function answerCallbackQuery(string $callbackQueryId, ?string $text = null, ?bool $showAlert = null) { $params = [ 'callback_query_id' => $callbackQueryId ]; if ($text !== null) { $params['text'] = $text; } if ($showAlert !== null) { $params['show_alert'] = $showAlert; } return $this->apiRequest('answerCallbackQuery', $params); } }