Tại sao json_encode trả về một chuỗi trống


107

Tôi có một cấu trúc php đơn giản với 3 mảng lồng nhau.

Tôi không sử dụng các đối tượng cụ thể và tôi tự xây dựng các mảng với 2 vòng lặp lồng nhau.

Đây là một ví dụ về var_dump của mảng mà tôi muốn chuyển đổi thành 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

Trong một kịch bản khác, tôi có cấu trúc tương tự và json_encodehoạt động tốt. Vì vậy, tôi không hiểu tại sao json_encodesẽ không hoạt động ở đây.

Chỉnh sửa: có vẻ như có vấn đề với mã hóa. Khi mb_detect_encodingtrả về ASCII, nó json_encodehoạt động nhưng khi trả về UTF8, nó không hoạt động nữa.

Edit2: json_last_error()trả về JSON_ERROR_UTF8có nghĩa là: Các ký tự UTF-8 không đúng định dạng, có thể được mã hóa không chính xác .


Hướng dẫn sử dụng PHP cho biết This function only works with UTF-8 encoded data.vì vậy sẽ không có bất kỳ vấn đề gì với việc mã hóa.
MahanGM

13
Cố gắng sử dụng utf8_encode()trên namecác trường mảng của bạn trước khi bạn chuyển chuỗi cho json_encode().
MahanGM

Cám ơn ! Tôi vừa đi đến giải pháp này để giải quyết vấn đề của tôi.
Matthieu Riegler

Vâng, đã thấy câu trả lời. Chúc may mắn.
MahanGM 14/10/13

3
Sử dụng JSON_PARTIAL_OUTPUT_ON_ERRORtùy chọn để xem vấn đề (ví dụ: trường có UTF8 sẽ là trống).
Peter Krauss

Câu trả lời:


255

Tốt sau 2 giờ đào (xem Chỉnh sửa)

Tôi phát hiện ra sau đây:

  • Trong trường hợp của tôi, đó là một vấn đề mã hóa
  • mb_detect_encoding trả về có thể là phản hồi bị lỗi, một số chuỗi có thể không phải là UTF-8
  • sử dụng utf8_encode()trên chuỗi đó đã giải quyết được vấn đề của tôi, nhưng hãy xem lưu ý bên dưới

Đây là một hàm đệ quy có thể buộc chuyển đổi thành UTF-8 tất cả các chuỗi có trong một mảng:

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;
}

Sử dụng nó đơn giản như thế này:

echo json_encode(utf8ize($data));

Lưu ý: utf8_encode () mã hóa chuỗi ISO-8859-1 thành UTF-8 theo tài liệu, vì vậy nếu bạn không chắc chắn về biểu tượng mã hóa đầu vàov () hoặc mb_convert_encoding () có thể là các tùy chọn tốt hơn như đã lưu ý trong nhận xét và các giải pháp khác.


4
Cảm ơn giải pháp của bạn ... tuy nhiên, một lưu ý nhỏ: Thay đổi } else {thành } else if (is_string ($d)) {; nếu không bạn sẽ thay đổi mọi thứ thành chuỗi (ví dụ: INTsẽ trở thành a STRING).
Paul Peelen

3
Bạn vừa cứu mạng tôi. Tôi đã sắp kết thúc mọi thứ cho đến khi tôi tìm thấy chức năng này !! Cảm ơn bạn.
silversunhunter

2
WTF! Cảm ơn bạn đã chia sẻ giải pháp của bạn. Tôi có thể thấy rằng điều này sẽ phải mất rất nhiều thời gian để tìm ra và tôi biết ơn bạn đã làm điều đó và chia sẻ.
kris

1
Sau ba ngày gỡ lỗi, tôi có thể hôn bạn ngay bây giờ.
AJB

2
Nếu đọc từ cơ sở dữ liệu chỉ cần sử dụng, $ conn-> set_charset ("utf8");
Andrew Briggs

36

Matthieu Riegler đã trình bày giải pháp thực sự tốt nhưng tôi cũng phải sửa đổi một chút để xử lý các đối tượng:

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;
}

Một lưu ý nữa: json_last_error () có thể hữu ích trong việc gỡ lỗi các hàm json_encode () / json_encode ().


Không nên elseifthay vì else if? (tức là không có ô trống).
Uwe Keim

2
@UweKeim theo tài liệu PHP "elseif và else if sẽ chỉ được xem xét giống hệt nhau khi sử dụng dấu ngoặc nhọn" có nghĩa là họ là tương đương chừng nào bạn không sử dụng các ký hiệu đại tràng ví dụif(): elseif:
Adam Bubela

1
Làm tốt lắm. PHP là rác và những người như bạn giữ nó không đi đến bãi rác.
Lonnie Best

Bạn nên chèn một else if(is_int($d)||is_bool($d)) return $d;trước khác cuối cùng, vì:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
David Refoua

