PHP:在不知道原始字符集的情况下将任何字符串转换为UTF-8,或者至少尝试一下

PHP:在不知道原始字符集的情况下将任何字符串转换为UTF-8,或者至少尝试一下,php,utf-8,character-encoding,Php,Utf 8,Character Encoding,我有一个处理来自世界各地客户的应用程序,当然,我希望进入数据库的所有内容都是UTF-8编码的 我的主要问题是,我不知道任何字符串的源代码是什么-它可能来自文本框(使用仅在用户实际提交表单时有用),也可能来自上传的文本文件,因此我无法控制输入 我需要的是一个函数或类,以确保进入数据库的内容尽可能是UTF-8编码的。我尝试过iconv(mb_detect_编码($text),“UTF-8”,“$text) 但这有问题(如果输入是'fiancée',则返回'fianc')。我试过很多东西=/ 对于文件

我有一个处理来自世界各地客户的应用程序,当然,我希望进入数据库的所有内容都是UTF-8编码的

我的主要问题是,我不知道任何字符串的源代码是什么-它可能来自文本框(使用
仅在用户实际提交表单时有用),也可能来自上传的文本文件,因此我无法控制输入

我需要的是一个函数或类,以确保进入数据库的内容尽可能是UTF-8编码的。我尝试过iconv(mb_detect_编码($text),“UTF-8”,“$text) 但这有问题(如果输入是'fiancée',则返回'fianc')。我试过很多东西=/

对于文件上传,我喜欢让最终用户指定他们使用的编码,并向他们展示输出的预览,但这无助于对付讨厌的黑客(事实上,这可以让他们的生活更轻松)

我读过关于这个主题的其他问题,但它们似乎都有细微的区别,比如“我需要解析RSS提要”或“我从网站上抓取数据”(或者,事实上,“你不能”)


但一定有什么东西至少有一个很好的尝试

你的要求是非常困难的。如果可能,最好让用户指定编码。通过这种方式防止攻击应该不会容易或困难得多

但是,您可以尝试这样做:

iconv(mb_detect_encoding($text, mb_detect_order(), true), "UTF-8", $text);

将其设置为strict可能会帮助您获得更好的结果

您可以设置一组度量来尝试猜测正在使用哪种编码。同样,这并不完美,但可以捕获mb_detect_encoding()中的一些未命中。

您可能已经尝试过这样做,但为什么不使用mb_convert_encoding函数呢?它将尝试自动检测所提供文本的字符集,或者您可以向其传递一个列表

此外,我还试着跑:

$text = "fiancée";
echo mb_convert_encoding($text, "UTF-8");
echo "<br/><br/>";
echo iconv(mb_detect_encoding($text), "UTF-8", $text);
$text=“未婚妻”;
echo mb_convert_编码($text,“UTF-8”);
回声“

”; echo iconv(mb_检测_编码($text)、“UTF-8”和$text);

这两种方法的结果是一样的。你怎么看你的文字被截断成“fianc”?它是在数据库中还是在浏览器中?

在祖国俄罗斯,我们有4种流行的编码,所以你的问题在这里很受欢迎

只有通过字符编码的符号才能检测到编码,因为代码页相交。不同语言中的一些代码页甚至完全相交。因此,我们需要另一种方法

处理未知编码的唯一方法是处理概率。因此,我们不想回答“这段文字的编码是什么?”的问题,我们试图理解“这段文字最可能的编码是什么?”

一个在俄罗斯流行科技博客上的家伙发明了这种方法:

在您想要支持的每种编码中建立字符代码的概率范围。你可以用你的语言中的一些大的文本来构建它(例如,一些小说,英语用莎士比亚,俄语用托尔斯泰,lol)。您将获得如下smth:

    encoding_1:
    190 => 0.095249209893009,
    222 => 0.095249209893009,
    ...
    encoding_2:
    239 => 0.095249209893009,
    207 => 0.095249209893009,
    ...
    encoding_N:
    charcode => probabilty
$connection = new mysqli($server, $user, $pass, $db);
$connection->set_charset("utf8");
下一个。在未知编码的文本中,对于“概率字典”中的每个编码,您都会搜索未知编码文本中每个符号的频率。符号的和概率。评分更高的编码可能是赢家。更大的文本效果更好

如果您感兴趣,我可以很乐意帮助您完成此任务。通过建立两个字符码概率表,可以大大提高准确率


顺便说一句,mb_detect_编码肯定不起作用。是的,一点也不。请看一看“ext/mbstring/libmbfl/mbfl/mbfl_ident.c”中的mb_detect_编码源代码。

无法识别完全准确的字符串字符集。 有很多方法可以尝试猜测字符集。其中一种方法是mb_detect_encoding(),这可能是/目前PHP中最好的方法。这将扫描字符串并查找某些字符集特有的内容。根据您的字符串,可能不会出现这种可区分的事件

以ISO-8859-1字符集与ISO-8859-15()

只有少数几个不同的字符,更糟糕的是,它们由相同的字节表示。如果给定一个字符串而不知道其编码,则无法检测字节0xA4在字符串中是表示·还是€,因此无法知道它的确切字符集

(注意:您可以添加人为因素,或更高级的扫描技术(例如Oroboros102建议的),以尝试根据周围环境确定角色是否应为€或€,尽管这看起来像是一座桥太远了)

例如,UTF-8和ISO-8859-1之间存在更明显的差异,因此,当您不确定时,仍然值得尝试找出它,尽管您可以也不应该依赖它是否正确

有趣的阅读:

不过,还有其他方法可以确保正确的字符集。关于表单,尽可能地强制使用UTF-8(查看snowman,确保您提交的内容在每个浏览器中都是UTF-8:) 这样做,至少你可以确保通过表单提交的每一篇文本都是utf_8。关于上载的文件,请尝试通过exec()等(如果可能,在您的服务器上)在其上运行unix“file-i”命令,以帮助检测(使用文档的BOM表) 关于抓取数据,您可以读取HTTP头,它通常指定字符集。解析XML文件时,请查看XML元数据是否包含字符集定义

与其尝试自动猜测字符集,不如在可能的情况下,首先尝试自己确定某个字符集,或者尝试从获取该字符集的源中获取定义(如果适用),然后再求助于检测

我的主要问题是
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    private function isUTF8($encoding, $value)
    {
        return (($encoding === 'UTF-8') && (utf8_encode(utf8_decode($value)) === $value));
    }

    private function utf8tify(&$value)
    {
        $encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];

        mb_internal_encoding('UTF-8');
        mb_substitute_character(0xfffd); //REPLACEMENT CHARACTER
        mb_detect_order($encodings);

        $stringEncoding = mb_detect_encoding($value, $encodings, true);

        if (!$stringEncoding) {
            $value = null;
            throw new \RuntimeException("Unable to identify character encoding in sanitizer.");
        }

        if ($this->isUTF8($stringEncoding, $value)) {
            return;
        } else {
            $value = mb_convert_encoding($value, 'UTF-8', $stringEncoding);
            $stringEncoding = mb_detect_encoding($value, $encodings, true);

            if ($this->isUTF8($stringEncoding, $value)) {
                return;
            } else {
                $value = null;
                throw new \RuntimeException("Unable to convert character encoding from ISO-8859-1, or ASCII, to UTF-8 in Sanitizer.");
            }
        }

        return;
    }
$connection = new mysqli($server, $user, $pass, $db);
$connection->set_charset("utf8");