mb_detect_encoding

(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)

mb_detect_encoding检测字符编码

说明

mb_detect_encoding(string $string, array|string|null $encodings = null, bool $strict = false): string|false

从一个有序的候选列表中检测 string string 的最可能字符编码。

自动检测预期的字符编码永远不可能完全可靠;如果没有一些额外信息,它类似于在没有密钥的情况下解码加密字符串。始终优先使用与数据一起存储或传输的字符编码指示,例如 "Content-Type" HTTP 标头。

此函数对于多字节编码最为有用,其中并非所有字节序列都形成有效的字符串。如果输入字符串包含这样的序列,则该编码将被拒绝,并检查下一个编码。

参数

string

要检查的 string

encodings

要尝试的字符编码列表,按顺序排列。该列表可以指定为字符串数组或以逗号分隔的单个字符串。

如果省略 encodings 或为 null,将使用当前的 detect_order(使用 mbstring.detect_order 配置选项或 mb_detect_order() 函数设置)。

strict

控制当 string 在列出的 encodings 中任何一个都不有效时的行为。如果 strict 设置为 false,将返回最接近的匹配编码;如果 strict 设置为 true,将返回 false

strict 的默认值可以使用 mbstring.strict_detection 配置选项设置。

返回值

检测到的字符编码,如果字符串在列出的任何编码中都不有效,则为 false

变更日志

版本 说明
8.2.0 mb_detect_encoding() 将不再返回以下非文本编码:"Base64""QPrint""UUencode""HTML entities""7 bit""8 bit"

范例

范例 #1 mb_detect_encoding() 范例

<?php
// 使用当前 detect_order 检测字符编码
echo mb_detect_encoding($str);

// "auto" 将根据 mbstring.language 展开
echo mb_detect_encoding($str, "auto");

// 通过以逗号分隔的列表指定 "encodings" 参数
echo mb_detect_encoding($str, "JIS, eucjp-win, sjis-win");

// 使用数组指定 "encodings" 参数
$encodings = [
"ASCII",
"JIS",
"EUC-JP"
];
echo
mb_detect_encoding($str, $encodings);
?>

范例 #2 strict 参数的效果

<?php
// 'áéóú' 以 ISO-8859-1 编码
$str = "\xE1\xE9\xF3\xFA";

// 该字符串在 ASCII 或 UTF-8 中无效,但 UTF-8 被认为更接近
var_dump(mb_detect_encoding($str, ['ASCII', 'UTF-8'], false));
var_dump(mb_detect_encoding($str, ['ASCII', 'UTF-8'], true));

// 如果找到有效的编码,strict 参数不会改变结果
var_dump(mb_detect_encoding($str, ['ASCII', 'UTF-8', 'ISO-8859-1'], false));
var_dump(mb_detect_encoding($str, ['ASCII', 'UTF-8', 'ISO-8859-1'], true));
?>

上面的例子将输出

string(5) "UTF-8"
bool(false)
string(10) "ISO-8859-1"
string(10) "ISO-8859-1"

在某些情况下,相同的字节序列可能在多个字符编码中形成有效的字符串,并且无法知道哪个解释是预期的。例如,在许多其他情况中,字节序列 "\xC4\xA2" 可以是

  • "Ä¢"(U+00C4 带分音符的拉丁大写字母 A 后跟 U+00A2 美分符号)以 ISO-8859-1、ISO-8859-15 或 Windows-1252 编码
  • "ФЂ"(U+0424 西里尔大写字母 EF 后跟 U+0402 西里尔大写字母 DJE)以 ISO-8859-5 编码
  • "Ģ"(U+0122 带撇号的拉丁大写字母 G)以 UTF-8 编码

范例 #3 当多个编码匹配时的顺序影响

<?php
$str
= "\xC4\xA2";

// 该字符串在所有三个编码中都有效,因此将返回第一个列出的编码
var_dump(mb_detect_encoding($str, ['UTF-8', 'ISO-8859-1', 'ISO-8859-5']));
var_dump(mb_detect_encoding($str, ['ISO-8859-1', 'ISO-8859-5', 'UTF-8']));
var_dump(mb_detect_encoding($str, ['ISO-8859-5', 'UTF-8', 'ISO-8859-1']));
?>

上面的例子将输出

string(5) "UTF-8"
string(10) "ISO-8859-1"
string(10) "ISO-8859-5"

参见

添加注释

