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

项目结构
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 <city> - Get weather information\n";
$helpText .= "/info - Get bot information\n";
$helpText .= "/time - Get current time\n";
$helpText .= "/echo <text> - 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
-
Install dependencies:
composer install
-
Configure environment:
cp .env.example .env # Edit .env file with your Telegram bot token
-
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
- Open Telegram and search for your bot
- 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
- Install ngrok
- Run ngrok:
ngrok http 8000
- 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机器人框架,包含用户认证、消息处理、命令系统和错误处理,您可以根据需要扩展功能。