Mengapa json_encode mengembalikan string kosong

107

Saya memiliki struktur php sederhana dengan 3 array bersarang.

Saya tidak menggunakan objek tertentu dan saya membangun sendiri array dengan 2 loop bersarang.

Berikut adalah contoh var_dump dari array yang ingin saya ubah ke Json.

array (size=2)
  'tram B' => 
    array (size=2)
      0 => 
        array (size=3)
          'name' => string 'Ile Verte' (length=9)
          'distance' => int 298
          'stationID' => int 762
      1 => 
        array (size=3)
          'name' => string 'La Tronche Hôpital' (length=18)
          'distance' => int 425
          'stationID' => int 771
  16 => 
    array (size=4)
      0 => 
        array (size=3)
          'name' => string 'Bastille' (length=8)
          'distance' => int 531
          'stationID' => int 397
      1 => 
        array (size=3)
          'name' => string 'Xavier Jouvin' (length=13)
          'distance' => int 589
          'stationID' => int 438

Di skrip lain saya memiliki struktur yang mirip dan json_encodeberfungsi dengan baik. Jadi saya tidak mengerti mengapa json_encodetidak bekerja di sini.

Edit: sepertinya ada masalah dengan encoding. Ketika mb_detect_encodingmengembalikan ASCII, json_encodeberfungsi tetapi ketika mengembalikan UTF8, itu tidak berfungsi lagi.

Edit2: json_last_error()mengembalikan JSON_ERROR_UTF8yang berarti: Karakter UTF-8 cacat, mungkin salah dienkode .

Matthieu Riegler
sumber
Manual PHP mengatakan This function only works with UTF-8 encoded data.jadi seharusnya tidak ada masalah dengan pengkodean.
MahanGM
13
Coba gunakan utf8_encode()pada namebidang array Anda sebelum Anda menyerahkan string ke json_encode().
MahanGM
Terima kasih ! Saya baru saja menemukan solusi ini yang memecahkan masalah saya.
Matthieu Riegler
Ya, lihat jawabannya. Semoga berhasil.
MahanGM
3
Gunakan JSON_PARTIAL_OUTPUT_ON_ERRORopsi untuk melihat masalah (mis. Bidang dengan UTF8 akan menjadi nol).
Peter Krauss

Jawaban:

255

Nah setelah 2 jam penggalian (cf Editan)

Saya menemukan hal berikut:

  • Dalam kasus saya ini adalah masalah pengkodean
  • mb_detect_encoding mengembalikan mungkin respons yang salah, beberapa string mungkin bukan UTF-8
  • menggunakan utf8_encode()pada string itu memecahkan masalah saya, tetapi lihat catatan di bawah

Berikut adalah fungsi rekursif yang dapat mengubah paksa ke UTF-8 semua string yang terdapat dalam sebuah array:

function utf8ize($d) {
    if (is_array($d)) {
        foreach ($d as $k => $v) {
            $d[$k] = utf8ize($v);
        }
    } else if (is_string ($d)) {
        return utf8_encode($d);
    }
    return $d;
}

Gunakan seperti ini:

echo json_encode(utf8ize($data));

Catatan: utf8_encode () mengkodekan string ISO-8859-1 ke UTF-8 sesuai dengan dokumen jadi jika Anda tidak yakin dengan input encoding iconv () atau mb_convert_encoding () mungkin opsi yang lebih baik seperti yang dicatat dalam komentar dan solusi lainnya.