用户贡献的注释 26 个注释

85
Gerg Tisza
13 年前
如果尝试使用 mb_detect_encoding 检测字符串是否为有效的 UTF-8,请使用严格模式,否则它几乎毫无用处。

<?php
$str
= 'áéóú'; // ISO-8859-1
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8'
mb_detect_encoding($str, 'UTF-8', true); // false
?>
21
mta59066 at gmail dot com
1 年前
对于 php8.1,文档不再正确,mb_detect_encoding 不再支持编码顺序。文档中给出的示例输出对于 php8.1 也不再正确。这里有一些解释 https://github.com/php/php-src/issues/8279

我理解这些函数之前存在歧义,但在我看来 8.1 应该已经弃用 mb_detect_encoding 和 mb_detect_order 并提出了不同的函数。现在它试图找到占用空间最少的编码,无论顺序如何,我不确定谁需要这样做。

下面是一个示例函数,它将执行 8.1 更改之前 mb_detect_encoding 所执行的操作。

<?php

function mb_detect_enconding_in_order(string $string, array $encodings): string|false
{
foreach(
$encodings as $enc) {
if (
mb_check_encoding($string, $enc)) {
return
$enc;
}
}
return
false;
}

?>
5
geompse at gmail dot com
1 年前
自 8.1.7 以来,主要的未记录的重大更改
https://3v4l.org/BLjZ3

确保用 mb_check_encoding 的循环调用替换 mb_detect_encoding
22
Chrigu
19 年前
如果您需要区分 UTF-8 和 ISO-8859-1 编码,请在您的 encoding_list 中首先列出 UTF-8
mb_detect_encoding($string, 'UTF-8, ISO-8859-1');

如果您首先列出 ISO-8859-1,mb_detect_encoding() 将始终返回 ISO-8859-1。
18
chris AT w3style.co DOT uk
18 年前
基于下面的使用 preg_match() 的代码片段,我需要一些更快、更不具体的代码。该函数工作良好且很棒,但它会扫描整个字符串并检查它是否符合 UTF-8。我希望有一些东西可以纯粹地检查字符串是否包含 UTF-8 字符,以便我可以将字符编码从 iso-8859-1 切换到 utf-8。

我修改了模式,使其只查找 UTF-8 范围内的非 ASCII 多字节序列,并且一旦找到至少一个多字节字符串就停止。这快了很多。

<?php

function detectUTF8($string)
{
return
preg_match('%(?:
[\xC2-\xDF][\x80-\xBF] # 非超长 2 字节
|\xE0[\xA0-\xBF][\x80-\xBF] # 排除超长字符
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # 直接 3 字节
|\xED[\x80-\x9F][\x80-\xBF] # 排除代理
|\xF0[\x90-\xBF][\x80-\xBF]{2} # 平面 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # 平面 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # 平面 16
)+%xs'
, $string);
}

?>
19
nat3738 at gmail dot com
15 年前
通过 BOM 检测 UTF-8/16/32 文件的简单方法(不适用于没有 BOM 的字符串或文件)

<?php
// Unicode BOM 为 U+FEFF,但编码后,它将看起来像这样。
define ('UTF32_BIG_ENDIAN_BOM' , chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF));
define ('UTF32_LITTLE_ENDIAN_BOM', chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00));
define ('UTF16_BIG_ENDIAN_BOM' , chr(0xFE) . chr(0xFF));
define ('UTF16_LITTLE_ENDIAN_BOM', chr(0xFF) . chr(0xFE));
define ('UTF8_BOM' , chr(0xEF) . chr(0xBB) . chr(0xBF));

function
detect_utf_encoding($filename) {

$text = file_get_contents($filename);
$first2 = substr($text, 0, 2);
$first3 = substr($text, 0, 3);
$first4 = substr($text, 0, 3);

if (
$first3 == UTF8_BOM) return 'UTF-8';
elseif (
$first4 == UTF32_BIG_ENDIAN_BOM) return 'UTF-32BE';
elseif (
$first4 == UTF32_LITTLE_ENDIAN_BOM) return 'UTF-32LE';
elseif (
$first2 == UTF16_BIG_ENDIAN_BOM) return 'UTF-16BE';
elseif (
$first2 == UTF16_LITTLE_ENDIAN_BOM) return 'UTF-16LE';
}
?>
11
dennis at nikolaenko dot ru
15 年前
注意检测俄语编码的错误
http://bugs.php.net/bug.php?id=38138
4
rl at itfigures dot nl
16 年前
我使用 Chris 的函数 "detectUTF8" 来检测从 utf8 到 8859-1 的转换需求,该函数工作正常。我确实遇到了以下 iconv 转换的问题。

