Last active
October 16, 2025 05:48
-
-
Save saeedvir/b62b48712f95b3e4d10e2ea7537cdfd2 to your computer and use it in GitHub Desktop.
Laravel Send Notification to Telegram or Bale Messenger
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\Services; | |
| use Illuminate\Support\Facades\Http; | |
| use Illuminate\Support\Facades\Log; | |
| /** | |
| * By saeedvir: https://github.com/saeedvir | |
| * Messenger notifier for Telegram & Bale. | |
| * | |
| * 1) Create the Telegram/bale bot | |
| Open Telegram and start a chat with @BotFather. | |
| Send /newbot and follow prompts (name, username). | |
| BotFather will return a Bot Token like 123456:ABC-DEF.... Keep it secret — store it in an env file. | |
| * 2) Create the channel and add the bot | |
| Create a Telegram/Bale channel (private or public). | |
| Add your bot as an administrator of the channel and give it permission to post messages. | |
| * 3) Get the channel chat_id | |
| If the channel is public and has a username @mychannel — you can use @mychannel as the chat_id. | |
| If the channel is private (no username), do this: | |
| Post any message in the channel (you or any admin). | |
| Forward that message to your bot (open message → forward → pick your bot). | |
| Call the Bot API getUpdates to see the forwarded message and retrieve forward_from_chat.id. | |
| Example (paste in browser): | |
| https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates | |
| or | |
| https://tapi.bale.ai/bot<YOUR_TOKEN>/getUpdates | |
| In the JSON you’ll see something like "forward_from_chat": {"id": -1001234567890, ...} — that -1001234567890 is the channel chat_id. | |
| (Alternative: forward to any bot that shows raw updates, or use @RawDataBot — but the getUpdates method above works without third-party tools.) | |
| *4) Create a new instance of MessengerNotifier | |
| $notifier = new MessengerNotifier(null, 'bale'); | |
| $ok = $notifier->info("<b>New Order Received!</b>\nOrder ID: 12345"); | |
| if ($ok) { | |
| $notifier->sendDocument(storage_path('logs/laravel.log'), 'Laravel Log Snapshot'); | |
| return "Sent to messenger!"; | |
| } else { | |
| return "Failed to send."; | |
| } | |
| **/ | |
| class MessengerNotifier | |
| { | |
| protected string $token; | |
| protected string|int $chatId; | |
| protected string $baseUrl; | |
| protected string $messenger; | |
| /** | |
| * Create a new instance of the messenger notifier. | |
| * | |
| * @param string|null $chatId The chat ID to use for sending messages. If null, the value from the config will be used. | |
| * @param string $messenger The messenger to use. Can be either 'telegram' or 'bale'. | |
| * @throws \InvalidArgumentException | |
| */ | |
| public function __construct(?string $chatId = null, string $messenger = 'telegram') | |
| { | |
| $this->messenger = strtolower($messenger); | |
| if ($this->messenger === 'telegram') { | |
| $this->token = config('services.telegram.bot_token', env('TELEGRAM_BOT_TOKEN')); | |
| $this->chatId = $chatId ?? config('services.telegram.chat_id', env('TELEGRAM_CHANNEL_ID')); | |
| $this->baseUrl = "https://api.telegram.org/bot{$this->token}"; | |
| } elseif ($this->messenger === 'bale') { | |
| $this->token = config('services.bale.bot_token', env('BALE_BOT_TOKEN')); | |
| $this->chatId = $chatId ?? config('services.bale.chat_id', env('BALE_CHANNEL_ID')); | |
| $this->baseUrl = "https://tapi.bale.ai/bot{$this->token}"; | |
| } else { | |
| throw new \InvalidArgumentException("Unsupported messenger: {$this->messenger}"); | |
| } | |
| } | |
| /** | |
| * Send a message to the specified chat. | |
| * | |
| * @param string $message | |
| * @param string $parseMode | |
| * @param string|null $chatId | |
| * @return bool | |
| * @throws \Throwable | |
| */ | |
| public function send(string $message, string $parseMode = 'HTML', ?string $chatId = null): bool | |
| { | |
| $url = "{$this->baseUrl}/sendMessage"; | |
| $data = [ | |
| 'chat_id' => $chatId ?? $this->chatId, | |
| 'text' => $message, | |
| 'parse_mode' => $parseMode, | |
| 'disable_web_page_preview' => true, | |
| ]; | |
| try { | |
| $response = Http::timeout(10)->post($url, $data); | |
| return $response->successful(); | |
| } catch (\Throwable $e) { | |
| Log::error("{$this->messenger} send() failed: " . $e->getMessage(), [ | |
| 'url' => $url, | |
| 'data' => $data, | |
| ]); | |
| return false; | |
| } | |
| } | |
| /** severity helpers */ | |
| public function info(string $msg): bool | |
| { | |
| return $this->send("ℹ️ <b>INFO:</b>\n{$msg}"); | |
| } | |
| public function warning(string $msg): bool | |
| { | |
| return $this->send("⚠️ <b>WARNING:</b>\n{$msg}"); | |
| } | |
| public function error(string $msg, \Throwable $e = null): bool | |
| { | |
| $extra = $e ? "\n<code>{$e->getFile()}:{$e->getLine()}</code>" : ''; | |
| return $this->send("❌ <b>ERROR:</b>\n{$msg}{$extra}"); | |
| } | |
| /** batch logs */ | |
| public function batch(array $messages, string $title = 'Batch Report'): bool | |
| { | |
| $text = "<b>{$title}</b>\n\n" . implode("\n", array_map(fn($m) => "• " . $m, $messages)); | |
| return $this->send($text); | |
| } | |
| /** media helpers */ | |
| public function sendPhoto(string $filePath, string $caption = ''): bool | |
| { | |
| return $this->sendMedia('sendPhoto', 'photo', $filePath, $caption); | |
| } | |
| public function sendDocument(string $filePath, string $caption = ''): bool | |
| { | |
| return $this->sendMedia('sendDocument', 'document', $filePath, $caption); | |
| } | |
| /** | |
| * Send media (photo or document) to the messenger | |
| * | |
| * @param string $method Telegram method name (sendPhoto or sendDocument) | |
| * @param string $type Media type (photo or document) | |
| * @param string $filePath File path (local or remote URL) | |
| * @param string $caption Caption for the media | |
| * | |
| * @return bool | |
| */ | |
| protected function sendMedia(string $method, string $type, string $filePath, string $caption = ''): bool | |
| { | |
| $url = "{$this->baseUrl}/{$method}"; | |
| try { | |
| // Case 1: Remote file (URL) | |
| if (preg_match('/^https?:\/\//i', $filePath)) { | |
| $response = Http::timeout(20)->post($url, [ | |
| 'chat_id' => $this->chatId, | |
| $type => $filePath, // direct URL | |
| 'caption' => $caption, | |
| 'parse_mode' => 'HTML', | |
| ]); | |
| return $response->successful(); | |
| } | |
| // Case 2: Local file (upload) | |
| $client = new \GuzzleHttp\Client(['timeout' => 30]); | |
| $response = $client->post($url, [ | |
| 'multipart' => [ | |
| [ | |
| 'name' => 'chat_id', | |
| 'contents' => $this->chatId, | |
| ], | |
| [ | |
| 'name' => $type, // "photo" or "document" | |
| 'contents' => fopen($filePath, 'r'), | |
| 'filename' => basename($filePath), | |
| ], | |
| [ | |
| 'name' => 'caption', | |
| 'contents' => $caption, | |
| ], | |
| ], | |
| ]); | |
| return $response->getStatusCode() === 200; | |
| } catch (\Throwable $e) { | |
| Log::error("{$this->messenger} {$method} failed: " . $e->getMessage(), [ | |
| 'url' => $url, | |
| 'file' => $filePath, | |
| ]); | |
| return false; | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
read more :
https://docs.bale.ai/
https://core.telegram.org/methods