Matthieu Riegler
sumber
4
Terima kasih atas solusi Anda ... namun, satu catatan tambahan: Ubah } else {menjadi } else if (is_string ($d)) {; jika tidak, Anda akan mengubah segalanya menjadi string (mis. INTakan menjadi a STRING).
Paul Peelen
3
Anda baru saja menyelamatkan hidup saya. Saya akan mengakhiri semuanya sampai saya menemukan fungsi ini !! Terima kasih.
silversunhunter
2
WTF! Terima kasih telah membagikan solusi Anda. Saya dapat melihat bahwa ini akan membutuhkan banyak penggalian untuk dipecahkan, dan saya berterima kasih kepada Anda karena melakukan itu dan berbagi.
keris
1
Setelah tiga hari debugging, aku bisa menciummu sekarang.
AJB
2
Jika membaca dari database cukup gunakan, $ conn-> set_charset ("utf8");
Andrew Briggs
36

Matthieu Riegler menyajikan solusi yang sangat bagus namun saya harus sedikit memodifikasinya untuk menangani objek juga:

function utf8ize($d) {
    if (is_array($d)) 
        foreach ($d as $k => $v) 
            $d[$k] = utf8ize($v);

     else if(is_object($d))
        foreach ($d as $k => $v) 
            $d->$k = utf8ize($v);

     else 
        return utf8_encode($d);

    return $d;
}

Satu catatan lagi: json_last_error () mungkin berguna dalam debugging fungsi json_encode () / json_encode ().

Adam Bubela
sumber
Bukankah seharusnya elseifbukan else if? (yaitu tidak boleh kosong).
Uwe Keim
2
@UweKeim menurut dokumentasi PHP "elseif dan lain jika hanya akan dianggap persis sama saat menggunakan tanda kurung kurawal" yang berarti mereka setara selama Anda tidak menggunakan notasi titik dua, misalnyaif(): elseif:
Adam Bubela
1
Kerja bagus. PHP adalah sampah dan orang-orang seperti Anda mencegahnya pergi ke tempat sampah.
Lonnie Best
Anda harus memasukkan else if(is_int($d)||is_bool($d)) return $d;sebelum yang terakhir, karena:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
David Refoua
Seperti yang direkomendasikan @ paul-peelen kepada @ matthieu-riegler: Ubah yang terakhir elseuntuk else if(is_string ($d)); jika tidak, Anda akan mengubah segalanya menjadi string (mis. INTakan menjadi a STRING).
Bruno Serrano
30

Bagi saya, jawaban untuk masalah ini adalah pengaturan charset=utf8koneksi PDO saya.

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);
fayd
sumber
2
Atau dalam fungsi mysqli: mysqli_set_charset ($ connection, "utf8");
pengguna18099
Ini adalah petunjuk untuk solusi saya. Penyebab koneksi msqli sedikit berbeda. Panggil saja $mysqli->set_charset("utf8");setelah melakukan penanganan database Anda.
MaggusK
Silakan gunakan utf8mb4di versi MySQL terbaru. utf8sudah usang.
Dharman
10

Adam Bubela juga menyajikan solusi yang sangat bagus yang membantu saya menyelesaikan masalah saya, dan berikut adalah fungsi yang disederhanakan:

function utf8ize($d)
{ 
    if (is_array($d) || is_object($d))
        foreach ($d as &$v) $v = utf8ize($v);
    else
        return utf8_encode($d);

    return $d;
}
Alex
sumber
1
Saya suka yang ini karena menyimpan kuncinya.
dev0
7

Saya memiliki masalah yang sama persis di PHP 5.6. Saya menggunakan Open Server + Nginx pada Windows 7. Semua charset disetel ke UTF-8. Secara teori, menurut dokumentasi resmi , bendera

JSON_UNESCAPED_UNICODE

harus menyelesaikan ini. Sayangnya ini bukan kasus saya. Saya tidak tahu kenapa. Semua potongan di atas tidak menyelesaikan masalah saya, jadi saya telah menemukan implementasi saya sendiri. Saya percaya itu bisa membantu seseorang. Setidaknya, huruf Rusia lulus ujian.

function utf8ize($d) {
    if (is_array($d) || is_object($d)) {
        foreach ($d as &$v) $v = utf8ize($v);
    } else {
        $enc   = mb_detect_encoding($d);

        $value = iconv($enc, 'UTF-8', $d);
        return $value;
    }

    return $d;
}
Vsevolod Azovsky
sumber
4

Jawaban yang diterima ini berhasil. Tetapi jika Anda mendapatkan data Anda dari MySQL (seperti yang saya lakukan sebelumnya) ada cara yang lebih mudah.

Setelah Anda membuka database Anda, sebelum Anda membuat kueri, Anda dapat mengatur set karakter menggunakan mysqli sebagai berikut:

/* change character set to utf8 | Procedural*/
if (!mysqli_set_charset($link, "utf8")) {
    printf("Error loading character set utf8: %s\n", mysqli_error($link));
    exit();
}

ATAU

/* change character set to utf8 | Object Oriented*/
if (!$mysqli->set_charset("utf8")) {
        printf("Error loading character set utf8: %s\n", $mysqli->error);
        exit();
 }

LINK: http://php.net/manual/en/mysqli.set-charset.php

Kholofelo
sumber
4

Saya mengalami masalah ini di server yang menjalankan versi PHP yang lebih lama (5.2). Saya menggunakan flag JSON_FORCE_OBJECT, dan tampaknya itu tidak didukung hingga 5.3

Jadi jika Anda menggunakan bendera itu, pastikan untuk memeriksa versi Anda!

Solusi yang tampaknya hanya mentransmisikan ke objek sebelum encoding, seperti:

json_encode((object)$myvar);
Shane N
sumber
3

Pengembalian mb_detect_encodingmungkin salah:

$data = iconv('UTF-8', 'ISO-8859-1', 'La Tronche Hôpital');
var_dump(
    mb_detect_encoding($data),
    mb_detect_encoding($data, array('ISO-8859-1', 'UTF-8'))
);

Bergantung pada urutan deteksi default, yang di atas mungkin memberikan hasil yang berbeda, sehingga encoding salah dilaporkan sebagai UTF-8. ( Berikut contoh yang lebih besar .)

Sepertinya data Anda tidak dienkode sebagai UTF-8, begitu json_encodejuga yang ditampilkan false. Anda harus melihat cara mengonversi string Anda ke UTF-8 sebelum encoding JSON:

$fromEncoding = 'ISO-8859-1'; // This depends on the data

array_walk_recursive($array, function (&$value, $key, $fromEncoding) {
    if (is_string($value)) {
        $value = iconv($fromEncoding, 'UTF-8', $value);
    }
}, $fromEncoding);
cmbuckley.dll
sumber
3

Saya mendapatkan data dari ob_get_clean () dan memiliki masalah yang sama, tetapi solusi di atas tidak berfungsi untuk saya. Dalam kasus saya, solusinya adalah ini, mungkin itu akan membantu seseorang.

$var = mb_convert_encoding($var, 'UTF-8');
zdeniiik.dll
sumber
2

menggunakan utf8_encode () pada string itu memecahkan masalah saya.

mobizen
sumber
1

Saya telah memperbaiki jawaban Adam Bubela. Saya benci jika blok tidak ditutup oleh {dan}. Ini lebih bersih dan Anda tidak memperkenalkan bug atau mungkin itu karena saya menggunakan Perl di masa lalu :)

<?php

class App_Updater_String_Util {    
    /**
     * Usage: App_Updater_String_Util::utf8_encode( $data );
     *
     * @param mixed $d
     * @return mixed
     * @see http://stackoverflow.com/questions/19361282/why-would-json-encode-returns-an-empty-string
     */
    public static function utf8_encode($d) {
        if (is_array($d)) {
            foreach ($d as $k => $v) {
                $d[$k] = self::utf8_encode($v);
            }
        } elseif (is_object($d)) {
            foreach ($d as $k => $v) {
                $d->$k = self::utf8_encode($v);
            }
        } elseif (is_scalar($d)) {
            $d = utf8_encode($d);
        }

        return $d;
    }
}

?>
Svetoslav Marinov
sumber
0

Jika Anda mendapatkan data ini dari database, gunakan mysqli_set_charset($connection, "utf8");koneksi saat mendapatkan params dari database

raul garcia de la fuente
sumber
0

masalah ini terkadang muncul - Anda tidak melewati kontrol akses header.

Dalam kasus saya jika saya telah menambahkan gema sebelum json_encode. Itu menunjukkan hasil, jika tidak, halaman kosong akan datang.

saya tambahkan

header('Access-Control-Allow-Origin: *'); 

dan masalah saya teratasi.

Anup
sumber