问题是,iconv 转换为 8859-1(使用 //TRANSLIT)会将欧元符号替换为 EUR,尽管通常的做法是在 8859-1 字符集中使用 \x80 作为欧元符号。

我无法使用 8859-15,因为它会破坏一些其他字符,所以我添加了 2 个 str_replace

if(detectUTF8($str)){
$str=str_replace("\xE2\x82\xAC","&euro;",$str);
$str=iconv("UTF-8","ISO-8859-1//TRANSLIT",$str);
$str=str_replace("&euro;","\x80",$str);
}

如果需要 html 输出,则最后一行没有必要(甚至不需要)。
5
eyecatchup at gmail dot com
11 年前
注意:不要使用 W3C 常用的(相当复杂的)正则表达式 (http://www.w3.org/International/questions/qa-forms-utf-8.en.php),您可以简单地使用 'u' 修饰符来测试字符串的 UTF-8 有效性

<?php
if (preg_match("//u", $string)) {
// $string 是有效的 UTF-8
}
5
hmdker at gmail dot com
15 年前
检测 UTF-8 的函数,当 mb_detect_encoding 不可用时,它可能会有用。

<?php
function is_utf8($str) {
$c=0; $b=0;
$bits=0;
$len=strlen($str);
for(
$i=0; $i<$len; $i++){
$c=ord($str[$i]);
if(
$c > 128){
if((
$c >= 254)) return false;
elseif(
$c >= 252) $bits=6;
elseif(
$c >= 248) $bits=5;
elseif(
$c >= 240) $bits=4;
elseif(
$c >= 224) $bits=3;
elseif(
$c >= 192) $bits=2;
else return
false;
if((
$i+$bits) > $len) return false;
while(
$bits > 1){
$i++;
$b=ord($str[$i]);
if(
$b < 128 || $b > 191) return false;
$bits--;
}
}
}
return
true;
}
?>
4
php-note-2005 at ryandesign dot com
19 年前
使用正则表达式检查 UTF-8,该表达式由 W3C 创建

<?php

// 如果 $string 是有效的 UTF-8,则返回 true,否则返回 false。
function is_utf8($string) {

// 来自 http://w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # 非超长 2 字节
| \xE0[\xA0-\xBF][\x80-\xBF] # 不包括超长字节
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # 直接 3 字节
| \xED[\x80-\x9F][\x80-\xBF] # 不包括代理
| \xF0[\x90-\xBF][\x80-\xBF]{2} # 平面 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # 平面 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # 平面 16
)*$%xs'
, $string);

}
// function is_utf8

?>
1
garbage at iglou dot eu
7 年前
要检测 UTF-8,您可以使用

if (preg_match('!!u', $str)) { echo 'utf-8'; }

- Norihiori
1
maarten
19 年前
有时 mb_detect_string 不是您需要的。例如,当使用 pdflib 时,您需要验证 utf-8 的正确性。mb_detect_encoding 会将一些 iso-8859-1 编码的文本报告为 utf-8。
要验证 utf 8,请使用以下方法

//
// 基于维基百科中关于 utf8 编码验证的条目开发
// http://en.wikipedia.org/wiki/UTF-8
//
// 实现为基于简单状态机的递归下降解析器
// 版权所有 2005 Maarten Meijer
//
// 这需要 C 实现才能包含在 PHP 核心代码中
//
function valid_1byte($char) {
if(!is_int($char)) return false;
return ($char & 0x80) == 0x00;
}

function valid_2byte($char) {
if(!is_int($char)) return false;
return ($char & 0xE0) == 0xC0;
}

function valid_3byte($char) {
if(!is_int($char)) return false;
return ($char & 0xF0) == 0xE0;
}

function valid_4byte($char) {
if(!is_int($char)) return false;
return ($char & 0xF8) == 0xF0;
}

function valid_nextbyte($char) {
if(!is_int($char)) return false;
return ($char & 0xC0) == 0x80;
}

