MENU

完整的 Telegram类实现 发送信息

April 15, 2025 • 已被 106 位童鞋围观过 • 代码分享

以下是完整的 Telegram 类实现,并附带了多个常见使用场景的示例代码:

<?php
namespace App\Utility;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

final class Telegram {
    private $bot = "";
    private $channel = "";
    private $client;
    private $apiBaseUrl;

    public function __construct() {
        $this->client = new Client([
            'timeout' => 10,
            'http_errors' => false
        ]);
        $this->apiBaseUrl = "https://api.telegram.org/bot" . $this->bot;
    }

    /**
     * 发送富文本消息(可包含文字、链接和格式)
     * 
     * @param string $text 要发送的HTML格式文本
     * @param array|null $inlineKeyboard 可选的内联键盘配置
     * @return array|false 成功返回响应数组,失败返回false
     */
    public function sendText(string $text, array $inlineKeyboard = null) {
        $postData = [
            "chat_id" => $this->channel,
            "text" => $text,
            "parse_mode" => "HTML",  // 支持HTML格式
            "disable_web_page_preview" => false  // 允许显示链接预览
        ];
  
        // 添加内联键盘
        if ($inlineKeyboard) {
            $postData['reply_markup'] = [
                'inline_keyboard' => $inlineKeyboard
            ];
        }
  
        return $this->jsonPost("/sendMessage", $postData);
    }

    /**
     * 发送图片,可附带文字和链接
     * 
     * @param string $imageUrl 图片URL或本地文件路径
     * @param string $caption 图片说明文字(支持HTML格式、链接)
     * @param array|null $inlineKeyboard 可选的内联键盘配置
     * @return array|false 成功返回响应数组,失败返回false
     */
    public function sendPhoto(string $imageUrl, string $caption = '', array $inlineKeyboard = null) {
        $postData = [
            "chat_id" => $this->channel,
            "caption" => $caption,
            "parse_mode" => "HTML"  // 支持HTML格式
        ];
  
        // 添加内联键盘
        if ($inlineKeyboard) {
            $postData['reply_markup'] = [
                'inline_keyboard' => $inlineKeyboard
            ];
        }
  
        // 判断是URL还是本地文件
        if (filter_var($imageUrl, FILTER_VALIDATE_URL)) {
            $postData["photo"] = $imageUrl;
            return $this->jsonPost("/sendPhoto", $postData);
        } else {
            // 本地文件需要使用multipart/form-data
            $multipart = [
                [
                    'name' => 'chat_id',
                    'contents' => $this->channel
                ],
                [
                    'name' => 'caption',
                    'contents' => $caption
                ],
                [
                    'name' => 'parse_mode',
                    'contents' => 'HTML'
                ],
                [
                    'name' => 'photo',
                    'contents' => fopen($imageUrl, 'r'),
                    'filename' => basename($imageUrl)
                ]
            ];
      
            // 添加内联键盘到multipart请求
            if ($inlineKeyboard) {
                $multipart[] = [
                    'name' => 'reply_markup',
                    'contents' => json_encode(['inline_keyboard' => $inlineKeyboard])
                ];
            }
      
            return $this->multipartPost("/sendPhoto", $multipart);
        }
    }

