本文介绍如何解决 twitter api 返回的重复 url 实体导致 html 链接被多次替换的问题,通过去重判断与提前终止循环,确保每个短链仅被渲染一次。
在使用 Twitter(现 X)API 获取推文内容时,entities.urls 字段常会返回多个结构完全相同的 URL 对象——尤其当一条推文附带多张图片时,Twitter 会为同一缩略图短链(如 t.co/xxx)重复填充 2–4 个 stdClass 实体。而原始 link_urls() 方法未做去重处理,直接对每个实体执行 str_replace(),导致短链被反复替换,最终生成嵌套、损坏的 HTML(如 标签属性错乱、重复拼接),严重破坏前端渲染。
根本问题在于:str_replace() 是全局替换,且后续迭代仍会匹配已被替换过的 HTML 片段中的 url 字符串(例如 pic.twitter.com/... 出现在已生成的 中),造成二次、三次误替换。
✅ 正确解法不是简单“跳过重复对象”,而是 确保每个唯一短链仅处理一次,且仅在原始纯文本中匹配。优化后的代码如下:
public function link_urls($text)
{
if (!$urls = $this->get('entities', 'urls')) {
return $text;
}
// 使用关联数组去重:以 url 为键,保留首个出现的实体
$uniqueUrls = [];
foreach ($urls as $url) {
// 清理 URL 空格(Twitter 响应中偶有空格,如 "https:// t.co/...")
$cleanUrl = str_replace(' ', '', $url->url);
if (!isset($uniqueUrls[$cleanUrl])) {
$uniqueUrls[$cleanUrl] = $url;
}
}
// 仅遍历去重后的唯一 URL 列表
foreach ($uniqueUrls as $cleanUrl => $url) {
// 严格限定:只在原始 $text(未修改前)中查找,避免 HTML 内误匹配
if (strpos($text, $cleanUrl) !== false) {
$text = str_replace(
$cleanUrl,
''
. htmlspecialcha
rs($url->display_url) . '',
$text
);
}
}
return $text;
}? 关键改进说明:
⚠️ 注意事项:
通过此方案,无论 API 返回 1 个还是 10 个重复 URL 实体,最终输出都将是语义正确、安全合规、结构干净的单个超链接。