function valid_utf8($string) {
$len = strlen($string);
$i = 0;
while( $i < $len ) {
$char = ord(substr($string, $i++, 1));
if(valid_1byte($char)) { // 继续
continue;
} else if(valid_2byte($char)) { // 检查 1 字节
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
} else if(valid_3byte($char)) { // 检查 2 字节
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
} else if(valid_4byte($char)) { // 检查 3 字节
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
if(!valid_nextbyte(ord(substr($string, $i++, 1))))
return false;
} // 转到下一个字符
}
return true; // 完成
}

有关状态机的绘制,请参见:http://www.xs4all.nl/~mjmeijer/unicode.pnghttp://www.xs4all.nl/~mjmeijer/unicode2.png
-1
d_maksimov
2 年前
这对我的 exec(...) 调用很有帮助。当它返回 cp866 或 cp1251 时

try {
$line = iconv('CP866', 'CP1251', $line);
} catch(Exception $e) {
}
return iconv('CP1251', 'UTF-8', $line);
0
emoebel at web dot de
10 年前
如果函数 "mb_detect_encoding" 不存在...

... 尝试

<?php
// ----------------------------------------------------
if ( !function_exists('mb_detect_encoding') ) {

// ----------------------------------------------------------------
function mb_detect_encoding ($string, $enc=null, $ret=null) {

static
$enclist = array(
'UTF-8', 'ASCII',
'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5',
'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10',
'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
'Windows-1251', 'Windows-1252', 'Windows-1254',
);

$result = false;

foreach (
$enclist as $item) {
$sample = iconv($item, $item, $string);
if (
md5($sample) == md5($string)) {
if (
$ret === NULL) { $result = $item; } else { $result = true; }
break;
}
}

return
$result;
}
// ----------------------------------------------------------------

}
// ----------------------------------------------------
?>

示例 / 使用:mb_detect_encoding()

<?php
// ------------------------------------------------------
function str_to_utf8 ($str) {

if (
mb_detect_encoding($str, 'UTF-8', true) === false) {
$str = utf8_encode($str);
}

return
$str;
}
// ------------------------------------------------------
?>

$txtstr = str_to_utf8($txtstr);
0
bmrkbyet at web dot de
11 年前
a) 如果函数 mb_detect_encoding 不可用

### mb_detect_encoding ... iconv ###

<?php
// -------------------------------------------

if(!function_exists('mb_detect_encoding')) {
function
mb_detect_encoding($string, $enc=null) {

static
$list = array('utf-8', 'iso-8859-1', 'windows-1251');

foreach (
$list as $item) {
$sample = iconv($item, $item, $string);
if (
md5($sample) == md5($string)) {
if (
$enc == $item) { return true; } else { return $item; }
}
}
return
null;
}
}

// -------------------------------------------
?>

b) 如果函数 mb_convert_encoding 不可用

### mb_convert_encoding ... iconv ###

<?php
// -------------------------------------------

if(!function_exists('mb_convert_encoding')) {
function
mb_convert_encoding($string, $target_encoding, $source_encoding) {
$string = iconv($source_encoding, $target_encoding, $string);
return
$string;
}
}

// -------------------------------------------
?>
-1
telemach
19 年前
注意:即使您需要区分 UTF-8 和 ISO-8859-1,并且您按照 chrigu 的建议使用以下检测顺序

mb_detect_encoding('accentu?e' , 'UTF-8, ISO-8859-1')

返回 ISO-8859-1,而

mb_detect_encoding('accentu?' , 'UTF-8, ISO-8859-1')

返回 UTF-8

底线:结尾的“?”(可能还有其他带重音的字符)会误导 mb_detect_encoding
-1
recentUser at example dot com
6 年前
在我的环境(PHP 7.1.12)中,
“mb_detect_encoding()”无法正常工作
如果“mb_detect_order()”未正确设置。

为了使“mb_detect_encoding()”在这种情况下正常工作,
只需在脚本文件中添加“mb_detect_order('...')”
在“mb_detect_encoding()”之前。

两者
“ini_set('mbstring.language', '...');”

“ini_set('mbstring.detect_order', '...');”
在脚本文件中不起作用
而在 PHP.INI 文件中设置它们可能有效。
-6
Anonymous
10 年前
// -----------------------------------------------------------

if(!function_exists('mb_detect_encoding')) {

function mb_detect_encoding($string, $enc=null, $ret=true) {
$out=$enc;
static $list = array('utf-8', 'iso-8859-1', 'iso-8859-15', 'windows-1251');
foreach ($list as $item) {
$sample = iconv($item, $item, $string);
if (md5($sample) == md5($string)) { $out = ($ret !== false) ? true : $item; }
}
return $out;
}

}

