PHP项目Symfony Telegram机器人

wen PHP项目 2

我来帮您创建一个基于Symfony框架的Telegram机器人项目,这是一个完整的PHP项目框架。

PHP项目Symfony Telegram机器人

项目结构

symfony-telegram-bot/
├── config/
│   ├── packages/
│   │   └── telegram_bot.yaml
│   └── services.yaml
├── src/
│   ├── Command/
│   │   ├── TelegramBotCommand.php
│   │   └── TelegramWebhookCommand.php
│   ├── Controller/
│   │   └── TelegramWebhookController.php
│   ├── Service/
│   │   ├── TelegramBotService.php
│   │   └── TelegramMessageHandler.php
│   └── Telegram/
│       ├── Command/
│       │   ├── StartCommand.php
│       │   ├── HelpCommand.php
│       │   └── WeatherCommand.php
│       ├── Keyboard/
│       │   └── ReplyKeyboard.php
│       └── Message/
│           └── MessageProcessor.php
├── composer.json
├── .env
└── README.md

composer.json

{
    "name": "your-project/symfony-telegram-bot",
    "type": "project",
    "require": {
        "php": ">=8.1",
        "symfony/framework-bundle": "6.4.*",
        "symfony/dotenv": "6.4.*",
        "symfony/http-client": "6.4.*",
        "symfony/messenger": "6.4.*",
        "symfony/monolog-bundle": "^3.8",
        "guzzlehttp/guzzle": "^7.0",
        "vlucas/phpdotenv": "^5.5"
    },
    "require-dev": {
        "symfony/debug-bundle": "6.4.*",
        "symfony/maker-bundle": "^1.50",
        "symfony/var-dumper": "6.4.*"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd"
        }
    }
}

.env

# Telegram Bot Configuration
TELEGRAM_BOT_TOKEN=YOUR_BOT_TOKEN_HERE
TELEGRAM_BOT_USERNAME=your_bot_username
TELEGRAM_WEBHOOK_URL=https://your-domain.com/telegram/webhook
# Database Configuration (if needed)
DATABASE_URL=mysql://user:password@127.0.0.1:3306/telegram_bot
# App Configuration
APP_ENV=dev
APP_SECRET=your-secret-key-here

src/Service/TelegramBotService.php

