Фильтрация ввода PHP - проверка ascii против проверки utf8 - PullRequest
1 голос
/ 30 октября 2009

Мне нужно убедиться, что все мои строки - 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 и половина нет) и обнаружил, что кажется, что _tf8 () выполняет задачи 0,011, а is_ascii - только 0,001 Но моя интуиция говорит мне, что вы получаете то, за что платите, и проверка utf8 была бы лучшим выбором.

Я планирую сделать что-то вроде этого.

<code><?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 '
'; }

Ответы [ 4 ]

1 голос
/ 30 октября 2009

Выбор между ASCII и UTF8 на основе производительности, вероятно, является неправильным подходом. Ответ действительно зависит от вашего варианта использования. Если ваша строка должна поддерживать интернационализацию, скорее всего, вы используете UTF8. Если ваш сайт только на английском языке, вы можете использовать ASCII. Или, может быть, вы все еще ходите с UTF8. Что бы вы ни выбрали, оно, вероятно, должно соответствовать кодировке символов, заданной вами для формы HTML, которую вы используете для запроса ввода от вашего пользователя.

1 голос
/ 06 декабря 2009

Я не уверен, насколько необходимые части этого подхода. Если вы попросите пользователя ввести UTF-8, и он даст вам «что-то еще», выбросьте его и спросите снова.

Различные функции обнаружения наборов символов универсально (и трагически, обязательно) несовершенны. Те, что в библиотеке MB, так же, как и в iconv, даже не настолько продвинуты по сравнению с некоторыми вещами, которые там есть. Mb_detect_encoding в основном выполняет итерацию по списку наборов символов и возвращает первый, который делает имеющуюся в нем строку выглядящей корректной. Вероятно, в наши дни некоторые из них вернут true (именно поэтому порядок выставляется через mb_detect_order ()).

Убедитесь, что на ваших страницах указаны правильные объявления набора символов HTTP и HTML, и браузеры должны возвращать данные в том же виде. Чтобы быть более конкретным, включите в ваш тег формы объявление accept-charset. Я еще не обнаружил случай, когда это было проигнорировано, что не представляло собой атаку.

Чтобы проверить кодировку байтового потока, вы можете просто использовать mb_check_encoding ().

0 голосов
/ 07 декабря 2009

Если вы просто пытаетесь защитить свои входы, чтобы они принимали только UTF-8, я думаю, вы можете просто использовать mb_check_encoding . Примерно так:

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

должно быть достаточно, чтобы отклонить любой неверный ввод.

0 голосов
/ 30 октября 2009

Я предполагаю, что вы проверяете, что iconv необходим перед выполнением?

Если вы не ожидаете очень частого появления символов, отличных от ASCII, тогда is_ascii кажется наиболее эффективным подходом. Iconv нужно будет запускать только в том случае, если встретится> 7-битный символ.

Если в проверяемой строке, скорее всего, присутствуют высокобитовые символы, то может быть, кажется, будет более эффективен visible_utf8, вам нужно будет вызывать iconv намного реже, если также нет высокой частоты высокобитных, но не UTF8 символов.

...