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

Telegram PHP Bot emoji/特殊字符下实体offset与length异常问题

解决Telegram Bot中含Emoji/特殊字符时Entity偏移量偏差问题

问题背景

开发基于PHP的Telegram Bot时,需要提取文本内嵌的text_link类型Entity并替换为明文URL,但当文本包含Emoji或多字节特殊字符时,Telegram返回的Entity的offset和length参数会出现偏差,导致截取的文本错误。

核心原因

Telegram API中Entity的offset和length是基于UTF-16代码单元计数的,而PHP默认的字符串操作(包括mb_substr)是按UTF-8字符计数。例如Emoji这类字符在UTF-16中占2个代码单元,直接用Telegram的参数去截取UTF-8文本必然会错位。

解决方案

将原始文本转换为UTF-16编码,按Telegram的参数截取对应部分后再转回UTF-8;同时调整代码逻辑,避免转义字符干扰替换,改用精准的位置替换而非全局字符串替换。

修改后的完整代码

<?php
$admin = ''; // 填入你的用户ID
$update = file_get_contents('php://input');
$update = json_decode($update, TRUE);

if (!empty($update['message'])) {
    $message = $update['message'];
    $text = $message['text'] ?? '';
    $links = [];

    if (!empty($message["entities"])) {
        foreach ($message["entities"] as $entity) {
            if ($entity["type"] === "text_link") {
                // 筛选亚马逊相关链接
                if (preg_match("/(https?:\/\/(?:www\.)?(?:amazon\.[a-z\.]+|amzn\.to+|amzn\.eu)\/[^\s]+)/i", $entity["url"], $matches)) {
                    $links[] = [
                        "url" => $entity["url"],
                        "offset" => $entity["offset"],
                        "length" => $entity["length"]
                    ];
                }
            }
        }
    }

    if (!empty($links)) {
        // 处理UTF-16与UTF-8的计数差异
        foreach ($links as $link) {
            $url = $link["url"];
            $offset = $link["offset"];
            $length = $link["length"];

            // 1. 将UTF-8文本转成Telegram使用的UTF-16LE编码
            $utf16Text = mb_convert_encoding($text, 'UTF-16LE', 'UTF-8');
            // 2. 按UTF-16代码单元截取:每个单元占2字节,所以偏移量和长度都乘以2
            $utf16Original = substr($utf16Text, $offset * 2, $length * 2);
            // 3. 转回UTF-8得到正确的原始文本片段
            $originalText = mb_convert_encoding($utf16Original, 'UTF-8', 'UTF-16LE');

            // 用mb_substr_replace精准替换对应位置的文本,避免重复内容误替换
            $text = mb_substr_replace($text, $url, $offset, $length);
        }
    }

    // 最后转义HTML特殊字符,避免发送消息时的格式冲突
    $text = htmlspecialchars($text, ENT_QUOTES);
    inviaMessaggio($admin, $text, null, "true");
}

function inviaMessaggio($chat_id, $text, $tastiera, $anteprima = "true")
{
    $args = [];
    $args['chat_id'] = $chat_id;
    $args['text'] = $text;
    $args['parse_mode'] = "HTML";
    $args['disable_web_page_preview'] = $anteprima;
    $rm = null;
    if (!empty($tastiera)) {
        $rm = json_encode(['inline_keyboard' => $tastiera]);
    }
    $args['reply_markup'] = $rm;
    // 发送消息
    $response = curlRequest($GLOBALS['website'].'/sendMessage', $args);

    // 从响应中提取消息ID
    $messageData = json_decode($response, true);
    if (isset($messageData['result'])) {
        $messageId = $messageData['result']['message_id'];
        return ['response' => $response, 'message_id' => $messageId];
    }
}

// 补充缺失的curl请求函数
function curlRequest($url, $data) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
?>

关键修改说明

  1. 编码转换逻辑:通过mb_convert_encoding实现UTF-8与UTF-16LE的互转,完全匹配Telegram的计数规则,解决偏移量偏差问题。
  2. 精准替换:用mb_substr_replace替代str_replace,直接按位置替换目标文本,避免重复内容导致的误替换。
  3. 逻辑优化:
    • 初始化$text变量,避免未定义错误;
    • 合并Entity遍历逻辑,减少重复循环;
    • 将htmlspecialchars移到替换之后,防止转义字符干扰原始文本匹配;
    • 补充了缺失的curlRequest函数,确保代码可直接运行。

内容的提问来源于stack exchange,提问作者Vainucleo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:36:04