2009-10-30 1 views
1

모든 문자열이 utf8인지 확인해야합니다. 사용자로부터 오는 입력이 ascii와 유사하거나 utf8과 같은지 확인하는 것이 더 낫지 않습니까?PHP 입력 필터링 - 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; 
} 

나는 (안 절반 유효 UTF8/아스키 반) 100 개 문자열에 대한 몇 가지 벤치마킹을했고 is_ascii은 0.001을 취하면서 그 seems_utf8() 작업 0.011을 발견했다. 하지만 내 직감은 당신이 지불하는 것을 얻고 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>'; } 
+0

UTF8은 기본 US-ASCII 코드 평면에 대해 말할 때 _exactly_ ASCII와 동일합니다. – jason

+0

예, 유효하지 않은 ASCII가 있는지 확인하는 것이 영어 이외의 인코딩을 본격적인 UTF-8에서 빠르게 호출하는 방법입니다. – Xeoncross

+0

첫 번째 함수는 문자열이 유효한 UTF-8인지 확인하지 않습니다. – Gumbo

답변

1

이 방법의 필요한 부분을 잘 모르겠습니다. 사용자에게 UTF-8 입력을 요청하면 "다른 것"을주고 멀리 던져서 다시 묻습니다.

다양한 문자 세트 감지 기능이 보편적으로 (그리고 비극적으로 필연적으로) 불완전합니다. MB 라이브러리에있는 것들과 iconv에있는 것들은 거기에있는 것들 중 일부에 비해서 고급스럽지 않습니다. mb_detect_encoding은 기본적으로 문자 집합 목록을 반복하고, 그 문자열이 손에 든 것처럼 보이는 첫 번째 문자 집합을 반환합니다. 이 시대에는 아마 여러 개가 true를 반환 할 것입니다 (mb_detect_order()를 통해 순서가 표시되는 이유).

페이지에 올바른 HTTP & HTML 문자 집합 선언이 제공되는지 확인하고 브라우저는 동일한 데이터를 반환해야합니다. 추가로 지정하려면 양식 태그에 accept-charset 선언을 포함시킵니다. 나는 공격이 아니라는 것을 무시한 경우를 아직 발견하지 못했다.

바이트 스트림의 인코딩을 확인하려면 mb_check_encoding()을 사용하면됩니다.

+0

예, 대부분이 질문에 대한 공격 사례가 걱정됩니다. 따라서 문자열이 유효한 ASCII 또는 utf-8이라는 사실을 알지 못하면 일부 문자열 처리 함수에 위험 할 수 있습니다. 하지만 내가 그것을 확인하지 않으면 그것이 유효하지 않다는 것을 어떻게 알 수 있습니까? – Xeoncross

0

나는 당신이하고있는 일은 iconv가 실행되기 전에 필요하다고 확인하는 것입니다.

비 ASCII 문자가 자주 출현하지 않는다면 is_ascii는 가장 효율적인 접근 방법입니다. iconv는> 7 비트 문자가있는 경우에만 트리거되어야합니다.

확인 된 문자열에 상위 비트 문자가 포함될 가능성이있는 경우, seem_utf8이 더 효율적일 수 있습니다. 상위 비트이지만 UTF8이 아닌 문자가 높은 경우가 아니면 iconv를 훨씬 덜 호출해야합니다 .

+0

몇 가지 예제 코드로 내 질문을 업데이트했습니다. – Xeoncross

1

성능에 따라 ASCII와 UTF8 중 하나를 선택하는 것은 잘못된 방법입니다. 대답은 실제로 유스 케이스에 달려있다. 문자열이 국제화를 지원해야하는 경우 UTF8을 사용하는 것이 가장 좋습니다. 귀하의 사이트가 영어로만 구성된 경우 ASCII로 갈 수도 있습니다. 또는 UTF8과 함께 할 수도 있습니다. 선택한 내용은 사용자 입력을 요청하는 HTML 양식에 대해 설정 한 문자 인코딩과 일치해야합니다.

-1

단지 입력을 보호하여 UTF-8 만 허용하려는 경우 mb_check_encoding을 사용할 수 있습니다. 다음과 같이 입력하십시오.

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

은 잘못된 입력을 거부하기에 충분해야합니다.

+0

일부 비 UTF-8 데이터가 내 사이트에 생성 된 경우에도 계속 지원하고 싶습니다. 99 %의 시간이 공격 일 뿐이지 만, 이상한 장치의 누군가는 UTF-8을 보낼 수 없습니다. – Xeoncross

+0

@Arkh 인코딩 유형으로 인해 모든 응용 프로그램이 종료됩니까? –