You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Telegram Bot调用sendMessage时键盘不显示问题求助

Telegram Bot API 键盘不显示问题排查

问题现象

通过PHP向Telegram Bot API发送消息请求,服务器返回发送成功,但聊天窗口仅显示文本Work in progress...,配置的Reply Keyboard或Inline Keyboard完全不显示。

现有参数与代码

打印的参数数组

Array
(
    [chat_id] => (omitted)
    [text] => Work in progress...
    [reply_markup] => Array
        (
            [keyboard] => Array
                (
                    [0] => Array
                        (
                            [0] => Array
                                (
                                    [text] => btn
                                )

                        )

                )

        )

)

请求发送核心代码

//...
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($this->arguments));
//...
$result = curl_exec($ch);

补充完整代码

Message类示例

class Message extends Type {

private $message_id;
/* ... */
/* constructor, getters, setters... */
}

抽象Method类

abstract class Method {
        private $methodUrl = "https://api.telegram.org/bot"; 
        private $method;
        private $arguments = array();
        private $response;

    private function extractFields($container, $refclassmethods = null) {
            $iteratingOnMethod = !is_null($refclassmethods);
            if (is_object($container)) {
                $methods = get_class_methods($container);
                foreach ($methods as $method) {
                    if (is_getter($method) && !is_null($container->$method()) &&
                            (!$iteratingOnMethod || in_array($method, $refclassmethods))
                    ) {
                        $varname = lcfirst(str_replace("get", "", $method));
                        $val = $container->$method();
                        $ret[$varname] = $this->extractFields($val);
                    }
                }
            } elseif (is_array($container)) {
                foreach ($container as $content) {
                    $ret[] = $this->extractFields($content);
                }
            } else /* it is a "final", atomic value (int, string et similia) */ {
                return $container;
            }
            return $ret;
        }
    
    public function execute() {
    
            $refclass = new ReflectionClass($this::class);
            $this->method = $refclass->getShortName();        
            $this->arguments = ($this->extractFields($this, filterRefClassMethods($refclass)));                
            $this->methodUrl .= API_TOKEN . "/" . $this->method . "?";        
            $ch = curl_init();        
            curl_setopt($ch, CURLOPT_URL, $this->methodUrl);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($this->arguments));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
            $result = curl_exec($ch); 
    
            curl_close($ch);           
        
        }

function is_getter(string $method): string {
    return str_starts_with($method, "get");
}

function filterRefClassMethods($refclass) {
    $methods = [];
    foreach ($refclass->getMethods() as $method) {
        if ($method->class === $refclass->getName()) {
            $methods[] = $method->name;
        }
    }
    return $methods;
}

sendMessage类

class sendMessage extends Method {

protected $chat_id;
protected $message_thread_id;
protected $text;
/* ... */
/* getters and setters... */

}

问题原因

  1. API参数格式不匹配:Telegram API要求reply_markup必须是JSON格式字符串,但当前用http_build_query()将PHP数组直接编码为URL格式(如reply_markup[keyboard][0][0][text]=btn),这种格式无法被API正确解析为键盘结构。
  2. 请求方式局限性:使用application/x-www-form-urlencoded格式传递复杂嵌套参数时,容易出现解析异常,官方更推荐用application/json格式发送完整请求体。

解决方案

方案一:单独转换reply_markup为JSON(兼容现有请求格式)

在生成参数数组后,单独对reply_markup进行JSON编码:

public function execute() {
    $refclass = new ReflectionClass($this::class);
    $this->method = $refclass->getShortName();        
    $this->arguments = ($this->extractFields($this, filterRefClassMethods($refclass)));

    // 新增:将reply_markup转为JSON字符串
    if (isset($this->arguments['reply_markup'])) {
        $this->arguments['reply_markup'] = json_encode($this->arguments['reply_markup']);
    }

    $this->methodUrl .= API_TOKEN . "/" . $this->method . "?";        
    $ch = curl_init();        
    curl_setopt($ch, CURLOPT_URL, $this->methodUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($this->arguments));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($ch); 

    curl_close($ch);           
}

方案二:改用JSON格式发送完整请求(官方推荐)

直接将整个参数数组转为JSON,设置正确的请求头,避免嵌套参数解析问题:

public function execute() {
    $refclass = new ReflectionClass($this::class);
    $this->method = $refclass->getShortName();        
    $this->arguments = ($this->extractFields($this, filterRefClassMethods($refclass)));

    // 修改URL:移除末尾的?,参数将放在POST体中
    $this->methodUrl .= API_TOKEN . "/" . $this->method;        
    $ch = curl_init();        
    curl_setopt($ch, CURLOPT_URL, $this->methodUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    // 发送JSON格式的请求体
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($this->arguments));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // 设置正确的Content-Type头
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json'
    ]);

    $result = curl_exec($ch); 

    curl_close($ch);           
}

额外检查:键盘结构正确性

确保键盘结构符合官方规范,示例如下:

// Reply Keyboard 正确结构示例
$reply_markup = [
    'keyboard' => [
        ['按钮1', '按钮2'], // 一行两个按钮
        ['按钮3'] // 一行一个按钮
    ],
    'resize_keyboard' => true, // 可选:让键盘适配屏幕大小
    'one_time_keyboard' => true // 可选:点击后自动隐藏键盘
];

内容的提问来源于stack exchange,提问作者G. Ianni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:22:17