UTF-8 all the way through
我正在设置一个新服务器,希望在我的Web应用程序中完全支持UTF-8。我以前在现有的服务器上尝试过这种方法,结果总是不得不回到ISO-8859-1。
我到底需要在哪里设置编码/字符集?我知道我需要配置Apache、MySQL和PHP来实现这一点——我是否可以遵循一些标准的检查清单,或者在出现不匹配的地方进行故障排除?
这是一个新的Linux服务器,运行mysql 5、php、5和apache 2。
数据存储:好的。
在数据库中的所有表和文本列上指定
utf8mb4 字符集。这使得MySQL可以物理地存储和检索以UTF-8编码的值。注意,如果指定了utf8mb4_* 排序规则(没有任何显式字符集),mysql将隐式使用utf8mb4 编码。好的。在旧版本的mysql(<5.5.3)中,不幸的是,您将不得不简单地使用
utf8 ,它只支持Unicode字符的子集。我真希望我开玩笑。好的。
数据访问:好的。
在应用程序代码(例如php)中,无论使用何种数据库访问方法,都需要将连接字符集设置为
utf8mb4 。这样,当MySQL将数据移交给您的应用程序时,它就不会从它的原生UTF-8进行转换,反之亦然。好的。一些驱动程序提供了自己的连接字符集配置机制,这两种机制都会更新自己的内部状态,并通知MySQL要在连接上使用的编码&mdash;这通常是首选的方法。在PHP中:好的。
如果将PDO抽象层与php&ge;5.3.6一起使用,则可以在DSN中指定
charset :好的。1$dbh = new PDO('mysql:charset=utf8mb4');如果你使用mysqli,你可以打电话给
set_charset() :好的。1
2$mysqli->set_charset('utf8mb4'); // object oriented style
mysqli_set_charset($link, 'utf8mb4'); // procedural style如果你坚持使用普通的mysql,但恰好运行php&ge;5.2.3,你可以调用
mysql_set_charset 。好的。
如果驱动程序没有提供自己的机制来设置连接字符集,那么您可能需要发出一个查询来告诉MySQL您的应用程序希望如何对连接上的数据进行编码:
SET NAMES 'utf8mb4' 。好的。关于
utf8mb4 /utf8 的相同考虑同样适用于上述情况。好的。
输出:好的。
如果您的应用程序将文本传输到其他系统,则还需要通知它们字符编码。对于Web应用程序,必须通知浏览器发送数据的编码(通过HTTP响应头或HTML元数据)。好的。
在php中,您可以使用
default_charset php.ini选项,也可以自己手动发出Content-Type mime头文件,这只不过是更多的工作,但效果相同。好的。
输入:好的。
不幸的是,在尝试存储或在任何地方使用之前,您应该验证每个接收到的字符串都是有效的UTF-8。PHP的
mb_check_encoding() 完成了这个技巧,但您必须认真使用它。确实没有办法解决这个问题,因为恶意客户机可以以他们想要的任何编码提交数据,而且我还没有找到让PHP可靠地为您完成这一任务的诀窍。好的。根据我对当前HTML规范的理解,以下子项目符号对于现代HTML来说不再是必需的,甚至不再有效。我的理解是浏览器将使用并提交文档指定字符集中的数据。但是,如果您的目标是旧版本的HTML(XHTML、HTML4等),这些要点可能仍然有用:好的。
- 对于HTML5之前的HTML:您希望浏览器发送给您的所有数据都是UTF-8格式。不幸的是,如果您选择可靠的方法,那么将
accept-charset 属性添加到您的所有 标记中:
- 对于HTML5之前的HTML:请注意,W3C HTML规范规定,客户机"应该"默认以服务器提供的任何字符集将表单发送回服务器,但这显然只是一个建议,因此需要在每个
标记上显式显示。
- 对于HTML5之前的HTML:您希望浏览器发送给您的所有数据都是UTF-8格式。不幸的是,如果您选择可靠的方法,那么将
其他代码注意事项:好的。
显然,您将要服务的所有文件(PHP、HTML、javascript等)都应该使用有效的UTF-8编码。好的。
您需要确保每次处理一个utf-8字符串时都是安全的。不幸的是,这是最困难的部分。您可能希望广泛使用PHP的
mbstring 扩展。好的。默认情况下,PHP的内置字符串操作不是UTF-8安全的。对于普通的php字符串操作(如连接),您可以安全地执行一些操作,但对于大多数操作,您应该使用等效的
mbstring 函数。好的。为了知道你在做什么(阅读:不要搞砸了),你真的需要知道UTF-8以及它在尽可能低的级别上是如何工作的。查看utf8.com的任何链接,获取一些好的资源,了解您需要了解的所有信息。好的。
好啊。
我想在查佐马提库斯出色的回答中加上一点:
也不要忘记meta标签(像这样,或者它的HTML4或XHTML版本):
1 | <meta charset="utf-8"> |
这似乎微不足道,但IE7以前给了我一些问题。
我做得很好;数据库、数据库连接和内容类型HTTP头都设置为UTF-8,在所有其他浏览器中都工作正常,但Internet Explorer仍然坚持使用"西欧"编码。
结果发现页面缺少元标记。加上这些解决了问题。
编辑:
W3C实际上有一个相当大的部分专门用于i18n。它们有许多与此问题相关的文章&ndash;描述http,(x)html和css方面的内容:
- 常见问题解答:将(x)HTML页面编码更改为UTF-8
- 在HTML中声明字符编码
- 教程:XHTML、HTML和CSS中的字符集和编码
- 设置HTTP字符集参数
他们建议同时使用HTTP头和HTML元标记(或者在XHTML用作XML的情况下使用XML声明)。
除了在php.ini中设置
1 |
在PHP中使用unicode很容易,只要您意识到大多数字符串函数不使用unicode,并且某些字符串可能会完全损坏。PHP认为"字符"的长度为1字节。有时这是可以的(例如,
一个好的图书馆是phputf8。这会重写所有"坏"函数,这样您就可以安全地使用utf8字符串。还有一些扩展,比如mbstring扩展,尝试为您做这些,但是我更喜欢使用库,因为它更便携(但我写的是大众市场产品,所以这对我很重要)。但是phputf8可以在幕后使用mbstring来提高性能。
老话题,我知道。发现有人使用PDO时出现问题,答案是将其用于PDO连接字符串:
1 2 3 4 5 | $pdo = new PDO( 'mysql:host=mysql.example.com;dbname=example_db', "username", "password", array(PDO::MYSQL_ATTR_INIT_COMMAND =>"SET NAMES utf8")); |
我从中得到这个的网站已经关闭了,幸运的是能够使用谷歌缓存获得它。
在我的例子中,我使用的是
作为补充说明,我还发现运行
首先,如果你的马力小于5.3马力,那么就没有了。你有很多问题要解决。
我很惊讶没有人提到intl库,它对unicode、字形、字符串操作、本地化等都有很好的支持,见下文。
我将在phpbenelux'14上引用伊丽莎白·史密斯幻灯片中有关PHP中Unicode支持的一些信息。
国际电信联盟好:
- 包裹ICU图书馆
- 标准化区域设置,每个脚本设置区域设置
- 数字格式
- 货币格式
- 邮件格式(替换GetText)
- 日历、日期、时区和时间
- 音译者
- 欺骗检查器
- 资源捆绑
- 变换器
- IDN支持
- 字形
- 校勘
- 遍历器
坏的:
- 不支持Zend_多咬合
- 不支持HTTP输入输出转换
- 不支持函数重载
MbS-字符串
- 启用Zend_多字节支持
- 支持透明HTTP入/出编码
- 提供一些功能性包装,如strtoupper
伊科夫
- 字符集转换的主要功能
- 输出缓冲处理程序
- MIME编码功能
- 转换
- 一些字符串帮助程序(len、substr、strpos、strrpos)
- 流式过滤器
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP') 。
数据库
- mysql:charset和collation,用于表和连接(而不是collation)。也不要使用mysql-msqli或pdo
- PostgreSQL:pg_set_client_编码
- sqlite(3):确保它是用unicode和intl支持编译的
其他一些哥特人
- 除非使用第三部分扩展名,否则不能在PHP和Windows中使用Unicode文件名。
- 如果使用exec、proc_open和其他命令行调用,则以ASCII格式发送所有内容
- 纯文本不是纯文本,文件有编码
- 您可以使用iconv过滤器动态转换文件
我将更新这个答案,以防添加的功能发生变化等。
我最近发现使用
解决方案是使用
1 |
mb_ uses MultiByte. It supports more characters but in general is a little slower.
我唯一要做的就是强调以utf8编码保存文件,我注意到浏览器接受这个属性而不是将utf8设置为代码编码。任何像样的文本编辑器都会向您显示这一点,例如,记事本++有一个文件编码菜单选项,它向您显示当前的编码,并允许您更改它。对于所有的PHP文件,我都使用不带bom的utf8。
前一段时间,有人让我为别人设计的php/mysql应用程序添加utf8支持,我注意到所有的文件都是用ansi编码的,所以我不得不使用iconv来转换所有的文件,更改数据库表以使用utf8字符集和utf8常规u ci collate,在连接后将"set name utf8"添加到数据库抽象层。action(如果使用5.3.6或更早版本,否则必须在连接字符串中使用charset=utf8)并更改字符串函数以使用等效的php多字节字符串函数。
我刚刚讨论了同一个问题,并在PHP手册中找到了一个很好的解决方案。
我将所有文件编码改为utf8,然后改为连接上的默认编码。这解决了所有的问题。
1 2 3 4 5 6 7 |
视图源
在PHP中,您需要使用多字节函数,或者打开mbstring.func_重载。这样,如果您的字符超过一个字节,strlen之类的东西就会工作。
您还需要确定响应的字符集。您可以像上面一样使用adddefaultcharset,或者编写返回头的PHP代码。(或者您可以向HTML文档添加元标记。)
PHP中的Unicode支持仍然是一个巨大的混乱。虽然它能够将iso8859字符串(内部使用)转换为utf8,但它缺乏本机处理Unicode字符串的能力,这意味着所有字符串处理函数都会损坏字符串。因此,您必须使用单独的库来获得适当的UTF8支持,或者自己重写所有字符串处理函数。
简单的部分就是在HTTP头文件和数据库等文件中指定字符集,但是如果您的PHP代码没有输出有效的UTF8,这些都不重要。这是最困难的部分,PHP在这方面几乎没有帮助。(我认为PHP6应该能解决最坏的问题,但那还需要一段时间)
如果您希望mysql服务器决定字符集,而不是将php作为客户机(我认为最好是旧行为),可以尝试在
如果您使用的不是UTF8,这可能会导致问题。
最好的答案是非常好的。下面是我在常规debian/php/mysql设置中需要做的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // storage // debian. apparently already utf-8 // retrieval // the mysql database was stored in utf-8, // but apparently php was requesting iso. this worked: // ***notice"utf8", without dash, this is a mysql encoding*** mysql_set_charset('utf8'); // delivery // php.ini did not have a default charset, // (it was commented out, shared host) and // no http encoding was specified in the apache headers. // this made apache send out a utf-8 header // (and perhaps made php actually send out utf-8) // ***notice"utf-8", with dash, this is a php encoding*** ini_set('default_charset','utf-8'); // submission // this worked in all major browsers once apache // was sending out the utf-8 header. i didnt add // the accept-charset attribute. // processing // changed a few commands in php, like substr, // to mb_substr |
就这样!
如果您想要一个MySQL解决方案,在服务器迁移之后,我的两个项目也有类似的问题。在搜索和尝试了很多解决方案后,我发现了这个/在这个解决方案起作用之前什么也没有):
1 |
把这一行添加到我的配置文件之后,一切都正常!
我在解决从HTML查询插入的问题时找到了这个解决方案https://www.w3schools.com/php/func_mysqli_set_charset.asp
祝你好运!