PHP输入过滤 - 检查ascii与检查utf8

时间:2009-10-30 02:13:59

标签: php utf-8 character-encoding ascii

我需要确保我的所有字符串都是utf8。检查来自用户的输入是ascii还是类似utf8会更好吗?

//KohanaPHP
function is_ascii($str) {
    return ! preg_match('/[^\x00-\x7F]/S', $str);
}

//Wordpress
function seems_utf8($Str) {
    for ($i=0; $i<strlen($Str); $i++) {
        if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
        elseif ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
        elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
        elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
        elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
        elseif ((ord($Str[$i]) & 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 == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80))
            return false;
        }
    }
    return true;
}

我对100个字符串进行了一些基准测试(一半有效的utf8 / ascii,一半没有),发现seem_utf8()任务为0.011,而is_ascii只需要0.001。但我的直觉告诉我,你得到的是你付出的代价,而utf8检查将是一个更好的选择。

我打算做一些像这样的转换。

<?php

/* Example data */
$string[] = 'hello';
$string[] = 'asdfghjkl;qwertyuiop[]\zxcvbnm,./]12345657890-=+_)(*&^%$#@!';
$string[] = '';
$string[] = 'accentué';
$string[] = '»á½µÎ½Ï‰Î½ Ï„á½° ';
$string[] = '???R??=8 ????? ++++¦??? ???2??????';
$string[] = 'hello¦ùó 5/5¡45-52ZÜ¿»'. "0x93". octdec('77'). decbin(26). "F???pp?? ??? ". '»á½µÎ½Ï‰Î½ Ï„á½° ';


$time = microtime(true);

//Count the successes
$true = array(1 => 0, 0 => 0);

foreach($string as $s) {
    $r = seems_utf8($s);    //0.011

    print_pre(mb_substr($s, 0, 30). ' is '. ($r ? 'UTF-8' : 'non-UTF-8'));


    if( ! $r ) {

        $e = mb_detect_encoding($s, "auto");

        print_pre('Encoding: '. $e);

        //Convert
        $s = iconv($e, 'UTF-8//TRANSLIT', $s);

        print_pre(mb_substr($s, 0, 30). ' is now '. (seems_utf8($s) ? 'valid' : 'not'). ' UTF-8');
    }

}

print_pre($true);
print_pre((microtime(TRUE) - $time). ' seconds');

function print_pre() { print '<pre>'; print_r(func_get_args()); print '</pre>'; }

4 个答案:

答案 0 :(得分:1)

根据性能在ASCII和UTF8之间进行选择可能是错误的方法。答案真的取决于你的用例。如果您的字符串需要支持国际化,那么您很可能使用UTF8。如果您的网站只有英文版,您可以使用ASCII。或者你仍然可以使用UTF8。无论您选择什么,它都应该与您为所提供的HTML表单设置的字符编码相匹配,以征求用户的意见。

答案 1 :(得分:1)

我不确定这种方法的必要部分是多少。如果你要求用户输入UTF-8,他们会给你“其他东西”扔掉它然后再问。

各种字符集检测功能普遍存在(并且悲惨地,必然地)不完美。 MB库中的那些以及iconv中的那些与那里的一些东西相比甚至都不是那么先进。 mb_detect_encoding基本上遍历一个字符集列表并返回第一个使其具有的字符串看起来有效的字符集。在这个时代,可能有几个会返回true(这就是为什么通过mb_detect_order()公开排序的原因)。

确保您的网页提供正确的HTTP&amp; HTML字符集声明,浏览器应该返回相同的数据。更具体的是在表单标记中包含accept-charset声明。我还没有发现一个被忽略但不代表攻击的案例。

要检查字节流的编码,只需使用mb_check_encoding()。

答案 2 :(得分:0)

我假设你正在做的是在执行之前检查iconv是否必要?

如果您不希望频繁出现非ASCII字符,那么is_ascii似乎是最有效的方法。只有当&gt;触发iconv时才需要触发。遇到了7位字符。

如果检查的字符串中可能存在高位字符,那么seem_utf8可能更有效,除非还存在高频率但非UTF8字符的高频率,否则您需要更少地调用iconv。

答案 3 :(得分:-1)

如果您只是想保护您的输入以便他们只接受UTF-8,我认为您可以使用mb_check_encoding。像这样:

if(!mb_check_encoding($input, 'UTF-8'){
  die('Non UTF-8 character found');
}

应该足以拒绝任何无效的输入。