// -----------------------------------------------------------
-2
lotushzy at gmail dot com
6 年前
关于函数 mb_detect_encoding,链接 https://php.net/manual/zh/function.mb-detect-encoding.php ,例如这样
mb_detect_encoding('áéóú', 'UTF-8', true); // false
但现在结果不再是 false,你能告诉我原因吗,谢谢!
-6
yaqy at qq dot com
16 年前
<?php
/*
*QQ: 290359552
* 如果 $str 不等于 'UTF-8',则转换为 Utf8
*/
function convToUtf8($str)
{
if(
mb_detect_encoding($str,"UTF-8, ISO-8859-1, GBK")!="UTF-8" )
{

return
iconv("gbk","utf-8",$str);

}
else
{
return
$str;
}

}
?>
-7
matthijs at ischen dot nl
15 年前
我严重低估了 setlocale 的重要性…
<?php
$strings
= array(
"mais coisas a pensar sobre diário ou dois!",
"plus de choses à penser à journalier ou à deux !",
"¡más cosas a pensar en diario o dos!",
"più cose da pensare circa giornaliere o due!",
"flere ting å tenke på hver dag eller to!",
"Další věcí, přemýšlet o každý den nebo dva!",
"mehr über Spaß spät schönen",
"më vonë gjatë fun bukur",
"több mint szórakozás késő csodálatos kenyér"
);

$convert = array();
setlocale(LC_CTYPE, 'de_DE.UTF-8');
foreach(
$strings as $string )
$convert[] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
?>

生成以下内容

数组
(
[0] => mais coisas a pensar sobre diário ou dois!
[1] => plus de choses à penser à journalier ou à deux !
[2] => ?mas cosas a pensar en diario o dos!
[3] => piu cose da pensare circa giornaliere o due!
[4] => flere ting aa tenke paa hver dag eller to!
[5] => Dalsi veci, premyslet o kazdy den nebo dva!
[6] => mehr ueber Spass spaet schoenen
[7] => me vone gjate fun bukur
[8] => toebb mint szorakozas keso csodalatos kenyer
)



<?php
$convert
= array();
setlocale(LC_CTYPE, 'nl_NL.UTF-8');
foreach(
$strings as $string )
$convert[] = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
?>

生成
数组
(
[0] => mais coisas a pensar sobre di?rio ou dois!
[1] => plus de choses ? penser ? journalier ou ? deux !
[2] => ?m?s cosas a pensar en diario o dos!
[3] => pi? cose da pensare circa giornaliere o due!
[4] => flere ting ? tenke p? hver dag eller to!
[5] => Dal?? v?c?, p?em??let o ka?d? den nebo dva!
[6] => mehr ?ber Spass sp?t sch?nen
[7] => m? von? gjat? fun bukur
[8] => t?bb mint sz?rakoz?s k?s? csod?latos keny?r
)

这在尝试将 utf-8 字符串转换为适合 URL 的 ASCII 时可能很有用。由于我一直在使用 us 和 nl 的语言环境,因此这对我来说从未显而易见。
-5
lexonight at yahoo dot com
7 年前
<?php
$file
= file_get_contents("somefile.txt");
$encodings = implode(',', mb_list_encodings());
echo
mb_detect_encoding($file, $encodings, true);
?>
似乎有效
-6
jaaks at playtech dot com
19 年前
用于验证 UTF-8 的最后一个示例有一个小错误。如果 10xxxxxx 字节单独出现,即不在多字节字符中,则它会被接受,尽管这违反了 UTF-8 规则。进行以下替换以修复它。

替换
} // 转到下一个字符

} else {
return false; // 10xxxxxx 单独出现
} // 转到下一个字符
-11
prgss at bk dot ru
15 年前
另一种检测字符编码的简单方法
<?php
function detect_encoding($string) {
static
$list = array('utf-8', 'windows-1251');

foreach (
$list as $item) {
$sample = iconv($item, $item, $string);
if (
md5($sample) == md5($string))
return
$item;
}
return
null;
}
?>
-16
sunggsun
17 年前
来自 PHPDIG

function isUTF8($str) {
if ($str === mb_convert_encoding(mb_convert_encoding($str, "UTF-32", "UTF-8"), "UTF-8", "UTF-32")) {
return true;
} else {
return false;
}
}
To Top