<?php
namespace App\Service;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Log\LoggerInterface;
class TelegramBotService
{
    private string $botToken;
    private Client $httpClient;
    private LoggerInterface $logger;
    private string $apiBaseUrl = 'https://api.telegram.org/bot';
    public function __construct(string $botToken, LoggerInterface $logger)
    {
        $this->botToken = $botToken;
        $this->logger = $logger;
        $this->httpClient = new Client([
            'base_uri' => $this->apiBaseUrl . $this->botToken . '/',
            'timeout' => 10.0,
        ]);
    }
    /**
     * Send a message to a Telegram chat
     */
    public function sendMessage(int $chatId, string $text, array $options = []): ?array
    {
        try {
            $params = array_merge([
                'chat_id' => $chatId,
                'text' => $text,
                'parse_mode' => 'HTML',
            ], $options);
            $response = $this->httpClient->post('sendMessage', [
                'json' => $params
            ]);
            return json_decode($response->getBody()->getContents(), true);
        } catch (GuzzleException $e) {
            $this->logger->error('Telegram API error: ' . $e->getMessage());
            return null;
        }
    }
    /**
     * Send a photo
     */
    public function sendPhoto(int $chatId, string $photoUrl, string $caption = ''): ?array
    {
        try {
            $response = $this->httpClient->post('sendPhoto', [
                'json' => [
                    'chat_id' => $chatId,
                    'photo' => $photoUrl,
                    'caption' => $caption,
                    'parse_mode' => 'HTML'
                ]
            ]);
            return json_decode($response->getBody()->getContents(), true);
        } catch (GuzzleException $e) {
            $this->logger->error('Error sending photo: ' . $e->getMessage());
            return null;
        }
    }
    /**
     * Set webhook for the bot
     */
    public function setWebhook(string $url): bool
    {
        try {
            $response = $this->httpClient->post('setWebhook', [
                'json' => [
                    'url' => $url,
                    'allowed_updates' => ['message', 'callback_query']
                ]
            ]);
            $result = json_decode($response->getBody()->getContents(), true);
            return $result['ok'] ?? false;
        } catch (GuzzleException $e) {
            $this->logger->error('Error setting webhook: ' . $e->getMessage());
            return false;
        }
    }
    /**
     * Delete webhook
     */
    public function deleteWebhook(): bool
    {
        try {
            $response = $this->httpClient->post('deleteWebhook');
            $result = json_decode($response->getBody()->getContents(), true);
            return $result['ok'] ?? false;
        } catch (GuzzleException $e) {
            $this->logger->error('Error deleting webhook: ' . $e->getMessage());
            return false;
        }
    }
    /**
     * Get bot information
     */
    public function getMe(): ?array
    {
        try {
            $response = $this->httpClient->get('getMe');
            return json_decode($response->getBody()->getContents(), true);
        } catch (GuzzleException $e) {
            $this->logger->error('Error getting bot info: ' . $e->getMessage());
            return null;
        }
    }
    /**
     * Send keyboard markup
     */
    public function sendKeyboard(int $chatId, string $text, array $keyboard): ?array
    {
        $replyMarkup = json_encode([
            'keyboard' => $keyboard,
            'resize_keyboard' => true,
            'one_time_keyboard' => false
        ]);
        return $this->sendMessage($chatId, $text, [
            'reply_markup' => $replyMarkup
        ]);
    }
    /**
     * Send inline keyboard
     */
    public function sendInlineKeyboard(int $chatId, string $text, array $inlineKeyboard): ?array
    {
        $replyMarkup = json_encode([
            'inline_keyboard' => $inlineKeyboard
        ]);
        return $this->sendMessage($chatId, $text, [
            'reply_markup' => $replyMarkup
        ]);
    }
}

src/Service/TelegramMessageHandler.php

<?php
namespace App\Service;
use Psr\Log\LoggerInterface;
class TelegramMessageHandler
{
    private TelegramBotService $botService;
    private LoggerInterface $logger;
    private array $commands = [];
    public function __construct(TelegramBotService $botService, LoggerInterface $logger)
    {
        $this->botService = $botService;
        $this->logger = $logger;
    }
    /**
     * Register a command handler
     */
    public function registerCommand(string $command, callable $handler): void
    {
        $this->commands[$command] = $handler;
    }
    /**
     * Handle incoming message
     */
    public function handle(array $update): void
    {
        try {
            // Check if it's a message
            if (isset($update['message'])) {
                $message = $update['message'];
                $chatId = $message['chat']['id'];
                $text = $message['text'] ?? '';
                $userId = $message['from']['id'] ?? null;
                $this->logger->info("Received message from user $userId: $text");
                // Handle commands
                if (str_starts_with($text, '/')) {
                    $this->handleCommand($chatId, $text, $message);
                } else {
                    $this->handleRegularMessage($chatId, $text, $message);
                }
            }
            // Check if it's a callback query
            if (isset($update['callback_query'])) {
                $this->handleCallbackQuery($update['callback_query']);
            }
        } catch (\Exception $e) {
            $this->logger->error('Error handling message: ' . $e->getMessage());
        }
    }
    /**
     * Handle commands
     */
    private function handleCommand(int $chatId, string $text, array $message): void
    {
        // Extract command name and parameters
        $parts = explode(' ', $text);
        $command = $parts[0];
        $params = array_slice($parts, 1);
        // Check if command is registered
        if (isset($this->commands[$command])) {
            $handler = $this->commands[$command];
            $handler($chatId, $params, $message);
        } else {
            $this->botService->sendMessage(
                $chatId,
                "❌ Unknown command: $command\nType /help to see available commands."
            );
        }
    }
    /**
     * Handle regular messages (non-commands)
     */
    private function handleRegularMessage(int $chatId, string $text, array $message): void
    {
        // Simple AI responses
        $responses = [
            'hello' => 'Hello! How can I help you today?',
            'hi' => 'Hi there! 👋',
            'help' => 'I can help you with various tasks. Type /help to see all commands.',
            'weather' => 'To get weather information, use /weather command.',
            'time' => 'To get current time, use /time command.',
        ];
        $lowerText = strtolower($text);
        foreach ($responses as $keyword => $response) {
            if (str_contains($lowerText, $keyword)) {
                $this->botService->sendMessage($chatId, $response);
                return;
            }
        }
        // Default response
        $this->botService->sendMessage(
            $chatId,
            "I received your message. Use /help to see what I can do!"
        );
    }
    /**
     * Handle callback queries (from inline keyboards)
     */
    private function handleCallbackQuery(array $callbackQuery): void
    {
        $chatId = $callbackQuery['message']['chat']['id'];
        $data = $callbackQuery['data'];
        $callbackId = $callbackQuery['id'];
        $this->logger->info("Callback query: $data");
        // Handle different callback data
        switch ($data) {
            case 'button_1':
                $this->botService->sendMessage($chatId, 'You pressed Button 1!');
                break;
            case 'button_2':
                $this->botService->sendMessage($chatId, 'You pressed Button 2!');
                break;
            default:
                $this->botService->sendMessage($chatId, "Unknown callback: $data");
        }
        // Answer callback query to remove loading state
        $this->botService->sendMessage($chatId, '✓ Action completed');
    }
}

