我正在寻找一个关于如何处理来自用户的无效UTF-8输入的一般策略/建议。
尽管我的web应用程序使用了UTF-8,但有些用户输入了无效字符。这会导致PHP的编码()中出现错误,总的来说,这似乎是一个不好的主意。
W3C I18N常见问题:多语言形式说:“如果接收到非UTF-8数据,应该返回错误消息。”
我非常熟悉mbstring扩展,也不问“UTF-8在PHP中是如何工作的?”我希望在现实世界中有经验的人给我建议,他们是如何处理这件事的。
作为解决方案的一部分,我非常希望看到一个将无效字符转换为U+FFFD的快速方法。
发布于 2010-09-18 18:16:07
accept-charset="UTF-8"
属性只是浏览器遵循的一个指南,它们不会被迫以这种方式提交。糟糕的表单提交机器人就是一个很好的例子..。
我通常通过iconv()
或不太可靠的utf8_encode()
/ utf8_decode()
函数忽略不好的字符。如果您使用iconv
,您还可以选择音译坏字符。
下面是一个使用iconv()
的示例
$str_ignore = iconv('UTF-8', 'UTF-8//IGNORE', $str);
$str_translit = iconv('UTF-8', 'UTF-8//TRANSLIT', $str);
如果您想向您的用户显示错误消息,我可能会以一种全局的方式,而不是以每个接收到的值为基础。像这样的事情可能会做得很好:
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!
您还可能希望将新行和(非)可见控制字符标准化,如下所示:
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代码点:
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
它可能比任何其他选择都快,但是我还没有对它进行广泛的测试。
示例:
$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);
}
这可能就是你要找的。
发布于 2010-09-15 06:56:44
从web应用程序接收无效字符可能与为HTML表单假定的字符集有关。可以使用属性指定用于窗体的字符集。
<form action="..." accept-charset="UTF-8">
您还可能需要查看Stack溢出上的类似问题,这些问题涉及如何处理无效字符(例如,列中右边的字符)的指针,但我认为,向用户发送错误信号比试图清除那些会导致重大数据意外丢失或用户输入意外更改的无效字符要好。
发布于 2010-09-21 16:03:33
我将一个相当简单的类放在一起,以检查输入是否在UTF-8中,并根据需要运行utf8_encode()
:
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);
https://stackoverflow.com/questions/3715264
复制相似问题