Sitio Web de Alfonso
10 min de lectura

Enviar Notificaciones en Telegram con Laravel, la Forma Fácil

En este post, te mostraré cómo enviar notificaciones a través de Telegram utilizando Laravel de una forma sencilla y fácil de configurar.

Pasos a Seguir

1. Crear tu Bot en Telegram

  1. Iniciar una Conversación con BotFather: Ve a Telegram y busca a @BotFather.

  2. Crear un Nuevo Bot: Usa el comando /newbot y sigue las instrucciones.

    /newbot
    
  3. Asignar un Nombre: Elige un nombre único para tu bot, como mysuperbot9000_bot. Debe terminar con _bot.

  4. Obtener el Token: Recibirás un token parecido a 1234567890:AAG2eDLduCRjsgHlms1EezWoCqBlpsSJexE. Guárdalo de forma segura, ya que lo necesitarás más adelante.

2. Configurar Laravel

  1. Instalar el Paquete Necesario: Utiliza Composer para instalar "Telegram Notifications Channel for Laravel".

    composer require laravel-notification-channels/telegram
    
  2. Configurar el Token: Añade el token recibido en el archivo config/services.php.

    Nota: Solo sigue estos dos primeros pasos del repositorio. Los demás pasos no son necesarios para nuestro enfoque que utiliza un webhook.

3. Agregar telegram_user_id al Usuario

  1. Editar al migración de usuario o Crear Migración: Agrega la columna telegram_user_id a la tabla de usuarios. Por ejemplo:

    // database/migrations/2014_10_12_000000_create_users_table.php
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            // Resto de las columnas…
            $table->string('telegram_user_id')->nullable();
        });
    }
    

4. Crear el Controlador para el Webhook

  1. Manejo de Mensajes de Telegram: El controlador procesará los mensajes recibidos, extrayendo el ID de usuario de Telegram y asociándolo al usuario correspondiente en tu sistema.
<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;

class TelegramBotWebhookController extends Controller
{
    public function __invoke(Request $request)
    {
        // Extrae el texto del mensaje recibido del webhook de Telegram
        $message = Arr::get($request->all(), 'message.text');

        // Extrae el ID del usuario de Telegram que envía el mensaje
        $telegramUserId = Arr::get($request->all(), 'message.from.id');

        // Extrae el código después del comando '/start' y lo limpia de espacios
        $code = trim(Arr::get(explode('/start', $message ?? ''), 1, ''));

        // Si no hay código o el ID de Telegram es nulo, termina la ejecución
        if (strlen($code) === 0 || $telegramUserId === null) {
            return ['success' => true];
        }

        try {
            // Intenta desencriptar el código recibido
            $decryptedCode = decrypt($code);

            // Verifica si el código desencriptado cumple con el formato 'code:{idusuario}'
            if (preg_match('/^code:(\d+)$/', $decryptedCode, $matches)) {
                // Extrae el ID del usuario del código
                $userId = $matches[1];

                // Busca el usuario en la base de datos usando el ID extraído
                $user = User::find($userId);

                // Si encuentra el usuario, asigna el ID de Telegram y guarda el cambio
                if ($user !== null) {
                    $user->telegram_user_id = $telegramUserId;
                    $user->save();
                }
            }
        } catch (DecryptException $e) {
            // En caso de error en la desencriptación, no realiza ninguna acción
            // (puede agregar un manejo de errores personalizado aquí si lo desea)
        }

        // Devuelve una respuesta de éxito
        return ['success' => true];
    }
}

  1. Ruta en Laravel: Agrega una ruta para el webhook en routes/web.php.
use App\Http\Controllers\TelegramBotWebhookController;
// ...resto de las rutas
Route::post('telegram/webhook', TelegramBotWebhookController::class)->name('telegram.webhook');
  1. Excluir de CSRF: En app/Http/Middleware/VerifyCsrfToken.php, añade la ruta del webhook a las excepciones.
class VerifyCsrfToken extends Middleware
{
    protected $except = [
		// Agregar esto:
        'telegram/webhook',
    ];
}

5. Configurar el Webhook en Telegram

  1. Crear Comando en Laravel: Crea un comando que configure el webhook para tu bot de Telegram.
<?php
<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use NotificationChannels\Telegram\Telegram;

class ConfigureTelegramWebhoook extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'notifications:set-telegram-webhoook';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Set the Telegram webhook for the bot';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $telegram = app(Telegram::class);

		// La clase `Telegram` no tiene un método para configurar el webhook así que solo
		// lo usaremos para obtener la api url y el token
        $apiUri = sprintf('%s/bot%s/%s', $telegram->getApiBaseUri(), $telegram->getToken(), 'setWebhook');

        Http::post($apiUri, [
            'url' => route('telegram.webhook'),
        ]);

        $this->info(sprintf('Telegram webhook configured to %s !', route('telegram.webhook')));
    }
}

Nota: Asegúrate de que la ruta del webhook sea accesible públicamente. Si estás trabajando localmente, herramientas como expose pueden ser útiles.

  1. Corre el comando que recien creaste php artisan notifications:set-telegram-webhoook

  2. Si todo funciona correctamente, deberías poder ver que el telegram_user_id se asigna correctamente en tu base de datos.

6. Probar el Webhook

  1. Generar Código Encriptado: Utiliza php artisan tinker para generar un código encriptado que asocie un ID de usuario con tu bot (en un aplicación real probablemente generaras esté código y se lo darás al usuario para que lo copie).
encrypt('code:1') // Reemplaza '1' con el ID de usuario deseado
  1. Enviar Mensaje al Bot: Usa el código generado para enviar un mensaje a tu bot con el formato /start {codigo_encriptado}.

Ejemplo:

start eyJpdiI6Im1iZzNVZkxUTlMxUGVESlNmdkE0bFE9PSIsInZhbHVlIjoiSDBoVytqOWxuZUNvZjJzaEZEY3paRjJGcmxNYkF2a2x5Q0tteW9vejJ1OD0iLCJtYWMiOiI4ZDU3Mzg0OGQ0YmMwOTM3MzMxMTI1Y2E1OGI2ODFlNTJlM2E0NjdmMzFlMjAwMGVlMDVkZmM5ZDZmYTVhZTJkIiwidGFnIjoiIn0=

7. Enviar una Notificación de Prueba

  1. Crear una Notificación: Usa la siguiente notificación de ejemplo para probar que recibes mensajes.
<?php

declare(strict_types=1);

namespace App\Notifications;

use App\Enums\NotificationChannelEnum;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use NotificationChannels\Telegram\TelegramMessage;

class TestNotification extends Notification implements ShouldQueue
{
    use Queueable;


    /**
     * Get the notification's delivery channels.
     *
     * @return array<int, string>
     */
    public function via(User $notifiable): array
    {
        return ['telegram'];

    }

    public function toTelegram(User $notifiable)
    {
	    // Contenido con formato markdown
        $content = sprintf("*%s*\n\n%s", 'Test notification!', 'If you see this message, it means that your notification was sent successfully.');

        return TelegramMessage::create()
            ->to($notifiable->telegram_user_id)
            ->content($content);
    }
}

  1. Probar la Notificación: En la consola de Laravel, envía una notificación de prueba.

php artisan tinker

User::find(1)->notifyNow(new App\Notifications\TestNotification())

Deberías de recibir una notificación de parte de tu bot en Telegram.