    /**
     * 发送媒体组(多图片、视频等)
     * 
     * @param array $mediaItems 媒体项目数组
     * @param string $caption 可选的共享说明文字
     * @return array|false 成功返回响应数组,失败返回false
     */
    public function sendMediaGroup(array $mediaItems, string $caption = '') {
        $media = [];
        $files = [];
        $fileIndex = 0;
  
        foreach ($mediaItems as $index => $item) {
            $mediaItem = [
                'type' => $item['type'] ?? 'photo', // 默认为图片
                'media' => '',
            ];
      
            if (!empty($caption) && $index === 0) {
                $mediaItem['caption'] = $caption;
                $mediaItem['parse_mode'] = 'HTML';
            }
      
            // 处理媒体文件
            if (isset($item['media'])) {
                // URL类型
                if (filter_var($item['media'], FILTER_VALIDATE_URL)) {
                    $mediaItem['media'] = $item['media'];
                } 
                // 本地文件
                else if (file_exists($item['media'])) {
                    $attachName = "file{$fileIndex}";
                    $mediaItem['media'] = "attach://{$attachName}";
                    $files[] = [
                        'name' => $attachName,
                        'contents' => fopen($item['media'], 'r'),
                        'filename' => basename($item['media'])
                    ];
                    $fileIndex++;
                }
            }
      
            $media[] = $mediaItem;
        }
  
        $multipart = [
            [
                'name' => 'chat_id',
                'contents' => $this->channel
            ],
            [
                'name' => 'media',
                'contents' => json_encode($media)
            ]
        ];
  
        // 添加本地文件
        if (!empty($files)) {
            $multipart = array_merge($multipart, $files);
        }
  
        return $this->multipartPost("/sendMediaGroup", $multipart);
    }

    /**
     * 多功能推送方法 - 支持同时发送文字、图片和链接
     * 
     * @param array|string $content 要发送的内容
     * @return array|false 成功返回响应数组,失败返回false
     */
    public function push($content) {
        // 如果是字符串,转换为数组格式以统一处理
        if (is_string($content)) {
            $content = ['text' => $content];
        }
  
        // 提取内联键盘配置(如果有)
        $inlineKeyboard = null;
        if (isset($content['inline_keyboard'])) {
            $inlineKeyboard = $content['inline_keyboard'];
        } elseif (isset($content['reply_markup']) && isset($content['reply_markup']['inline_keyboard'])) {
            $inlineKeyboard = $content['reply_markup']['inline_keyboard'];
        }
  
        // 场景1: 有多张图片/视频 - 使用sendMediaGroup
        if (isset($content['media']) && is_array($content['media']) && count($content['media']) > 1) {
            $caption = $content['text'] ?? '';
            return $this->sendMediaGroup($content['media'], $caption);
        }
  
        // 场景2: 单张图片+文字 - 使用sendPhoto
        if (isset($content['image']) || (isset($content['media']) && is_array($content['media']) && count($content['media']) == 1)) {
            $imageUrl = $content['image'] ?? $content['media'][0]['media'];
            $caption = $content['text'] ?? '';
            return $this->sendPhoto($imageUrl, $caption, $inlineKeyboard);
        }
  
        // 场景3: 纯文本+链接 - 使用sendText
        $message = '';
  
        // 添加文本内容
        if (isset($content['text'])) {
            $message .= $content['text'];
        }
  
        // 添加链接
        if (isset($content['links']) && is_array($content['links'])) {
            if (!empty($message)) {
                $message .= "\n\n";
            }
      
            foreach ($content['links'] as $link) {
                $title = $link['title'] ?? $link['url'];
                $message .= "<a href=\"{$link['url']}\">{$title}</a>\n";
            }
        } else if (isset($content['link'])) {
            if (!empty($message)) {
                $message .= "\n\n";
            }
            $title = $content['link_title'] ?? $content['link'];
            $message .= "<a href=\"{$content['link']}\">{$title}</a>";
        }
  
        // 发送最终消息
        return $this->sendText($message, $inlineKeyboard);
    }

