确保在PHP中使用有效的utf-8

Bri*_*ian 20 php encoding utf-8

我正在使用PHP来处理来自各种来源的文本.我不认为它将是UTF-8,ISO-8859-1或WINDOWS-1252以外的任何东西.如果它不是其中之一,我只需要确保文本变成有效的UTF-8字符串,即使字符丢失也是如此.iconv的// TRANSLIT选项是否解决了这个问题?例如,此代码是否确保字符串可以安全地插入到UTF-8编码的文档(或数据库)中?

function make_safe_for_utf8_use($string) {

    $encoding = mb_detect_encoding($string, "UTF-8,ISO-8859-1,WINDOWS-1252");

    if ($encoding != 'UTF-8') {
        return iconv($encoding, 'UTF-8//TRANSLIT', $string);
    }
    else {
        return $string;
    }
}
Run Code Online (Sandbox Code Playgroud)

bob*_*nce 37

UTF-8可以存储任何Unicode字符.如果你的编码是其他任何东西,包括ISO-8859-1或Windows-1252,UTF-8可以存储其中的每个字符.因此,当您将字符串从任何其他编码转换为UTF-8时,您不必担心会丢失任何字符.

此外,ISO-8859-1和Windows-1252都是单字节编码,其中任何字节都是有效的.从技术上讲,区分它们是不可能的.我会选择Windows-1252作为非UTF-8序列的默认匹配,因为唯一不同的解码字节是0x80-0x9F.这些解码到各种字符,如智能引号和Windows-1252中的欧元,而在ISO-8859-1中,它们是几乎从不使用的隐形控制字符.Web浏览器有时可能会说他们正在使用ISO-8859-1,但他们通常会使用Windows-1252.

这段代码是否确保字符串可以安全地插入到UTF-8编码的文档中

您肯定希望为此目的将可选的'strict'参数设置为TRUE.但我不确定这实际上涵盖了所有无效的UTF-8序列.该函数并未声明明确检查字节序列的UTF-8有效性.已知mb_detect_encoding之前会错误地猜测UTF-8的情况,但我不知道在严格模式下是否仍然会发生这种情况.

如果你想确定,使用W3推荐的正则表达式自己动手:

if (preg_match('%^(?:
      [\x09\x0A\x0D\x20-\x7E]            # ASCII
    | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
    | \xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs
    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
    | \xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates
    | \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
    | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
    | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
)*$%xs', $string))
    return $string;
else
    return iconv('CP1252', 'UTF-8', $string);
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这个正则表达式是错误的.它将无法匹配有效的UTF-8代码点(例如`chr(0)`).它适用于可打印的字符,但不适用于通用的UTF-8 ... (2认同)

Fro*_*y Z 14

使用mbstring库,你有mb_check_encoding().

使用示例:

mb_check_encoding($string, 'UTF-8');
Run Code Online (Sandbox Code Playgroud)

当性能很重要时,这比接受的答案中提供的正则表达式更快.

我的配置快速测试显示(20,000次迭代):

  • 正则表达式:~310ms
  • mb_check_encoding:~90ms

编辑

在最近的Windows 10系统上使用PHP 7.1.9,正则表达式解决方案优于mb_check_encoding()任何字符串长度(仍然是20,000次迭代):

  • 10个字符:正则表达式=> 4ms,mb_check_encoding()=> 64ms
  • 10000个字符:正则表达式=> 125ms,mb_check_encoding()=> 2.4s


eye*_*hUp 7

请注意:您可以简单地使用 'u' 修饰符来测试字符串的 UTF-8 有效性,而不是使用W3C经常推荐的(相当复杂的)正则表达式:

<?php
  if (preg_match("//u", $string)) {
      // $string is valid UTF-8
  }
Run Code Online (Sandbox Code Playgroud)