我有一个使用 latin-1 的数据库和一个 utf-8 的 PHP 应用程序。
我在数据库中有这样的字符串:
' Société ' 应该是 Société
“ € 10 亿”应该是 20 亿欧元。
当我使用 PHP 的ord()将错误字符打印到屏幕上时,从数据库中的返回数据中,它会打印 195 和 226。
有人可以解释为什么会发生这种情况(为什么要这样保存以及为什么要按原样读取字符)以及我是否可以扭转它。
我有一个使用 latin-1 的数据库和一个 utf-8 的 PHP 应用程序。
我在数据库中有这样的字符串:
' Société ' 应该是 Société
“ € 10 亿”应该是 20 亿欧元。
当我使用 PHP 的ord()将错误字符打印到屏幕上时,从数据库中的返回数据中,它会打印 195 和 226。
有人可以解释为什么会发生这种情况(为什么要这样保存以及为什么要按原样读取字符)以及我是否可以扭转它。
为什么:
1) é是unicode 233(浏览器读取它)。
é
utf8 字节转换为 latin1 字符字节是Ã ©
. 这就是为什么它在数据库中看起来像这样。
à ©
被识别为Ã
代码点 195。这就是为什么你会看到它。
2) € 是 unicode 8364。
€ utf8 字节转换为 latin1 chars 字节是â <82> ¬
. 这也是为什么它们在数据库中看起来像这样的原因。
â <82> ¬
被识别为â
代码点 226。这也是您看到此内容的原因。
这就是为什么您会从中看到这些值ord()
以及字符以这种方式存储在 latin-1 数据库中的原因。
逆转:
要反转它,我们需要将 Latin-1 字符字节转换为 UTF8 字节。
如果我们尝试一下:
â
是 226。将 latin-1 转换为 utf8 会产生â
.
Ã
是 195。将 latin-1 转换为 utf8 会产生Ã
.
问题:
问题是 Latin-1 的字符比 utf-8 少(很长一段路)。
Latin1 单字节流和 UTF8 多字节字符流,因此 utf8 中的 1 个字符最多可以为 latin1 生成 4 个字符。
所以 UTF-8 到 Latin-1 的转换会产生错误的字符。
Latin1 回到 utf8 是不可能的。
解决方案:
如果您无法更改数据库的字符集,我可以建议在编写它们之前将数据库中的特殊字符编码为它们的字符实体(因此 db 可以保持为 latin1 和 app 为 utf8,因为两者都可以理解 html 实体)例如 umlaut 为Ä
.
可以使用 PHPhtml_entity_decode()
结合mb_detect_encoding()
检测和转换特定字符来完成。
参考:
有关utf8 char 字节到 latin1 字节的信息,请参见ltf.ed.ac.uk:http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=%C3%96&mode=char