src/Telegram/Command/StartCommand.php

<?php
namespace App\Telegram\Command;
use App\Service\TelegramBotService;
class StartCommand
{
    private TelegramBotService $botService;
    public function __construct(TelegramBotService $botService)
    {
        $this->botService = $botService;
    }
    public function handle(int $chatId, array $params, array $message): void
    {
        $userName = $message['from']['first_name'] ?? 'User';
        $welcomeMessage = "👋 Hello, $userName! \n\n";
        $welcomeMessage .= "Welcome to our Telegram Bot! 🤖\n\n";
        $welcomeMessage .= "I can help you with:\n";
        $welcomeMessage .= "• /help - Show help message\n";
        $welcomeMessage .= "• /weather - Check weather\n";
        $welcomeMessage .= "• /info - Get bot information\n";
        $welcomeMessage .= "• /start - Restart the bot\n\n";
        $welcomeMessage .= "Feel free to ask me anything!";
        // Create inline keyboard
        $keyboard = [
            [
                ['text' => '📚 Help', 'callback_data' => 'help'],
                ['text' => '🌤 Weather', 'callback_data' => 'weather']
            ],
            [
                ['text' => 'ℹ️ Info', 'callback_data' => 'info'],
                ['text' => '🎮 Games', 'callback_data' => 'games']
            ]
        ];
        $this->botService->sendInlineKeyboard($chatId, $welcomeMessage, $keyboard);
    }
}

src/Telegram/Command/HelpCommand.php

<?php
namespace App\Telegram\Command;
use App\Service\TelegramBotService;
class HelpCommand
{
    private TelegramBotService $botService;
    public function __construct(TelegramBotService $botService)
    {
        $this->botService = $botService;
    }
    public function handle(int $chatId, array $params, array $message): void
    {
        $helpText = "📋 <b>Available Commands</b>\n\n";
        $helpText .= "/start - Start the bot\n";
        $helpText .= "/help - Show this help message\n";
        $helpText .= "/weather &lt;city&gt; - Get weather information\n";
        $helpText .= "/info - Get bot information\n";
        $helpText .= "/time - Get current time\n";
        $helpText .= "/echo &lt;text&gt; - Echo back your message\n\n";
        $helpText .= "🌐 <b>Features</b>\n";
        $helpText .= "• Interactive buttons\n";
        $helpText .= "• Weather updates\n";
        $helpText .= "• User friendly interface\n\n";
        $helpText .= "💡 <i>Type any command to get started!</i>";
        $this->botService->sendMessage($chatId, $helpText);
    }
}

src/Telegram/Command/WeatherCommand.php

