代码之家  ›  专栏  ›  技术社区  ›  Max Cuttins

php json_encode()正在获取“格式错误的utf-8字符,可能编码不正确”(错误)

  •  1
  • Max Cuttins  · 技术社区  · 6 年前

    我解决不了这个问题,我快疯了。

    JSON_encode() 正在投射错误: Malformed UTF-8 characters, possibly incorrectly encoded 在几条记录(2或3)从一组10公里的记录。 然而,这似乎很难解决。

    • mysql已经在任何地方都是utf8mb4(数据库、表、列和排序规则)
    • php是7.2,当然是utf8
    • apache默认字符集是utf8(但是错误是在php级别抛出的)。

    我还可以在一个简单的html调试页面中打印并正确地筛选php中的记录。但是,如果我尝试用json编码它,就会得到错误。

    我发现这些记录是从一个cvs导入的,可能绕过了清洁器。奇怪的是,整个csv文件都是用以下语句解析的:

    $this->encoding = mb_detect_encoding($source,mb_detect_order(),true);
    if ($this->encoding!="" && $this->encoding!="UTF8") {
        $source = iconv($this->encoding, "UTF-8", $source);
    } 
    

    由于隐私(和gdpr),我不能发布任何完整的损坏数据。 然而,我成功地提取出了一个看似破碎的部分:

    RESIDENCE �PRINCIPE
    

    更新

    我试着得到这些坏字符的比特码。这就是我发现的。 在ascii中使用简单的本机函数 str_split ord 这些字符是:

    '�' 160
    

    我还想在utf8中找到位代码,所以我在php.net上找到了这个有用的函数 http://php.net/manual/en/function.ord.php#109812 它试图找到multibytestrings的位码。它给了我:

    -2096
    

    也就是……消极的?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Max Cuttins    6 年前

    解决了的!

    问题出在职能部门 mb_detect_order() ,这个函数并不像我所期望的那样工作。我认为这是一个完整的支持编码顺序列表,主要用于加快检测过程。

    但我发现这个函数只返回2个编码:

    //print_r(mb_detect_order());
    Array
    (
        [0] => ASCII
        [1] => UTF-8
    )
    

    这对我来说几乎毫无用处。 mb函数可以检测更多的字符集。 你可以跑去看看 mb_list_encodings()

    //print_r(mb_list_encodings());
    Array
    (
        [0] => pass
        [1] => auto
        [2] => wchar
        [3] => byte2be
        [4] => byte2le
        [5] => byte4be
        [6] => byte4le
        [7] => BASE64
        [8] => UUENCODE
        [9] => HTML-ENTITIES
        [10] => Quoted-Printable
        [11] => 7bit
        [12] => 8bit
        [13] => UCS-4
        [14] => UCS-4BE
        [15] => UCS-4LE
        [16] => UCS-2
        [17] => UCS-2BE
        [18] => UCS-2LE
        [19] => UTF-32
        [20] => UTF-32BE
        [21] => UTF-32LE
        [22] => UTF-16
        [23] => UTF-16BE
        [24] => UTF-16LE
        [25] => UTF-8
        [26] => UTF-7
        [27] => UTF7-IMAP
        [28] => ASCII
        [29] => EUC-JP
        [30] => SJIS
        [31] => eucJP-win
        [32] => EUC-JP-2004
        [33] => SJIS-win
        [34] => SJIS-Mobile#DOCOMO
        [35] => SJIS-Mobile#KDDI
        [36] => SJIS-Mobile#SOFTBANK
        [37] => SJIS-mac
        [38] => SJIS-2004
        [39] => UTF-8-Mobile#DOCOMO
        [40] => UTF-8-Mobile#KDDI-A
        [41] => UTF-8-Mobile#KDDI-B
        [42] => UTF-8-Mobile#SOFTBANK
        [43] => CP932
        [44] => CP51932
        [45] => JIS
        [46] => ISO-2022-JP
        [47] => ISO-2022-JP-MS
        [48] => GB18030
        [49] => Windows-1252
        [50] => Windows-1254
        [51] => ISO-8859-1
        [52] => ISO-8859-2
        [53] => ISO-8859-3
        [54] => ISO-8859-4
        [55] => ISO-8859-5
        [56] => ISO-8859-6
        [57] => ISO-8859-7
        [58] => ISO-8859-8
        [59] => ISO-8859-9
        [60] => ISO-8859-10
        [61] => ISO-8859-13
        [62] => ISO-8859-14
        [63] => ISO-8859-15
        [64] => ISO-8859-16
        [65] => EUC-CN
        [66] => CP936
        [67] => HZ
        [68] => EUC-TW
        [69] => BIG-5
        [70] => CP950
        [71] => EUC-KR
        [72] => UHC
        [73] => ISO-2022-KR
        [74] => Windows-1251
        [75] => CP866
        [76] => KOI8-R
        [77] => KOI8-U
        [78] => ArmSCII-8
        [79] => CP850
        [80] => JIS-ms
        [81] => ISO-2022-JP-2004
        [82] => ISO-2022-JP-MOBILE#KDDI
        [83] => CP50220
        [84] => CP50220raw
        [85] => CP50221
        [86] => CP50222
    )
    

    我错了,以为 mb_detect_order 只是这个列表的一个有序版本。这个 mb_检测顺序 只是…没用。要以正确的方式使用UTF8编码,请使用以下代码:

    $my_encoding_list = [
        "UTF-8",
        "UTF-7",
        "UTF-16",
        "UTF-32",
        "ISO-8859-16",
        "ISO-8859-15",
        "ISO-8859-10",
        "ISO-8859-1",
        "Windows-1254",
        "Windows-1252",
        "Windows-1251",
        "ASCII",
        //add yours preferred
    ];
    
    //remove unsupported encodings
    $encoding_list = array_intersect($my_encoding_list, mb_list_encodings());
    
    //detect 'finally' the encoding
    $this->encoding = mb_detect_encoding($source,$encoding_list,true);
    

    这有效地解决了我在数据库中保存坏数据的问题。

        2
  •  1
  •   fxbt    6 年前

    您可以使用 UTF-8//IGNORE 你的内裤 iconv 方法。

    $this->encoding = mb_detect_encoding($source,mb_detect_order(),true);
    
    if ($this->encoding!="" && $this->encoding!="UTF8") {
        $source = iconv($this->encoding, "UTF-8//IGNORE", $source);
    } 
    

    通过使用 //IGNORE 在您的字符集之后,目标字符集中无法表示的每个字符都将被自动丢弃。