如何解决PHP中DomDocument导致的文本乱码问题?
解决DOMDocument处理UTF-8特殊字符乱码问题
你的代码出现乱码的核心原因是DOMDocument默认使用ISO-8859-1编码解析HTML,而你的文本是UTF-8格式,导致特殊字符(如→、’)被错误转换。另外代码中还有一个逻辑错误:return语句放在了foreach循环内部,会导致只处理第一个链接就终止。
以下是具体修复方案:
1. 加载HTML时指定UTF-8编码
在加载原始HTML前,添加UTF-8编码声明,让DOMDocument正确识别编码:
$domDocument = new \DOMDocument(); // 前置UTF-8编码声明,避免DOMDocument默认用ISO-8859-1解析 $domDocument->loadHTML('<?xml encoding="UTF-8">' . $text, LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR); $domDocument->formatOutput = true; $links = $domDocument->getElementsByTagName('a');
2. 修复循环内的return语句
将return $domDocument->saveHTML();移到foreach循环外部,确保所有链接都被处理:
foreach($links as $link) { $href = $link->getAttribute('href'); $title = $this->fetchPageTitle($href); $link->nodeValue = $title; } // 循环结束后再返回处理后的HTML $html = $domDocument->saveHTML();
3. 保存HTML时强制UTF-8编码
DOMDocument的saveHTML()默认可能输出ISO-8859-1编码的内容,需要转换为UTF-8:
return mb_convert_encoding($html, 'UTF-8', 'ISO-8859-1');
4. 优化页面标题获取的编码处理
在fetchPageTitle方法中,先根据响应头的字符集转换页面内容为UTF-8,再加载到DOMDocument:
private function fetchPageTitle($url) :string { $response = Http::get($url); // 从响应头提取字符集,默认UTF-8 $contentType = $response->header('Content-Type'); $charset = 'UTF-8'; if (preg_match('/charset=([^\s;]+)/', $contentType, $matches)) { $charset = $matches[1]; } // 将页面内容转换为UTF-8 $page_html = mb_convert_encoding($response->body(), 'UTF-8', $charset); $pageDocument = new \DOMDocument(); // 同样添加UTF-8声明 $pageDocument->loadHTML('<?xml encoding="UTF-8">' . $page_html, LIBXML_NOERROR); $titleNode = $pageDocument->getElementsByTagName('title')->item(0); // 处理标题不存在的情况,避免报错 return $titleNode ? $titleNode->nodeValue : $url; }
完整修正后的代码
$domDocument = new \DOMDocument(); $domDocument->loadHTML('<?xml encoding="UTF-8">' . $text, LIBXML_HTML_NOIMPLIED | LIBXML_NOERROR); $domDocument->formatOutput = true; $links = $domDocument->getElementsByTagName('a'); foreach($links as $link) { $href = $link->getAttribute('href'); $title = $this->fetchPageTitle($href); $link->nodeValue = $title; } $html = $domDocument->saveHTML(); return mb_convert_encoding($html, 'UTF-8', 'ISO-8859-1'); private function fetchPageTitle($url) :string { $response = Http::get($url); $contentType = $response->header('Content-Type'); $charset = 'UTF-8'; if (preg_match('/charset=([^\s;]+)/', $contentType, $matches)) { $charset = $matches[1]; } $page_html = mb_convert_encoding($response->body(), 'UTF-8', $charset); $pageDocument = new \DOMDocument(); $pageDocument->loadHTML('<?xml encoding="UTF-8">' . $page_html, LIBXML_NOERROR); $titleNode = $pageDocument->getElementsByTagName('title')->item(0); return $titleNode ? $titleNode->nodeValue : $url; }
这些修改确保了整个流程中所有文本都以UTF-8编码处理,彻底解决特殊字符乱码问题,同时修复了只处理单个链接的逻辑错误。
内容的提问来源于stack exchange,提问作者TheBigK
相关产品推荐
相关产品推荐