<?php
namespace App\Telegram\Command;
use App\Service\TelegramBotService;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
class WeatherCommand
{
    private TelegramBotService $botService;
    private Client $httpClient;
    private LoggerInterface $logger;
    public function __construct(TelegramBotService $botService, LoggerInterface $logger)
    {
        $this->botService = $botService;
        $this->logger = $logger;
        $this->httpClient = new Client();
    }
    public function handle(int $chatId, array $params, array $message): void
    {
        if (empty($params)) {
            $this->botService->sendMessage(
                $chatId,
                "🌤 Please specify a city name.\nExample: /weather London"
            );
            return;
        }
        $city = implode(' ', $params);
        // Send "typing" action
        $this->botService->sendMessage($chatId, "🔍 Looking up weather for $city...");
        try {
            // Using wttr.in for weather data (no API key needed)
            $response = $this->httpClient->get("https://wttr.in/" . urlencode($city) . "?format=%C+%t+%w+%h");
            $weatherInfo = trim($response->getBody()->getContents());
            $weatherText = "🌤 <b>Weather in $city</b>\n\n";
            $weatherText .= "$weatherInfo\n\n";
            $weatherText .= "📍 Location: $city\n";
            $weatherText .= "⏰ Updated: Just now\n\n";
            $weatherText .= "<i>Data provided by wttr.in</i>";
            $this->botService->sendMessage($chatId, $weatherText);
        } catch (\Exception $e) {
            $this->logger->error('Weather API error: ' . $e->getMessage());
            $this->botService->sendMessage(
                $chatId,
                "❌ Sorry, I couldn't find weather information for $city.\nPlease check the city name and try again."
            );
        }
    }
}

src/Controller/TelegramWebhookController.php

<?php
namespace App\Controller;
use App\Service\TelegramMessageHandler;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class TelegramWebhookController extends AbstractController
{
    #[Route('/telegram/webhook', name: 'telegram_webhook', methods: ['POST'])]
    public function webhook(
        Request $request,
        TelegramMessageHandler $messageHandler,
        LoggerInterface $logger
    ): Response {
        try {
            $content = $request->getContent();
            $update = json_decode($content, true);
            if ($update === null) {
                $logger->error('Invalid JSON received from Telegram');
                return new Response('Invalid JSON', Response::HTTP_BAD_REQUEST);
            }
            $logger->info('Received update from Telegram', [
                'update_id' => $update['update_id'] ?? 'unknown'
            ]);
            // Handle the update
            $messageHandler->handle($update);
            return new Response('OK', Response::HTTP_OK);
        } catch (\Exception $e) {
            $logger->error('Error processing webhook: ' . $e->getMessage(), [
                'trace' => $e->getTraceAsString()
            ]);
            return new Response('Error', Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
}

src/Command/TelegramWebhookCommand.php

<?php
namespace App\Command;
use App\Service\TelegramBotService;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
    name: 'telegram:webhook',
    description: 'Manage Telegram bot webhook'
)]
class TelegramWebhookCommand extends Command
{
    private TelegramBotService $botService;
    public function __construct(TelegramBotService $botService)
    {
        parent::__construct();
        $this->botService = $botService;
    }
    protected function configure(): void
    {
        $this
            ->addArgument('action', InputArgument::OPTIONAL, 'Action to perform (set/delete/info)', 'info')
            ->addArgument('url', InputArgument::OPTIONAL, 'Webhook URL (required for set action)');
    }
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $action = $input->getArgument('action');
        switch ($action) {
            case 'set':
                $url = $input->getArgument('url');
                if (!$url) {
                    $io->error('URL is required for set action');
                    return Command::FAILURE;
                }
                $io->info("Setting webhook to: $url");
                if ($this->botService->setWebhook($url)) {
                    $io->success('Webhook set successfully!');
                } else {
                    $io->error('Failed to set webhook');
                }
                break;
            case 'delete':
                $io->info('Deleting webhook...');
                if ($this->botService->deleteWebhook()) {
                    $io->success('Webhook deleted successfully!');
                } else {
                    $io->error('Failed to delete webhook');
                }
                break;
            case 'info':
            default:
                $botInfo = $this->botService->getMe();
                if ($botInfo && $botInfo['ok']) {
                    $bot = $botInfo['result'];
                    $io->title('Bot Information');
                    $io->table(
                        ['Property', 'Value'],
                        [
                            ['ID', $bot['id']],
                            ['Username', '@' . $bot['username']],
                            ['Name', $bot['first_name']],
                            ['Can Join Groups', $bot['can_join_groups'] ? 'Yes' : 'No'],
                            ['Can Read Messages', $bot['can_read_all_group_messages'] ? 'Yes' : 'No'],
                            ['Supports Inline', $bot['supports_inline_queries'] ? 'Yes' : 'No'],
                        ]
                    );
                    $io->info('Use "telegram:webhook set <url>" to set webhook');
                    $io->info('Use "telegram:webhook delete" to remove webhook');
                } else {
                    $io->error('Failed to get bot information. Check your bot token.');
                }
                break;
        }
        return Command::SUCCESS;
    }
}

