迁移php应用程序以处理UTF-8

时间:2013-05-31 13:51:23

标签: php utf-8 iconv

我正在使用php中的多语言应用程序。

一切都很好,直到最近才被要求支持中文字符。我为支持UTF-8字符而采取的措施如下:

  • 所有数据库表现在都是UTF-8

  • HTML模板包含标记<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

  • 控制器发出一个标题,指定用于http响应的编码(utf-8)

一切都很好,直到我开始进行一些字符串操作(substr等)

使用中文它将无法工作,因为中文表示为多字节,因此如果你做一个正常的子字符串(substr),它会在分配的字节之一和f * ck up中间切割一个“字母”屏幕上的结果。

我通过在引导程序

中添加此问题来修复我的所有问题

mb_internal_encoding("UTF-8");

并将所有strlensubstrstrstr替换为mb_对应的人。

在php中完全支持UTF-8需要做些什么?

1 个答案:

答案 0 :(得分:8)

除了更换这些功能之外还有一点点。

正则表达式

您应该将utf8标志添加到所有可以包含非Ascii字符的字符串的PCRE正则表达式中,以便将模式解释为实际字符而不是字节。

$subject = "Helló";
$pattern = '/(l|ó){2,3}/u'; //The u flag indicates the pattern is UTF8
preg_match($pattern, substr($subject,3), $matches, PREG_OFFSET_CAPTURE);

如果你希望你的正则表达式对于非拉丁字母表是正确的,你应该使用Unicode character classes而不是标准的Perl吗?

  • \ p {L}而不是\ w表示任何“字母”字符。
  • \ p {Z}而不是\ s表示任何“空格”字符。
  • \ p {N}代替\ d代表任何“数字”字符,例如Arabic numbers

有很多不同的Unicode字符类,其中一些对于习惯用拉丁字母读写的人来说非常不寻常。例如,一些characters combine with the previous字符可以创建一个新的字形。对它们的更多解释可以是read here

虽然mbstring扩展中有正则表达式函数,但不建议使用它们。标准PCRE功能可以正常使用UTF8标志。

功能替换

虽然你的列表是一个开头,但我到目前为止找到的需要用多字节版本替换的函数列表更长。这是具有替换函数的函数列表,其中一些函数未在PHP中定义,但可从Github as mb_extra处获得。

$unsafeFunctions = array(
    'mail'      => 'mb_send_mail',
    'split'     => null, //'mb_split', deprecated function - just don't use it
    'stripos'   => 'mb_stripos',
    'stristr'   => 'mb_stristr',
    'strlen'    => 'mb_strlen',
    'strpos'    => 'mb_strpos',
    'strrpos'   => 'mb_strrpos',
    'strrchr'   => 'mb_strrchr',
    'strripos'  => 'mb_strripos',
    'strstr'    => 'mb_strstr',
    'strtolower'    => 'mb_strtolower',
    'strtoupper'    => 'mb_strtoupper',
    'substr_count'  => 'mb_substr_count',
    'substr'        => 'mb_substr',
    'str_ireplace'  => null,
    'str_split'     => 'mb_str_split', //TODO - check this works
    'strcasecmp'    => 'mb_strcasecmp', //TODO - check this works
    'strcspn'       => null, //TODO - implement alternative
    'strrev'        => 'mb_strrev', //TODO - check this works
    'strspn'        => null, //TODO - implement alternative
    'substr_replace'=> 'mb_substr_replace',
    'lcfirst'       => null,
    'ucfirst'       => 'mb_ucfirst',
    'ucwords'       => 'mb_ucwords',
    'wordwrap'      => null,
);

<强>的MySQL

虽然您可能认为将字符类型设置为utf8会在MySQL中为您提供UTF-8支持,但事实并非如此。

它只支持UTF-8,它最多可编码3个字节,即Basic Multi-lingual Plane。然而,人们正在积极使用需要4个字节进行编码的字符,包括大多数Emoji characters,也称为Supplementary Multilingual Plane

为了支持这些,您通常应该使用:

  • utf8mb4 - 用于您的角色编码。
  • utf8mb4_unicode_ci - 用于角色整理。

对于特定场景,可能有适合您的备用排序规则集,但通常会坚持最正确的排序规则集。

您应在MySQL配置文件中设置字符集和排序规则的位置列表:

[mysql]
default-character-set=utf8mb4

[client]
default-character-set=utf8mb4

[mysqld]
init-connect='SET NAMES utf8mb4'
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

在所有情况下可能都不需要SET NAMES - 但只需要很小的速度惩罚就更安全。

PHP INI文件

虽然你说你已经在你的bootstrap脚本中设置了mb_internal_encoding,但是在PHP ini文件中这样做要好得多,并且还设置了所有推荐的参数:

mbstring.language   = Neutral   ; Set default language to Neutral(UTF-8) (default)
mbstring.internal_encoding  = UTF-8 ; Set default internal encoding to UTF-8
mbstring.encoding_translation = On  ;  HTTP input encoding translation is enabled
mbstring.http_input     = auto  ; Set HTTP input character set dectection to auto
mbstring.http_output    = UTF-8 ; Set HTTP output encoding to UTF-8
mbstring.detect_order   = auto  ; Set default character encoding detection order to auto
mbstring.substitute_character = none ; Do not print invalid characters
default_charset      = UTF-8 ; Default character set for auto content type header

帮助浏览器为表单选择UTF8

  • 您需要将表单上的accept-charset设置为UTF-8,以告知浏览器将其提交为UTF8。

  • 在您的form in a hidden field中添加UTF8字符,以阻止Internet Explorer(5,6,7和8)将表单提交为UTF8以外的其他内容。

<强>其它

  • 如果您正在使用Apache设置“AddDefaultCharset utf-8”

  • 正如您所说的那样,但只是为了提醒任何人阅读答案,请在标题中设置元内容类型。

那应该是关于它的。虽然值得阅读“What Every Programmer Absolutely, Positively Needs To Know About Encodings And Character Sets To Work With Text”页面,但我认为它优于use UTF-8 everywhere,因此不必花费任何精力去处理不同的字符集。