首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理无效UTF-8字符的用户输入

如何处理无效UTF-8字符的用户输入
EN

Stack Overflow用户
提问于 2010-09-15 06:42:37
回答 9查看 54.5K关注 0票数 40

我正在寻找一个关于如何处理来自用户的无效UTF-8输入的一般策略/建议。

尽管我的web应用程序使用了UTF-8,但有些用户输入了无效字符。这会导致PHP的编码()中出现错误,总的来说,这似乎是一个不好的主意。

W3C I18N常见问题:多语言形式说:“如果接收到非UTF-8数据,应该返回错误消息。”

  • 在一个有几十个可以输入数据的不同地方的站点中,具体应该如何做到这一点呢?
  • 如何将错误以有用的方式呈现给用户?
  • 如何暂时存储和显示糟糕的表单数据,这样用户就不会丢失所有的文本?脱下坏角色?使用替换字符,以及如何使用?
  • 对于数据库中的现有数据,当检测到无效的UTF-8数据时,我应该尝试转换它并将其保存回(如何?编码,编码()?编码()?),还是将其保留为-在数据库中,但是正在做一些事情(什么?)在json_encode()之前?

我非常熟悉mbstring扩展,也不问“UTF-8在PHP中是如何工作的?”我希望在现实世界中有经验的人给我建议,他们是如何处理这件事的。

作为解决方案的一部分,我非常希望看到一个将无效字符转换为U+FFFD的快速方法。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2010-09-18 18:16:07

accept-charset="UTF-8"属性只是浏览器遵循的一个指南,它们不会被迫以这种方式提交。糟糕的表单提交机器人就是一个很好的例子..。

我通常通过iconv()或不太可靠的utf8_encode() / utf8_decode()函数忽略不好的字符。如果您使用iconv,您还可以选择音译坏字符。

下面是一个使用iconv()的示例

代码语言:javascript
运行
复制
$str_ignore = iconv('UTF-8', 'UTF-8//IGNORE', $str);
$str_translit = iconv('UTF-8', 'UTF-8//TRANSLIT', $str);

如果您想向您的用户显示错误消息,我可能会以一种全局的方式,而不是以每个接收到的值为基础。像这样的事情可能会做得很好:

代码语言:javascript
运行
复制
function utf8_clean($str)
{
    return iconv('UTF-8', 'UTF-8//IGNORE', $str);
}

$clean_GET = array_map('utf8_clean', $_GET);

if (serialize($_GET) != serialize($clean_GET))
{
    $_GET = $clean_GET;
    $error_msg = 'Your data is not valid UTF-8 and has been stripped.';
}

// $_GET is clean!

您还可能希望将新行和(非)可见控制字符标准化,如下所示:

代码语言:javascript
运行
复制
function Clean($string, $control = true)
{
    $string = iconv('UTF-8', 'UTF-8//IGNORE', $string);

    if ($control === true)
    {
            return preg_replace('~\p{C}+~u', '', $string);
    }

    return preg_replace(array('~\r\n?~', '~[^\P{C}\t\n]+~u'), array("\n", ''), $string);
}

代码从UTF-8转换为Unicode代码点:

代码语言:javascript
运行
复制
function Codepoint($char)
{
    $result = null;
    $codepoint = unpack('N', iconv('UTF-8', 'UCS-4BE', $char));

    if (is_array($codepoint) && array_key_exists(1, $codepoint))
    {
        $result = sprintf('U+%04X', $codepoint[1]);
    }

    return $result;
}

echo Codepoint('à'); // U+00E0
echo Codepoint('ひ'); // U+3072

它可能比任何其他选择都快,但是我还没有对它进行广泛的测试。

示例:

代码语言:javascript
运行
复制
$string = 'hello world�';

// U+FFFEhello worldU+FFFD
echo preg_replace_callback('/[\p{So}\p{Cf}\p{Co}\p{Cs}\p{Cn}]/u', 'Bad_Codepoint', $string);

function Bad_Codepoint($string)
{
    $result = array();

    foreach ((array) $string as $char)
    {
        $codepoint = unpack('N', iconv('UTF-8', 'UCS-4BE', $char));

        if (is_array($codepoint) && array_key_exists(1, $codepoint))
        {
            $result[] = sprintf('U+%04X', $codepoint[1]);
        }
    }

    return implode('', $result);
}

这可能就是你要找的。

票数 62
EN

Stack Overflow用户

发布于 2010-09-15 06:56:44

从web应用程序接收无效字符可能与为HTML表单假定的字符集有关。可以使用属性指定用于窗体的字符集。

代码语言:javascript
运行
复制
<form action="..." accept-charset="UTF-8">

您还可能需要查看Stack溢出上的类似问题,这些问题涉及如何处理无效字符(例如,列中右边的字符)的指针,但我认为,向用户发送错误信号比试图清除那些会导致重大数据意外丢失或用户输入意外更改的无效字符要好。

票数 4
EN

Stack Overflow用户

发布于 2010-09-21 16:03:33

我将一个相当简单的类放在一起,以检查输入是否在UTF-8中,并根据需要运行utf8_encode()

代码语言:javascript
运行
复制
class utf8
{

    /**
     * @param array $data
     * @param int $options
     * @return array
     */
    public static function encode(array $data)
    {
        foreach ($data as $key=>$val) {
            if (is_array($val)) {
                $data[$key] = self::encode($val, $options);
            } else {
                if (false === self::check($val)) {
                    $data[$key] = utf8_encode($val);
                }
            }
        }

        return $data;
    }

    /**
     * Regular expression to test a string is UTF8 encoded
     * 
     * RFC3629
     * 
     * @param string $string The string to be tested
     * @return bool
     * 
     * @link http://www.w3.org/International/questions/qa-forms-utf-8.en.php
     */
    public static function check($string)
    {
        return 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);
    }
}

// For example
$data = utf8::encode($_POST);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3715264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档