【发布时间】:2022-01-23 04:20:36
【问题描述】:
我正在使用 localhost windows10 apache 2.4:Apache/2.4.51 (Win64) OpenSSL/1.1.1l PHP/8.0.11和Database client version: libmysql - mysqlnd 8.0.11,它使用服务器Server version: 10.4.21-MariaDB - mariadb.org binary distribution。默认设置为 _utf8mb4:Server charset: UTF-8 Unicode (utf8mb4)。
我制作了一个 php 脚本,它使用 loadHTMLFile 从维基百科页面获取内容(包括 html 标签)。然后我进一步使用xpath->query过滤dom,然后数据被mysqli_real_escape_string转义后作为字符串保存在mysql表中。稍后,我查询数据库并将内容保存在传递给loadHTML 的变量中,然后删除一些 dom 元素,然后将修改后的内容传递给saveHTML 并回显到我的网页。
会发生一些字符显示如下:
  -->  - --> –€ --> €ευρώ --> ευÏÏŽÂ
当我使用echo utf8_decode($output) 时,所有字符都正确显示。注意:不使用utf8_decode,以下任何一项都无效:
<meta charset="utf-8"> // in my html file
header('Content-Type: text/html; charset=utf-8'); // before the echo statement
mysqli_query($conn, "SET NAMES utf8"); // before mysql insert into and Select from statements
mysqli_set_charset($conn, "utf8"); // before mysql insert into and Select from
声明
同样mb_detect_encoding($output) 和mb_detect_encoding(utf8_decode($output)) 返回UTF-8 不 utf8mb4。在我的 chrome 浏览器的网络/标题选项卡中,我总是将 Content-type 设为 text/html; charset=UTF-8 ,无论我在服务器端 php/mysql 设置中进行什么更改。
我的猜测是,维基百科页面中的数据是正常的UTF-8 形式,当loadHTMLFile 下载它时,它会被php 自动转换 为utf8mb4。现在这些数据以utf8mb4 格式保存在mysql 表中。稍后检索时,此数据将保留为utf8mb4 格式,并以utf8mb4 格式显示给浏览器。当我使用utf8_decode 时,它必须将其转换为正常的utf-8 格式。
我猜的问题是关于utf8_decode页面的php文档,没有提到utf8mb4,而是说,多字节UTF-8 ISO-8859-1编码被转换为单字节UTF-8 ISO-8859-1。其次,文档说,ISO-8859-1 字符集不包含欧元符号。但是我的网页在utf8_decode 之后成功显示了欧元符号,并且浏览器也能够解析多字节 utf-8 字符,所以如果这是utf8_decode 所做的唯一事情,那么它应该不会对我的代码产生任何影响。
编辑:
我找到了罪魁祸首。以下回显正确的字符:
$stmt = $conn->prepare("Select ...");
...
$result = $stmt->execute();
...
$row = $stmt->get_result()->fetch_assoc()
echo $row['content']; // gives €ερυώ
现在,$row['content'] 是直接来自我的数据库的数据,没有任何 utf_decode。但是后来我碰巧使用了 php domdocument 并且发生了以下情况:
libxml_use_internal_errors(true); // important
$content = new DOMDocument();
$content->loadHTML($row['content']);
echo $row['content'], $content->saveHTML($content); die();
// The output is: €ερυώ
//â¬ÎµÏÏÏ
以上代码在我的查看源代码中的输出是:
€ερυώ<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>â¬ÎµÏÏÏ</p></body></html>
那么请解释一下loadHTML 和saveHTML 到底在做什么?
P.S:我的全部代码在 github repo 上可用:https://github.com/AnupamKhosla/crimeWiki 和关于 wikipedea 页面编码的特定脚本在 https://github.com/AnupamKhosla/crimeWiki/blob/main/include/wikipedea_code.phphttps://github.com/AnupamKhosla/crimeWiki/blob/main/include/post_code.php
【问题讨论】:
-
什么版本的 MySQL? (
SELECT @@version;) -
"ISO-8859-1" 可能最接近 MySQL 的 "latin1"。
-
现在,您在问题中发布了编辑,很明显问题不在于 mysqli。问题是您没有为 DOMDocument 指定正确的编码。见stackoverflow.com/a/47396055/1839439
-
@Dharman 有趣的是,与您提供的链接相反,当我使用
$tmp = new DOMDocument(); $tmp->loadHTMLFile($url)加载维基百科网址时,所有字符都以 utf-8 编码,并且保存在我的数据库中的数据仍然是 utf-8格式。当我使用$content = new DOMDocument(); $content->loadHTML($row['content']);查询该数据并从中创建html dom时,我遇到了编码问题。
标签: php mysql utf-8 character-encoding utf8mb4