    /**
     * 创建内联键盘的便捷方法
     * 
     * @param array $buttons 按钮配置数组
     * @param int $columns 每行按钮数量,默认为1
     * @return array 格式化的内联键盘数组
     */
    public function createInlineKeyboard(array $buttons, int $columns = 1) {
        $keyboard = [];
        $row = [];
  
        foreach ($buttons as $index => $button) {
            // 创建按钮
            $buttonData = [];
      
            // URL类型按钮
            if (isset($button['url'])) {
                $buttonData = [
                    'text' => $button['text'],
                    'url' => $button['url']
                ];
            } 
            // 回调类型按钮
            elseif (isset($button['callback_data'])) {
                $buttonData = [
                    'text' => $button['text'],
                    'callback_data' => $button['callback_data']
                ];
            }
      
            $row[] = $buttonData;
      
            // 当达到指定列数或最后一个按钮时,添加行
            if (count($row) >= $columns || $index == count($buttons) - 1) {
                $keyboard[] = $row;
                $row = [];
            }
        }
  
        return $keyboard;
    }

    /**
     * 发送JSON POST请求
     * 
     * @param string $endpoint API端点
     * @param array $postData 请求数据
     * @return array|false 成功返回响应数组,失败返回false
     */
    private function jsonPost(string $endpoint, array $postData) {
        try {
            $response = $this->client->post($this->apiBaseUrl . $endpoint, [
                'json' => $postData
            ]);
      
            $responseBody = json_decode($response->getBody(), true);
      
            if (isset($responseBody['ok']) && $responseBody['ok'] === true) {
                return $responseBody;
            }
      
            return false;
        } catch (GuzzleException $e) {
            // 记录错误或处理异常
            return false;
        }
    }

    /**
     * 发送multipart/form-data POST请求
     * 
     * @param string $endpoint API端点
     * @param array $multipart 多部分表单数据
     * @return array|false 成功返回响应数组,失败返回false
     */
    private function multipartPost(string $endpoint, array $multipart) {
        try {
            $response = $this->client->post($this->apiBaseUrl . $endpoint, [
                'multipart' => $multipart
            ]);
      
            $responseBody = json_decode($response->getBody(), true);
      
            if (isset($responseBody['ok']) && $responseBody['ok'] === true) {
                return $responseBody;
            }
      
            return false;
        } catch (GuzzleException $e) {
            // 记录错误或处理异常
            return false;
        }
    }
}

使用示例

1. 发送普通文本消息

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 发送简单的纯文本消息
$telegram->push('这是一条简单的文本消息');

// 发送带格式的HTML文本消息
$telegram->push([
    'text' => '<b>重要通知</b>: 系统将于今晚<i>10点</i>进行维护。'
]);

2. 发送带链接的消息

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 方法1: 使用link和link_title字段
$telegram->push([
    'text' => '请查看最新的系统公告:',
    'link' => 'https://example.com/announcements',
    'link_title' => '点击查看详情'
]);

// 方法2: 使用HTML标签直接在文本中嵌入链接
$telegram->push([
    'text' => '请查看最新的<a href="https://example.com/announcements">系统公告</a>'
]);

// 方法3: 发送多个链接
$telegram->push([
    'text' => '以下是重要链接:',
    'links' => [
        ['url' => 'https://example.com/help', 'title' => '帮助中心'],
        ['url' => 'https://example.com/faq', 'title' => '常见问题']
    ]
]);

3. 发送图片

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 发送网络图片
$telegram->push([
    'image' => 'https://example.com/images/photo.jpg',
    'text' => '这是一张网络图片'
]);

// 发送本地图片
$telegram->push([
    'image' => '/path/to/local/image.jpg',
    'text' => '这是一张本地图片'
]);

// 发送带HTML格式说明的图片
$telegram->push([
    'image' => 'https://example.com/images/chart.png',
    'text' => '这是<b>数据图表</b>,显示了<a href="https://example.com/stats">最新统计数据</a>'
]);

4. 发送多张照片

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 发送多张图片
$telegram->push([
    'text' => '这是一组产品图片',
    'media' => [
        ['type' => 'photo', 'media' => 'https://example.com/images/product1.jpg'],
        ['type' => 'photo', 'media' => 'https://example.com/images/product2.jpg'],
        ['type' => 'photo', 'media' => 'https://example.com/images/product3.jpg']
    ]
]);