Cũng giống như @ paul-peelen được đề xuất cho @ matthieu-riegler: Thay đổi cái cuối cùng elsecho else if(is_string ($d)); nếu không bạn sẽ thay đổi mọi thứ thành chuỗi (ví dụ: INTsẽ trở thành a STRING).
Bruno Serrano

30

Đối với tôi, câu trả lời cho vấn đề này được đặt charset=utf8trong kết nối PDO của tôi.

$dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);

2
Hoặc trong các hàm mysqli: mysqli_set_charset ($ connection, "utf8");
user18099

Đây là gợi ý cho giải pháp của tôi. Nguyên nhân ít khác nhau của kết nối msqli. Chỉ cần gọi $mysqli->set_charset("utf8");sau khi xử lý cơ sở dữ liệu của bạn.
MaggusK

Vui lòng sử dụng utf8mb4trong các phiên bản MySQL gần đây. utf8Là lỗi thời.
Dharman

10

Adam Bubela cũng đã trình bày giải pháp thực sự tốt, người đã giúp tôi giải quyết vấn đề của mình và đây là hàm đơn giản hóa:

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

    return $d;
}

1
Tôi thích cái này vì nó giữ được các phím.
dev0

7

Tôi gặp chính xác vấn đề tương tự trên PHP 5.6. Tôi sử dụng Open Server + Nginx trên Windows 7. Tất cả các bộ ký tự được đặt thành UTF-8. Về lý thuyết, theo tài liệu chính thức , cờ

JSON_UNESCAPED_UNICODE

nên giải quyết vấn đề này. Thật không may, đây không phải là trường hợp của tôi. Tôi không biết tại sao. Tất cả các đoạn mã ở trên không giải quyết được vấn đề của tôi, do đó tôi đã tìm cách triển khai của riêng mình. Tôi tin rằng nó có thể giúp một ai đó. Ít nhất, các chữ cái tiếng Nga đã vượt qua bài kiểm tra.

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;
}

4

Câu trả lời được chấp nhận này hoạt động. Nhưng trong trường hợp bạn đang lấy dữ liệu của mình từ MySQL (như tôi đã từng làm) thì có một cách dễ dàng hơn.

Khi bạn mở cơ sở dữ liệu của mình, trước khi truy vấn, bạn có thể đặt bộ ký tự bằng mysqli như sau:

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

HOẶC LÀ

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

LIÊN KẾT: http://php.net/manual/en/mysqli.set-charset.php


4

Tôi gặp sự cố này trên máy chủ chạy phiên bản PHP cũ hơn (5.2). Tôi đang sử dụng cờ JSON_FORCE_OBJECT và rõ ràng là cờ đó không được hỗ trợ cho đến 5.3

Vì vậy, nếu bạn đang sử dụng cờ đó, hãy chắc chắn kiểm tra phiên bản của bạn!

Một cách giải quyết dường như chỉ là truyền tới một đối tượng trước khi mã hóa, như:

json_encode((object)$myvar);

3

Việc trả lại mb_detect_encodingcó thể không đúng:

$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'))
);

Tùy thuộc vào thứ tự phát hiện mặc định, ở trên có thể trả về các kết quả khác nhau, do đó, mã hóa được báo cáo sai là UTF-8. ( Đây là một ví dụ lớn hơn .)

Có khả năng là dữ liệu của bạn không được mã hóa dưới dạng UTF-8, vì vậy json_encodesẽ bị trả về false. Bạn nên xem xét việc chuyển đổi chuỗi của mình sang UTF-8 trước khi mã hóa 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);

3

Tôi đang nhận dữ liệu từ ob_get_clean () và gặp vấn đề tương tự, nhưng các giải pháp trên không hiệu quả với tôi. Trong trường hợp của tôi, giải pháp là cái này, có lẽ nó sẽ giúp được ai đó.

$var = mb_convert_encoding($var, 'UTF-8');

2

sử dụng utf8_encode () trên chuỗi đó đã giải quyết được vấn đề của tôi.


1

Tôi đã cải thiện câu trả lời của Adam Bubela. Tôi chỉ ghét nó khi các khối không được đóng bởi {và}. Nó sạch hơn và bạn không giới thiệu lỗi hoặc có thể đó là tôi đã sử dụng Perl trong quá khứ :)

<?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;
    }
}

?>

0

Nếu bạn lấy dữ liệu này từ cơ sở dữ liệu, hãy sử dụng mysqli_set_charset($connection, "utf8");kết nối khi lấy các thông số từ cơ sở dữ liệu


0

vấn đề này đôi khi xảy ra - bạn không vượt qua kiểm soát truy cập tiêu đề.

Trong trường hợp của tôi, nếu tôi đã được thêm bất kỳ tiếng vọng nào trước json_encode. Nó đang hiển thị kết quả nếu không có trang trống.

Tôi đã thêm

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

và vấn đề của tôi đã được giải quyết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.