簡體   English   中英

PHP輸入過濾-檢查ascii與檢查utf8

[英]PHP input filtering - checking ascii vs checking utf8

我需要確保我所有的字符串都是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,另一半沒有),發現似乎sees_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>'; }

根據性能在ASCII和UTF8之間進行選擇可能是錯誤的方法。 答案確實取決於您的用例。 如果您的字符串需要支持國際化,則很可能會使用UTF8。 如果您的站點僅是英語,則可以使用ASCII。 也許您仍然選擇UTF8。 無論您選擇什么,它都應該與為服務於HTML表單設置的字符編碼相匹配,以請求用戶輸入。

我不確定這種方法的必要性。 如果您要求用戶提供UTF-8輸入,並且他們給您“其他”信息,請將其丟棄並再次詢問。

那里的各種字符集檢測功能普遍(並且很可悲地是)不完善。 與庫中的某些內容相比,MB庫中的內容以及iconv中的內容都沒有那么先進。 mb_detect_encoding基本上會遍歷一個字符集列表,並返回第一個字符集,從而使它手中的字符串看起來有效。 在當今時代,可能會有幾個返回true(這就是為什么通過mb_detect_order()公開順序的原因)。

確保為您的頁面提供了正確的HTTP和HTML字符集聲明,並且瀏覽器應以相同的方式返回數據。 具體而言,在表單標簽中包含accept-charset聲明。 我還沒有發現忽略這種情況並不代表攻擊的情況。

要檢查字節流的編碼,只需使用mb_check_encoding()。

我假設您正在執行的操作是在執行iconv之前檢查它是否必要?

如果您不希望出現非常頻繁的非ASCII字符,則is_ascii似乎是最有效的方法。 iconv僅在遇到> 7位字符時才需要觸發。

如果在檢查的字符串中可能有高位字符,則似乎see_utf8會更有效,您將需要更少地調用iconv,除非也有高頻率的高位字符但非UTF8字符。

如果您只是想保護您的輸入,使其僅接受UTF-8,我想您可以使用mb_check_encoding 像這樣的東西:

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

應該足以拒絕任何無效輸入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM