[英]How to replace/remove 4(+)-byte characters from a UTF-8 string in PHP?
注意:你不應該只是剝離,而是替換為替換字符 U+FFFD 以避免 unicode 攻擊,主要是 XSS:
http://unicode.org/reports/tr36/#Deletion_of_Noncharacters
preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $value);
由於 4 字節 UTF-8 序列始終以字節0xF0-0xF7
開頭,因此以下應該有效:
$str = preg_replace('/[\xF0-\xF7].../s', '', $str);
或者,您可以在 UTF-8 模式下使用preg_replace
,但這可能會更慢:
$str = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $str);
這是有效的,因為 4 字節 UTF-8 序列用於補充 Unicode 平面中的代碼點,從0x10000
開始。
下面是一個例子:
<?php
mb_internal_encoding("UTF-8");
//utf8 string, 13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP
$str = "qué \xF0\x9D\x92\xB3 tal";
$array = mbStringToArray($str);
print "str: [$str] strlen:" . strlen($str) . " chars:" . count($array) . "\n";
$str1 = "";
foreach($array as $c) {
// print "$c : " . strlen($c) ."\n";
$str1 .= strlen($c)<=3? $c : '?';
}
print "[$str1]\n";
function mbStringToArray ($str) {
if (empty($str)) return false;
$len = mb_strlen($str);
$array = array();
for ($i = 0; $i < $len; $i++) {
$array[] = mb_substr($str, $i, 1);
}
return $array;
}
或者,更緊湊和更高效:
<?php ///
mb_internal_encoding("UTF-8");
//utf8 string, 13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP
$str = "qué \xF0\x9D\x92\xB3 tal";
$str1 = trimOutsideBMP($str);
print "original: [$str]\n";
print "trimmed: [$str1]\n";
// Replaces non-BMP characters in the UTF-8 string by a '?' character
// Assumes UTF-8 default encoding ( if not sure, call first mb_internal_encoding("UTF-8"); )
function trimOutsideBMP($str) {
if (empty($str)) return $str;
$len = mb_strlen($str);
$str1 = '';
for ($i = 0; $i < $len; $i++) {
$c = mb_substr($str, $i, 1);
$str1 .= strlen($c) <= 3 ? $c : '?';
}
return $str1;
}
在嘗試解決我自己的問題時遇到了這個問題(Facebook 將某些表情符號吐出為 4 字節字符,Amazon Mechanical Turk 不接受 4 字節字符)。
我最終使用了這個,不需要 mbstring 擴展:
function remove_4_byte($string) {
$char_array = preg_split('/(?<!^)(?!$)/u', $string );
for($x=0;$x<sizeof($char_array);$x++) {
if(strlen($char_array[$x])>3) {
$char_array[$x] = "";
}
}
return implode($char_array, "");
}
下面的函數將 3 個和 4 個字節的字符從 utf8 字符串更改為“#”:
function remove3and4bytesCharFromUtf8Str($str) {
return preg_replace('/([\xF0-\xF7]...)|([\xE0-\xEF]..)/s', '#', $str);
}
這是我過濾掉 4 字節字符的實現
$string = preg_replace_callback(
'/./u',
function (array $match) {
return strlen($match[0]) >= 4 ? null : $match[0];
},
$string
);
您可以調整它並用一些替代字符串替換null
(刪除字符)。 您還可以用其他一些字節長度檢查替換>= 4
。
另一個過濾器實現,更復雜。
它嘗試轉寫為 ASCII 字符,否則會使用 unicode 替換字符來避免 XSS,例如: <a href='java\script:alert("XSS")'>
$tr = preg_replace_callback('/([\x{10000}-\x{10FFFF}])/u', function($m){
$c = iconv('ISO-8859-2', 'UTF-8',iconv('utf-8','ISO-8859-2//TRANSLIT//IGNORE', $m[1]));
if($c == '')
return '�';
return $c;
}, $s);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.