MySQLのようです サポートしていません デフォルトのUTF-8文字セットに3バイトを超える文字が含まれています。
では、PHPで、文字列内の4(以上)バイトの文字をすべて削除して、他の文字のようなものに置き換えるにはどうすればよいですか?
注:Unicode攻撃、主にXSSを回避するために、単に削除するだけでなく、置換文字U + FFFDに置き換える必要があります。
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);
これが機能するのは、0x10000
で始まる補足Unicodeプレーンのコードポイントに4バイトのUTF-8シーケンスが使用されているためです。
次に例を示します。
<?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;
}
以下の関数は、3バイトと4バイトの文字をutf8文字列から「#」に変更します。
function remove3and4bytesCharFromUtf8Str($str) {
return preg_replace('/([\xF0-\xF7]...)|([\xE0-\xEF]..)/s', '#', $str);
}
私自身の問題を解決しようとしたときにこの質問に出くわしました(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, "");
}
これが4バイト文字を除外するための私の実装です
$string = preg_replace_callback(
'/./u',
function (array $match) {
return strlen($match[0]) >= 4 ? null : $match[0];
},
$string
);
それを微調整して、null
(文字を削除する)を代替文字列に置き換えることができます。 >= 4
を他のバイト長チェックに置き換えることもできます。