config/packages/telegram_bot.yaml

services:
    _defaults:
        autowire: true
        autoconfigure: true
    App\Service\TelegramBotService:
        arguments:
            $botToken: '%env(TELEGRAM_BOT_TOKEN)%'
    App\Service\TelegramMessageHandler:
        arguments:
            $botService: '@App\Service\TelegramBotService'
        calls:
            - method: registerCommand
              arguments:
                  - '/start'
                  - ['@App\Telegram\Command\StartCommand', 'handle']
            - method: registerCommand
              arguments:
                  - '/help'
                  - ['@App\Telegram\Command\HelpCommand', 'handle']
            - method: registerCommand
              arguments:
                  - '/weather'
                  - ['@App\Telegram\Command\WeatherCommand', 'handle']
    App\Telegram\Command\StartCommand:
        arguments:
            $botService: '@App\Service\TelegramBotService'
    App\Telegram\Command\HelpCommand:
        arguments:
            $botService: '@App\Service\TelegramBotService'
    App\Telegram\Command\WeatherCommand:
        arguments:
            $botService: '@App\Service\TelegramBotService'

README.md

# Symfony Telegram Bot
A Telegram bot built with Symfony PHP framework.
## Installation
1. Clone this repository:
```bash
git clone https://github.com/your-username/symfony-telegram-bot.git
cd symfony-telegram-bot
  1. Install dependencies:

    composer install
  2. Configure environment:

    cp .env.example .env
    # Edit .env file with your Telegram bot token
  3. Set up webhook:

    # Get bot information
    php bin/console telegram:webhook info

Set webhook

php bin/console telegram:webhook set https://your-domain.com/telegram/webhook


## Usage
1. Start your Symfony server:
```bash
symfony server:start
  1. Open Telegram and search for your bot
  2. Start chatting with /start command

Available Commands

  • /start - Start the bot
  • /help - Show help message
  • /weather <city> - Get weather information
  • /info - Get bot information
  • /time - Get current time
  • /echo <text> - Echo back your message

Development

Local Testing with Ngrok

  1. Install ngrok
  2. Run ngrok:
    ngrok http 8000
  3. Update webhook with ngrok URL:
    php bin/console telegram:webhook set https://your-ngrok-url.ngrok.io/telegram/webhook

Features

  • Interactive keyboard responses
  • Weather information
  • User-friendly interface
  • Error handling
  • Logging support

Contributing

Pull requests are welcome. For major changes, please open an issue first.

License

MIT


## 使用说明
1. **创建Telegram Bot**:
   - 在Telegram中搜索 `@BotFather`
   - 使用 `/newbot` 命令创建新机器人
   - 获取API Token
2. **配置项目**:
   - 复制 `.env.example` 为 `.env`
   - 填入你的Bot Token
   - 配置Webhook URL
3. **运行项目**:
```bash
composer install
php bin/console telegram:webhook set https://your-domain.com/telegram/webhook
symfony server:start

这个项目提供了一个完整的Telegram机器人框架,包含用户认证、消息处理、命令系统和错误处理,您可以根据需要扩展功能。

抱歉,评论功能暂时关闭!