Почему json_encode возвращает пустую строку
У меня есть простая структура php с 3 вложенными массивами.
Я не использую конкретные объекты, и я создаю массивы с двумя вложенными циклами.
Вот пример 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
В другом script у меня похожая структура, а json_encode
отлично работает.
Поэтому я не понимаю, почему json_encode
здесь не будет работать.
Изменить: похоже, проблема с кодировкой. Когда mb_detect_encoding
возвращает ASCII, json_encode
работает, но когда он возвращает UTF8, он больше не работает.
Edit2: json_last_error()
возвращает JSON_ERROR_UTF8
, что означает: Неправильные символы UTF-8, возможно, неправильно закодированные.
Ответы
Ответ 1
Через 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() могут быть лучшими вариантами, как отмечено в комментариях и других решениях.
Ответ 2
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().
Ответ 3
Для меня ответ на эту проблему заключался в установке charset = utf8 в моем подключении PDO.
например: $dbo = new PDO('mysql:host=localhost;dbname=yourdb;charset=utf8', $username, $password);
Ответ 4
Адам Бубела также представил действительно хорошее решение, которое помогло мне решить мою проблему, и вот упрощенная функция:
function utf8ize($d)
{
if (is_array($d) || is_object($d))
foreach ($d as &$v) $v = utf8ize($v);
else
return utf8_encode($d);
return $d;
}
Ответ 5
Я столкнулся с этой проблемой на сервере, на котором установлена более старая версия PHP (5.2). Я использовал флаг JSON_FORCE_OBJECT и, по-видимому, не поддерживался до 5.3
Итак, если вы используете этот флаг, обязательно проверьте свою версию!
Обходной путь - это просто кастинг для объекта перед кодированием, например:
json_encode((object)$myvar);
Ответ 6
У меня точно такая же проблема на 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;
}
Ответ 7
Возврат 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);
Ответ 8
Этот принятый ответ работает. Но если вы получаете данные из 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();
}
LINK:
http://php.net/manual/en/mysqli.set-charset.php
Ответ 9
с помощью utf8_encode() на этой строке решена моя проблема.
Ответ 10
Я получал данные от ob_get_clean() и имел ту же проблему, но выше решения не работают для меня. В моем случае решение было так, возможно, это поможет кому-то.
$var = mb_convert_encoding($var, 'UTF-8');
Ответ 11
Я улучшил ответ Адама Бубелы.
Я просто ненавижу, когда блоки не закрыты {и}.
Это чище, и вы не вводите ошибки или, возможно, это то, что я использовал 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;
}
}
?>
Ответ 12
Если вы получаете эти данные из базы данных, используйте mysqli_set_charset($connection, "utf8");
в связи, когда получить параметры из базы данных
Ответ 13
эта проблема возникает иногда - вы не проходите контроль доступа заголовка.
В моем случае, если бы я добавил какое-либо эхо перед json_encode. Это показывало результат, иначе была пустая страница.
я добавил
header('Access-Control-Allow-Origin: *');
и моя проблема решена.