脚本标签中的 Symfony dom-crawler 字符串转换为 UTF8

0 php utf-8 symfony domcrawler

我有这个 HTML 内容:

<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
Run Code Online (Sandbox Code Playgroud)

当我使用 Symfony 的 dom-crawler 时,文本被 HTML 编码。我怎样才能防止这种情况?$crawler->html()结果:

<div>??</div>
<script>
    function drawCharts(){
        console.log('&#27979;&#35797;');
    }
Run Code Online (Sandbox Code Playgroud)

sep*_*ehr 6

让我们看看 symfony/dom-crawler 是如何工作的。下面是一个示例:

<?php

require 'vendor/autoload.php';

use Symfony\Component\DomCrawler\Crawler;

$html = <<<HTML
<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
HTML;

$crawler = new Crawler($html);

print $crawler->html();
Run Code Online (Sandbox Code Playgroud)

它输出:

<div>æµè¯</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('&aelig;&micro;&#139;&egrave;&macr;&#149;');
    }
</script>
Run Code Online (Sandbox Code Playgroud)

当您通过构造函数传递内容时,Crawler该类会尽力找出编码。如果它无法弄清楚任何事情,它会回退到ISO-8859-1; 这是 HTTP 1.1 规范定义的默认字符集。

如果您的 HTML 内容包含字符集元标记,则 Crawler 类将从其中读取字符集,对其进行设置并正确转换。这是上面相同的示例,在 HTML 内容之前添加了一个字符集元标记:

<?php

require 'vendor/autoload.php';

use Symfony\Component\DomCrawler\Crawler;

$html = <<<HTML
<meta charset="utf-8">
<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
HTML;

$crawler = new Crawler($html);

print $crawler->html();
Run Code Online (Sandbox Code Playgroud)

现在它打印:

<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('&#27979;&#35797;');
    }
</script>
Run Code Online (Sandbox Code Playgroud)

如果您不想添加字符集元标记,还有另一种方法;addHTMLContent()方法接受一个字符集作为它的第二个参数,它默认为UTF-8. 不是通过构造函数传递 HTML 内容,而是首先实例化类,然后使用此方法添加内容:

<?php

require 'vendor/autoload.php';

use Symfony\Component\DomCrawler\Crawler;

$html = <<<HTML
<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
HTML;

$crawler = new Crawler;

// You can safely drop the 2nd argument
$crawler->addHTMLContent($html, 'UTF-8');     

print $crawler->html();
Run Code Online (Sandbox Code Playgroud)

现在,没有字符集元标记,它打印:

<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('&#27979;&#35797;');
    }
</script>
Run Code Online (Sandbox Code Playgroud)

好的,您可能已经知道所有这些。那么,与&#27979;&#35797;? 为什么div内容按原样显示,但script标签中的相同内容被 html 编码?

Symfony 的Crawler类,正如它自己解释的那样,由于以下方面的错误将内容转换为 HTML 实体DOMDocument::loadHTML()

使用loadHTML()处理UTF-8页面时,可能会遇到DOM函数的输出与输入不一样的问题。例如,如果您想获得“C?nh tranh”,您将收到“Cạnh tranh”。我建议我们mb_convert_encoding在加载 UTF-8 页面之前使用。
https://php.net/manual/en/domdocument.loadhtml.php#74777

有人建议Content-Type在 head 元素中添加一个 HTML4元标记。其他一些建议在<?xml encoding="UTF-8">将 HTML 内容传递给loadHTML(). 由于您的 HTML 结构不完整(缺少headbody等),我建议您只需将输出传递给html_entity_decode()

<?php

require 'vendor/autoload.php';

use Symfony\Component\DomCrawler\Crawler;

$html = <<<HTML
<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
HTML;

$crawler = new Crawler();
$crawler->addHTMLContent($html, 'UTF-8');

print html_entity_decode($crawler->html());
Run Code Online (Sandbox Code Playgroud)

输出:

<div>??</div>
<script charset="utf-8" type="text/javascript">
    function drawCharts(){
        console.log('??');
    }
</script>
Run Code Online (Sandbox Code Playgroud)

这就是你想要的。

您可能还想阅读:
PHP DOMDocument loadHTML not encoding UTF-8