// 混合网络图片和本地图片
$telegram->push([
    'text' => '这是一组混合图片',
    'media' => [
        ['type' => 'photo', 'media' => 'https://example.com/images/online1.jpg'],
        ['type' => 'photo', 'media' => '/path/to/local/image1.jpg'],
        ['type' => 'photo', 'media' => '/path/to/local/image2.jpg']
    ]
]);

5. 发送带内联键盘按钮的消息

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 方法1: 使用您之前提到的格式
$phone = "123456789";
$config = ['url' => 'https://example.com'];
$markup = "点击更新";

$reply_markup = json_decode('{"type": "InlineKeyboardMarkup","inline_keyboard": [[{"text": "'.$markup.'","url": "'.$config['url'].'/updata/'.$phone.'"}]]}', true);

$telegram->push([
    'text' => '请点击按钮更新您的信息',
    'reply_markup' => $reply_markup
]);

// 方法2: 使用inline_keyboard字段直接定义
$telegram->push([
    'text' => '请选择一个操作:',
    'inline_keyboard' => [
        [
            ['text' => '查看详情', 'url' => 'https://example.com/details'],
            ['text' => '立即购买', 'url' => 'https://example.com/buy']
        ],
        [
            ['text' => '取消', 'callback_data' => 'cancel_action']
        ]
    ]
]);

// 方法3: 使用createInlineKeyboard助手方法
$buttons = [
    ['text' => '按钮1', 'url' => 'https://example.com/btn1'],
    ['text' => '按钮2', 'url' => 'https://example.com/btn2'],
    ['text' => '按钮3', 'url' => 'https://example.com/btn3']
];

// 创建2列的键盘布局
$keyboard = $telegram->createInlineKeyboard($buttons, 2);

$telegram->push([
    'text' => '使用助手方法创建的按钮:',
    'inline_keyboard' => $keyboard
]);

6. 发送图片 + 文字 + 按钮的组合消息

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// 组合所有元素: 图片+文字+链接+按钮
$telegram->push([
    'image' => 'https://example.com/images/product.jpg',
    'text' => '<b>新产品上市!</b>\n\n这是我们最新推出的产品,具有以下特点:\n- 高性能\n- 低功耗\n- 智能操控\n\n详情请访问<a href="https://example.com/product">产品页面</a>',
    'inline_keyboard' => [
        [
            ['text' => '立即购买', 'url' => 'https://example.com/buy'],
            ['text' => '加入购物车', 'callback_data' => 'add_to_cart_123']
        ],
        [
            ['text' => '查看评价', 'url' => 'https://example.com/reviews']
        ]
    ]
]);

7. 智能内容检测示例

<?php
require_once 'vendor/autoload.php';

use App\Utility\Telegram;

$telegram = new Telegram();

// push方法会自动检测内容类型
function sendContent($content) {
    global $telegram;
    return $telegram->push($content);
}

// 自动检测为文本
sendContent('这是一条普通消息');

// 自动检测为图片
sendContent([
    'image' => 'https://example.com/image.jpg'
]);

// 自动检测为带说明的图片
sendContent([
    'image' => 'https://example.com/image.jpg',
    'text' => '图片说明'
]);

// 自动检测为带按钮的消息
sendContent([
    'text' => '带按钮的消息',
    'inline_keyboard' => [
        [
            ['text' => '点击这里', 'url' => 'https://example.com']
        ]
    ]
]);

// 自动检测为多媒体组
sendContent([
    'media' => [
        ['type' => 'photo', 'media' => 'https://example.com/image1.jpg'],
        ['type' => 'photo', 'media' => 'https://example.com/image2.jpg']
    ],
    'text' => '多媒体组说明'
]);

这些示例涵盖了大多数常见的使用场景,从简单的文本消息到复杂的组合内容。可以根据实际需求选择合适的方式发送消息。该类的设计允许灵活组合各种元素,同时保持了简洁的 API 接口。