如何确保用户输入的包含国际字符的数据不会损坏


How do I ensure that user entered data containing international characters doesn't get corrupted?

经常

发生诸如é之类的字符被转换为é的情况,即使MySQL DB,表和字段的排序规则设置为utf8_general_ci也是如此。页面的内容类型中的编码也设置为 UTF8。

我知道utf8_encode/解码,但我不太确定在哪里以及如何使用它。

我已经阅读了"每个软件开发人员绝对,肯定必须了解Unicode和字符集的绝对最低限度(没有借口!"的文章,但我需要一些 MySQL/PHP 特定的指针。

如何确保用户输入的包含国际字符的数据不会损坏?

在第一次看到 http://www.nicknettleton.com/zine/php/php-utf-8-cheatsheet 时,我认为缺少一件重要的事情(也许我忽略了这件)。根据您的MySQL安装和/或配置,您必须设置连接编码,以便MySQL知道客户端(意味着MySQL连接的客户端,应该是PHP脚本)上期望的编码。您可以通过手动发出

SET NAMES utf8

在您发送到 MySQL 服务器的任何其他查询之前进行查询。

如果您在 PHP 端使用 PDO,则可以将连接设置为在每次(重新)连接时自动发出此查询,方法是使用

$db=new PDO($dsn, $user, $pass);
$db->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8");

初始化数据库连接时。

排序规则和字符集不是一回事。您的排序规则需要与字符集匹配,因此如果您的字符集是 utf-8,则排序规则也应该匹配。选择错误的排序规则不会使数据乱码 - 只是使字符串比较/排序工作错误。

也就是说,有几个地方可以在 PHP 中设置字符集设置。如果可能的话,我建议您始终使用 utf-8。需要指定字符集的位置包括:

  • 数据库。这可以在数据库、表和字段级别设置,甚至可以在每个查询级别设置。
  • PHP 和数据库之间的连接。
  • HTTP输出;确保 HTTP 标头Content-Type指定 utf-8。您可以在PHP和Apache中设置默认值,也可以使用PHP的header函数。
  • HTTP 输入。通常,表单将以与提供页面相同的字符集提交,但为了确保安全,您应该指定 accept-charset 属性。还要确保 URL 是 utf-8 编码的,或者避免在 url 中使用非 ascii 字符(和 GET 参数)。

utf8_encode/decode 函数的名字有点奇怪。它们专门在拉丁语1(ISO-8859-1)和utf-8之间进行转换。如果应用程序中的所有内容都是 utf-8,则不必过多使用它们。

关于 utf-8 和 PHP 至少有两个陷阱。首先,PHP 的内置字符串函数希望字符串是单字节的。对于很多操作来说,这并不重要,但这意味着你不能依赖strlen和其他功能。此页面上有很好的限制概述。通常,这不是一个大问题,但尤其是在使用 3 方库时,您需要意识到事情可能会因此而爆炸。一种选择是使用 mb_string 扩展,该扩展可以选择用 utf-8 感知替代方案替换所有麻烦的功能。它仍然不是100%防弹的解决方案,但在大多数情况下都有效。

另一个问题是某些 PHP 安装仍然打开了magic_quotes设置。此问题与 utf-8 正交,但可能会导致一些挠头。为了你自己的理智,把它关掉。

你应该

做的事情:

  • 确保 Apache 发布 UTF-8 内容。在你的httpd.conf中执行此操作,或使用PHP的header()函数手动执行此操作。
  • 确保您的数据库连接为 UTF8。 SET NAMES utf8做到了。
  • 确保所有表都设置为 UTF8。
  • 如果将所有 PHP 和模板文件都编码为 UTF8,请确保在其中存储国际字符。

执行此操作时,通常不必使用 mb_stringutf8_encode/decode -函数执行太多操作。

为了更好的 unicode 正确性,您应该使用 utf8_unicode_ci(尽管文档对差异有点模糊)。您还应该确保正确设置以下 Mysql 标志 -

  • 默认字符集=UTF8
  • 跳过字符集客户端握手//重要,以便客户端不会强制执行其他编码

这些可以在 mysql 配置文件(在 [mysqld] 选项卡下)中设置,也可以在运行时通过发送适当的查询来设置。

无论它是用哪种语言编写的,如果您要创建一个允许各种编码的应用程序,请将其分段处理:

  • 识别编码
    • 不知何故,您想找出您正在处理的编码类型,否则,进一步考虑它是毫无意义的。你最终会得到垃圾字符。
  • 处理您的字节
      将这些字符串视为不太像
    • 字符的"字符串",而更像是字节列表
    • PHP特别狡猾。不要让它即时截断您的数据。如果要正则表达式 UTF-8 字符串,请确保将其标识为 UTF-8 字符串
  • 液晶屏存储
    • 同样,您不希望截断数据。如果你用英语存储一个句子,你也可以存储一组普通话字形吗?阿拉伯语怎么样?其中哪一个需要最多的空间?说明它。