我想确保我知道的一切有关UTF-8是正确的。 我一直在想现在使用UTF-8一段时间,但我一直在更多和更多的bug和其他怪异的东西,使它看起来几乎不可能有100%的UTF-8网站绊脚石。 总有一种疑难杂症的地方,我似乎错过。 也许有人在这里可以纠正我的列表或OK,所以我不会错过任何重要的。
数据库
每个网站都有一些地方保存有数据。 不管你的PHP设置是什么,你还必须配置DB。 如果您无法访问配置文件,然后确保尽快您连接“ 集名称‘UTF8’”。 此外,请务必使用utf8_ UNICODE_ CI对所有表的。 这是假定MySQL的数据库,你将不得不改变别人。
正则表达式
我做的正则表达式的很多是更复杂的比一般的搜索替换。 我一定要记得使用“/ U”修饰符让PCRE不会破坏我的琴弦 。 然而,即使这样,也有仍然存在问题明显 。
字符串函数
所有的默认字符串函数(strlen的(),strpos()等),应改为多字节字符串函数是看角色,而不是字节。
头你应该确保你的服务器返回的浏览器知道你要使用(就像你必须告诉MySQL)什么字符集正确的标题。
报头( '内容类型:文本/ HTML;字符集= UTF-8');
这也是把正确的<meta>标签页面中的头一个好主意。 虽然实际的头将覆盖本应他们不同。
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
问题
我需要,我从用户代理接收(HTML表单和URI)为UTF-8一切转换页面加载时或者如果我可以离开琴弦/值,因为它们仍然通过这些功能没有问题,运行它们?
如果我需要的一切UTF-8转换 - 那么我应该采取什么措施? mb_detect_encoding似乎为此要建,但我不断看到人们抱怨说,它并不总是奏效。 mb_check_encoding似乎也告诉从畸形一个良好的UTF-8字符串的问题。
(; VS和在HTML像&AMP)不同,具体取决于编码它使用(如文件类型),或者它仍然保存像某些字符被不同的解释经常刺痛是否在内存PHP存储字符串。 chazomaticus回答了这个问题:
在PHP(高达PHP5,无论如何),字符串只是字节序列。 有没有与之相关的明示或暗示的字符集; 这件事情的程序员必须跟踪。
如果给一个非UTF-8字符串到MB_ *功能它都不会产生问题?
如果UTF串编码错误意志的东西出问题(如在正则表达式解析错误?),或者将它只是标志着一个实体为差(HTML)? 是否有过不正当地编码字符串将导致函数返回FALSE,因为该字符串是坏的机会吗?
我听说你要标记您的形式为UTF-8也(接收字符=“UTF-8”),但我不知道的好处是什么..?
在UTF-16编写的,以解决UTF-8是否有限制? 像做了UTF-8用完的字符空间? (Y2(UTF)K?)
功能
这里有一对夫妇的我已经找到了自定义的PHP函数,但我没有任何办法来验证他们的实际工作。 也许有人有,我可以用一个例子。 第一是convertToUTF8() ,然后从WordPress的seems_utf8。
function seems_utf8($str) {
$length = strlen($str);
for ($i=0; $i < $length; $i++) {
$c = ord($str[$i]);
if ($c < 0x80) $n = 0; # 0bbbbbbb
elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
else return false; # Does not match any model
for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
return false;
}
}
return true;
}
function is_utf8($str) {
$c=0; $b=0;
$bits=0;
$len=strlen($str);
for($i=0; $i<$len; $i++){
$c=ord($str[$i]);
if($c > 128){
if(($c >= 254)) return false;
elseif($c >= 252) $bits=6;
elseif($c >= 248) $bits=5;
elseif($c >= 240) $bits=4;
elseif($c >= 224) $bits=3;
elseif($c >= 192) $bits=2;
else return false;
if(($i+$bits) > $len) return false;
while($bits > 1){
$i++;
$b=ord($str[$i]);
if($b < 128 || $b > 191) return false;
$bits--;
}
}
}
return true;
}
如果有人有兴趣,我发现一个很好的例子,页面中使用测试UTF-8时 。
我需要,我从用户代理(HTML表单和URI)接收到UTF-8的页面加载时,一切都转换
号用户代理应在UTF-8格式提交数据; 如果不是你失去的Unicode的利益。
确保用户代理的方式在UTF-8格式提交是服务包含它提交的UTF-8编码形式的网页。 (如果你打算要保存的表单和工作的独立和META HTTP-当量太)使用Content-Type头。
我听说你要标记您的形式为UTF-8也(接收字符=“UTF-8”)
别。 这是在HTML标准的一个不错的主意,但IE从来没有得到它的权利。 它应该说明允许的字符集的独家名单,但IE浏览器将其视为额外的字符集列表尝试,在每场的基础。 所以,如果你有一个ISO-8859-1页和“接收字符=‘UTF-8’”的形式,IE将首先尝试一个字段编码为ISO-8859-1,如果有一个非8859-1性格在里面, 那么它就会采取UTF-8。
但由于IE不告诉你它是否已使用ISO-8859-1或UTF-8,这是完全没有用你。 你将不得不猜测,分别为每个字段,其编码是在使用! 没有用。 忽略属性并为您的网页为UTF-8; 这就是你可以在瞬间做到最好。
如果UTF串编码错误意志的东西出问题
如果让这样的序列打通,你可能会遇到麻烦的浏览器。 有“超长序列”编码以字节为单位的长序列比所需的低编号的码点。 这意味着如果你正在过滤“<”通过寻找字节序列ASCII字符,你可能会错过一个,让一个脚本元素插入你认为是安全的文本内容。
超长序列中的Unicode初期被禁止回,但它采取了微软一个很长的时间来得到他们的狗屎在一起:IE会解释字节序列“\ XC0 \命苦”为“<”,直到IE6的Service Pack 1。 Opera还听错了高达(约,我认为)版本7幸运的是,这些旧的浏览器消亡,但它仍然是值得的情况下,过滤超长序列这些浏览器仍然对,现在(或新的白痴浏览器犯同样的错误在未来)。 你可以这样做,并修复等不良序列,用正则表达式只允许适当的UTF-8通过,比如这一个从W3。
如果您在PHP中使用MB_功能,你可以从这些问题绝缘。 我不能肯定地说是MB_ *是不可用的脆弱,当我还在写PHP。
在任何情况下,这也是很好的时间以除去控制字符,这是错误的一个大的,通常赏识源。 我会从除W3正则表达式取出别人提交的字符串中删除字符9和13; 这也是值得您知道是不是应该多字符串文本框除去纯换行。
在UTF-16编写的,以解决UTF-8是否有限制?
不,UTF-16是这是我们用来做索引的Unicode字符串容易内存(从天,当所有的Unicode的能装下两个字节两个字节的每码点编码,如Windows和Java系统仍然这样做的)。 不同于UTF-8是不与ASCII兼容,并且是小到没有在Web上使用。 但是你偶尔满足它保存的文件,通常由Windows用户保存的谁被误导的UTF-16LE的视窗的描述为“Unicode的”另存为菜单。
seems_utf8
相比于正则表达式,这是非常低效的!
此外,一定要对所有表的使用utf8_unicode_ci。
实际上,你可以有点侥幸没有这个,处理MySQL作为也不过字节的存储和只有它们解释为脚本中的UTF-8。 使用utf8_unicode_ci的优点是,它会整理(排序和不区分大小写的比较)与有关非ASCII字符的知识,所以如。 “R”和“R”是相同的字符。 如果您使用非UTF8归类你应该坚持二进制(区分大小写)匹配。
无论选择哪种方式,做到始终如一:使用相同的字符集为你的表,因为你的连接做的。 要避免什么是你的脚本和数据库之间的有损字符集转换。
大多数时候,你现在在做什么,应该是正确的。
一些注意事项:任何utf_*
在MySQL整理会正确地存储你的数据为UTF-8,它们之间唯一的区别是排序时核对(排名不分先后)应用。
你可以告诉Apache和PHP发出正确的字符集设置标题AddDefaultCharset utf-8
在httpd.conf /的.htaccess和default_charset = "utf-8"
分别在php.ini。
你可以告诉mbstring扩展采取的字符串函数的照顾。 这对我的作品:
mbstring.internal_encoding=utf-8
mbstring.http_output=UTF-8
mbstring.encoding_translation=On
mbstring.func_overload=6
(这留下的mail(
)函数不变-我发现它设置为7打乱了我的邮件标题)
对于字符集转换看一看https://sourceforge.net/projects/phputf8/ 。
PHP并不关心在所有关于什么是在变量,它只是存储和检索盲目的内容。
你将有意想不到的结果,如果你宣布一个mbstring.internal_encoding
和供应到另一个编码一个MB_ *函数字符串。 您可以安全地反正发送ASCII为UTF-8的功能。
如果你担心有人故意发布不正确编码的东西,我相信你768,16考虑HTML纯化的圆弧加工之前过滤GET / POST数据。
Accept-charset
,因为永远一直在规格,但其在浏览器中真实世界的支持或多或少是零。 浏览器将tipically使用的编码自动对焦包含表单的页面。
UTF-16是不是UTF-8的老大哥,它只是用于不同的用途。
数据库/ MySQL的:如果你使用SET NAMES
和如PHP / MySQL的你要离开mysql_real_escape_string()在黑暗中关于字符编码的变化。 这可能会导致错误的结果。 所以,如果你是依靠像mysql_real_escape_string转义功能(因为你没有使用预处理语句) SET NAMES
是一个次优解。 这就是为什么mysql_set_charset()已经出台或者为什么Gentoo的应用补丁,增加的配置参数mysql.connect_charset两个PHP / MySQL和PHP / mysqli的。
客户通常并不表示它发送的参数编码。 如果您预计UTF-8编码的数据有可能是编码错误(在UTF-8无效字节序列)。 因此,如预期的数据可能无法正常显示或解析器可以中止解析。 但至少在用户输入无法“逃离”和内嵌SQL语句或HTML输出做更多的伤害如。 如采取脚本(保存为ISO-8859-1或UTF-8,无所谓)
<?php
$s = 'abcxyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));
// adding the byte sequence for äöü in iso-8859-1
$s = 'abc'. chr(0xE4) . chr(0xF6) . chr(0xFC). 'xyz';
var_dump(htmlspecialchars($s, ENT_QUOTES, 'utf-8'));
版画
string(6) "abcxyz"
string(0) ""
E4F6FC不是有效的UTF-8字节序列,因此用htmlspecialchars返回空字符串。 其他功能可能返回? 或另一种“特殊”的字符。 但至少他们不会“错误”的字符为非法控制字符 - 只要他们都坚持“正确”的编码(UTF-8在这种情况下)。
接收字符并不能保证你只会得到的数据与该编码。 对于所有你知道的甚至可能不会有“使用”客户端/解析包含表单元素的HTML文档。 它可以帮助,而且也没有理由你不应该设置该属性。 但它不是“可靠”。
UTF-8是好的,并且不具有UTF-16解决了任何限制。 PHP好好尝试一下改变它的方式来存储字符串内存(不像Python的)。 如果整个数据流是使用UTF-8(网络形式的接收UTF-8的数据,表格使用UTF8编码和你使用的SET NAMES utf8
,以及数据存储没有被改变(没有字符集转换),这应该是罚款。
从形式我这个属性添加到我的用户输入的form
s个标签: accept-charset="utf-8"
。 这个你收到这样的数据应是UTF-8编码。