Чому json_encode повертає порожній рядок


107

У мене проста структура php з 3 вкладеними масивами.

Я не використовую конкретні об'єкти, і я будую масиви з 2 вкладених циклів.

Ось зразок var_dump масиву, який я хочу перетворити на 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

В іншому сценарії у мене схожа структура і json_encodeпрекрасно працює. Тож я не розумію, чому json_encodeтут не працюватиме.

Редагувати: мабуть, проблема з кодуванням. Коли mb_detect_encodingповертається ASCII, json_encodeпрацює, але коли він повертає UTF8, він більше не працює.

Edit2: json_last_error()повертає, JSON_ERROR_UTF8що означає: неправильно сформовані символи UTF-8, можливо, неправильно закодовані .


Посібник PHP говорить, This function only works with UTF-8 encoded data.що не повинно виникнути проблем із кодуванням.
MahanGM

13
Спробуйте використовувати utf8_encode()в nameполях масиву перед тим, як вручити рядок json_encode().
MahanGM

Дякую ! Я просто прийшов до цього рішення, яке вирішило мою проблему.
Матьє Ріглер

Так, побачив відповідь. Удачі.
MahanGM

3
Використовуйте JSON_PARTIAL_OUTPUT_ON_ERRORопцію, щоб переглянути проблему (наприклад, поле з UTF8 буде нульовим).
Пітер Краусс

Відповіді:


255

Добре через 2 години копання (див. Правки)

Я дізнався наступне:

  • У моєму випадку це проблема кодування
  • mb_detect_encoding повертає, ймовірно, несправну відповідь, деякі рядки, ймовірно, не були UTF-8
  • використання utf8_encode()цих рядків вирішило мою проблему, але див. примітку нижче

Ось рекурсивна функція, яка може змусити перетворити в UTF-8 всі рядки, що містяться в масиві:

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

Використовуйте його просто так:

echo json_encode(utf8ize($data));

Примітка: utf8_encode () кодує рядок ISO-8859-1 до UTF-8 згідно з документами, тому якщо ви не впевнені в кодуванні вводу iconv () або mb_convert_encoding (), можуть бути кращі варіанти, як зазначено в коментарях та інших рішеннях.


4
Дякуємо за ваше рішення ... однак, одна сторона зауваження: Змініть } else {на } else if (is_string ($d)) {; інакше ви зміните все до рядків (наприклад INT, станете a STRING).
Пол Пілен

3
Ти щойно врятував мені життя. Я збирався закінчити все, поки не знайшов цю функцію !! Дякую.
silversunhunter

2
WTF! Дякуємо, що поділилися своїм рішенням. Я можу побачити, що для цього знадобилося б багато копати, і я вдячний тобі за те, що робив це та ділився.
kris

1
Після трьох днів налагодження я можу зараз поцілувати вас.
AJB

2
Якщо читати з бази даних просто використовувати, $ conn-> set_charset ("utf8");
Ендрю Бріггс

36

Matthieu Riegler представив дійсно гарне рішення, проте мені довелося трохи модифікувати його для обробки об'єктів:

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

Ще одна примітка: json_last_error () може бути корисним для налагодження функцій json_encode () / json_encode ().


Чи не повинно бути elseifзамість цього else if? (тобто немає пробілу).
Уве Кеїм

2
@UweKeim згідно з документацією PHP "elseif і інше, якщо будемо вважатись точно таким же самим при використанні фігурних дужок", це означає, що вони є еквівалентами, доки ви не використовуєте позначення двокрапки, наприкладif(): elseif:
Adam Bubela

1
Хороша робота. PHP - це сміття, і такі хлопці, як ти, перешкоджає тому, щоб виходити на смітник
Lonnie Best

Ви повинні вставити else if(is_int($d)||is_bool($d)) return $d;перед останнім іншим через:{"success":true, "message":"Ⲃⲟⲟ𝓵ⲉⲁⲛ ⲁⲛⲇ Ⲓⲛϯⲉ𝓰ⲉꞅ𝛓"}
Девід Refoua

Так само, як @ paul-peelen, рекомендований @ matthieu-riegler: Змініть останнє elseна else if(is_string ($d)); інакше ви зміните все до рядків (наприклад INT, станете a STRING).
Бруно Серрано

30

Для мене відповідь на цю проблему було встановлення charset=utf8в моєму PDO-з'єднанні.

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

2
Або у функціях mysqli: mysqli_set_charset ($ з'єднання, "utf8");
user18099

Це було натяком на моє рішення. Трохи інша причина з'єднання msqli. Просто зателефонуйте $mysqli->set_charset("utf8");після обробки вашої бази даних.
MaggusK

Будь ласка, використовуйте utf8mb4в останніх версіях MySQL. utf8застаріла.
Дхарман

10

Адам Бубела також представив дійсно гарне рішення, яке допомогло мені вирішити свою проблему, і ось спрощена функція:

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
Мені подобається цей, оскільки він зберігає ключі.
dev0

7

У мене точно така ж проблема на PHP 5.6. Я використовую Open Server + Nginx в Windows 7. Усі діаграми встановлені на UTF-8. Теоретично, згідно з офіційною документацією , прапор

JSON_UNESCAPED_UNICODE

повинні вирішити це. На жаль, це не моя справа. Я не знаю чому. Усі фрагменти вище не вирішують моєї проблеми, тому я знайшов власну реалізацію. Я вірю, що це може комусь допомогти. Принаймні, російські букви проходять тест.

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

Ця прийнята відповідь працює. Але у випадку, якщо ви отримуєте свої дані з MySQL (як я), є простіший спосіб.

Після відкриття бази даних, перед запитом ви можете встановити набір символів за допомогою mysqli наступним чином:

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

АБО

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

ЛІНКА: http://php.net/manual/en/mysqli.set-charset.php


4

Я зіткнувся з цим питанням на сервері, на якому працює старша версія PHP (5.2). Я використовував прапор JSON_FORCE_OBJECT, і, мабуть, це не підтримується до 5.3

Тож якщо ви використовуєте цей прапор, обов'язково перевірте свою версію!

Виявляється, що обхідне рішення - це просто перекидання об'єкта перед кодуванням, наприклад:

json_encode((object)$myvar);

3

Повернення mb_detect_encodingможе бути невірним:

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

Залежно від порядку виявлення за замовчуванням, вищезазначене може повертати різні результати, тому про кодування помилково повідомляється як UTF-8. ( Ось більший приклад .)

Цілком імовірно, що ваші дані не кодуються як UTF-8, тому json_encodeповертаються false. Слід поглянути на перетворення рядків у UTF-8 перед кодуванням 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

Я отримував дані від ob_get_clean () і мав ту ж проблему, але вищевикладені рішення не працюють для мене. У моєму випадку рішення було таким, можливо, воно комусь допоможе.

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

2

використання utf8_encode () у цих рядках вирішило мою проблему.


1

Я вдосконалив відповідь Адама Бубела. Я просто ненавиджу це, коли блоки {and} не закриті. Це чистіше, і ви не вводите помилок або, можливо, це те, що я раніше використовував Perl :)

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

Якщо ви отримуєте ці дані з бази даних, використовуйте mysqli_set_charset($connection, "utf8");підключення, коли отримуєте парами з бази даних


0

ця проблема виникає іноді - ви не передаєте контроль доступу до заголовка.

У моєму випадку, якщо до json_encode мені додали відлуння. Він показував результат, інакше виходила порожня сторінка.

я додав

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

і моя проблема вирішена.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.