我有一个用户将文本输入表单的应用程序。
将数据保存到MySQL数据库中(排序规则:utf8_general_ci
),然后以XML格式输出(编码:UTF-8)。
问题是人们倾向于从其他来源剪切和粘贴他们的信息,例如,Microsoft Word文档或PDF。
此输入文本通常包含输出编码不正确的字符,例如“智能引号”,来自Windows-1252 encoding
中的文档这显然会导致转换或处理XML时出现问题,因为这些字符是非法的。
那么,如何消毒输入?
以前,我使用了一些相当强力的方法,例如"de-moronize" script,它包含一长串搜索和替换操作。
这仍然是最好的方法吗?还有其他方法吗?
我可以在表单上设置accept-charset attribute并让浏览器为我执行此操作吗?
如果是这样,哪些浏览器会这样做并且可能存在任何问题?
另外,为什么我的数据库接受这些字符,这些字符是UTF-8中的保留/控制字符?
正如你所看到的,我对编码了解得足以知道我有问题,但我现在有点超出我的深度......
TIA
答案 0 :(得分:9)
此输入文本通常包含输出编码不正确的字符,例如“智能引号”,来自Windows-1252编码的文档
“智能引号”(cp1252中的字节147和148)是完全有效的Unicode字符,U + 201C和U + 201D。您的应用程序应该能够无缝地处理它们;如果没有,你做错了,很可能所有非ASCII字符都会失败。
无论字符是来自某人键入它们还是从Word中粘贴它们的人,浏览器都应该向您的应用程序提交UTF-8编码的字符,这应该将相同的UTF-8字节存储到数据库中。
如果浏览器未以UTF-8提交,则您可能无法设置包含该表单的HTML页面的字符集。这可以使用:
完成Content-Type: text/html;charset=utf-8
HTTP标头和/或:
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
&lt; head&gt;中的元素。
我可以在表单上设置accept-charset属性并让浏览器为我做这个吗?
不,由于IE的缘故,accept-charset基本没用,它误解了它意味着“如果页面上的那个不能编码我们想要的字符,请尝试使用这个字符集”,而不是“总是使用这个字符集”。这意味着如果你使用accept-charset,你最终可能会同时提交一系列编码,而无法弄清楚哪个是哪个。尼斯!
我的数据库是如何接受这些字符的,这些字符是UTF-8中的保留/控制字符?
在MySQL中,UTF-8只是一种排序规则,用于比较和排序。它仍然将数据存储为字节,并不关心它们是否不是有效的UTF-8序列。
最好在你的应用程序中解码和检查传入的UTF-8序列,因为现代Unicode中无效的“短序列”可以隐藏旧的浏览器仍然可以识别的'&lt;'字符(at至少IE6之前的SP2,Opera 7)。
ETA:
所以,我输入了一个包含字节146的字符串
不,您输入了Unicode字符U + 201B。浏览器处理Unicode字符,而不是字节,直到它必须将序列化表单提交给服务器。然后它决定如何将字符转换为字节,如果页面被处理为UTF-8,它将始终选择UTF-8。
(如果它不是UTF-8,浏览器倾向于以不符合标准的方式作弊:对于所有不适合编码的字符,它会将它们编码为HTML字符引用,如'&amp;# 8217;'。这是错误的,因为你现在无法区分浏览器转义的'&amp;'和真实的,用户输入的'&amp;'之间的区别,而且它是隐蔽的错误,因为如果你然后回应未转义的引用HTML看起来你说得对,事实上你刚刚做了一个很大的安全漏洞。)
它作为146
进入数据库
真的,'\ x92'字节,不是'\ xC2 \ x92','\ xE2 \ x80 \ x99'或'&amp;#146;'?
当我制作(UTF-8编码的)XML时,它就出现了146.没有来自浏览器的投诉
然后它没有作为单个146字节出现。当在XML文件中给出“\ x92”时,浏览器会抱怨。 (不是HTML文件,其中无效的UTF-8序列作为缺失字符字形出现。)
我怀疑它是作为'&amp;#146;'字符引用出现的,它是格式良好的(尽管字符U + 0092是C1控件集的一部分,因此不会呈现为任何有用的东西) 。如果这是正在发生的事情,那么您的表单页面毕竟不会被选为UTF-8,并且您正遭受上述浏览器自动转义提交问题。
答案 1 :(得分:2)
您可以尝试使用Perl Encode模块。它支持多个字符集之间的转换,包括couse的UTF-8。我刚刚检查了我的Perl安装,它也支持“cp1252”,根据维基百科,它只是Windows-1252的另一个名称。您可以使用以下一个班轮检查自己的安装:
perl -MEncode -e 'print map {"$_\n"} Encode->encodings(":all");'
答案 2 :(得分:1)
“我可以在表单上设置accept-charset属性并让浏览器为我做这个吗?”
只有当你准备信任“浏览器”时 - 这可能适用于某些应用程序,但总的来说,它会让你自己大肆恶作剧(或更糟)。
(另见bobince关于IE的警告......)
伊恩