cURL получает ответ со спецификацией utf-8

В моем скрипте я отправляю данные с помощью cURL и включил CURLOPT_RETURNTRANSFER. Ответ представляет собой данные в формате json. Когда я пытаюсь использовать json_decode, он возвращает null. Затем я обнаружил, что ответ содержит символы спецификации utf-8 в начале строки ().

Есть эксперименты:


$data = $data = curl_exec($ch);
echo $data;

результат {"поле_1":"текст_1","поле_2":"текст_2","поле_3":"текст_3"}

$data = $data = curl_exec($ch);
echo mb_detect_encoding($data);

результат - UTF-8

$data = $data = curl_exec($ch);
echo mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
// identical to echo mb_convert_encoding($data, 'UTF-8', 'UTF-8');

результат - {"поле_1":"текст_1","поле_2":"текст_2","поле_3":"текст_3"}


Единственное, что помогает, это удалить первые 3 символа:

if (substr($data, 0, 3) == pack('CCC', 239, 187, 191)) {
    $data = substr($data, 3);
}

Но что, если будет другая спецификация? Итак, вопрос: как определить правильную кодировку ответа cURL? ИЛИ как определить, какая спецификация прибыла? Или, может быть, как преобразовать ответ с BOM?


person Reshat Belyalov    schedule 20.09.2012    source источник


Ответы (3)


Боюсь, вы уже нашли ответ самостоятельно - плохие новости в том, что лучшего ответа, насколько я знаю, не существует.

Спецификации не должно быть там, и отправитель несет ответственность за то, чтобы не отправлять ее.

Но могу вас успокоить, спецификация либо есть, либо ее нет, а если и есть, то это те три байта, которые вы знаете.

Вы можете сделать немного быстрее и обработать другие N спецификаций с небольшим изменением:

$__BOM = pack('CCC', 239, 187, 191);
// Careful about the three ='s -- they're all needed.
while(0 === strpos($data, $__BOM))
    $data = substr($data, 3);

Детектор спецификации стороннего производителя ничем не отличается. Таким образом, вы защищены, даже если позже cURL начнет удалять ненужные спецификации.

Возможные причины

Некоторые оптимизаторы и фильтры JSON могут решить, что для вывода требуется спецификация. Кроме того, возможно, проще говоря, тот, кто написал сценарий, генерирующий JSON, непреднамеренно включил спецификацию перед открывающим тегом PHP. Apache, не заботясь о том, что такое спецификация, видит данные перед открывающим тегом, поэтому отправляет их и скрывает от самого потока PHP. Иногда это также может вызывать ошибку «Невозможно добавить заголовки: вывод уже начался».

Обнаружение контента

Вы можете убедиться, что JSON является допустимым UTF-8, спецификацией или не спецификацией, но вам нужна mb_string поддержка и вы должны использовать строгий режим, чтобы получить некоторые крайние случаи:

if (false === mb_detect_encoding($data, 'UTF-8', true)) {
    // JSON contains invalid sequences (erroneously NOT JSON encoded)
}

Я бы посоветовал против пытаться исправить возможную ошибку кодирования; вы рискуете сломать собственный код, а также вам придется поддерживать чужую работу.

person LSerni    schedule 20.09.2012

На этой странице описана аналогичная проблема: BOM на странице PHP, созданной автоматически. от Wordpress

По сути, это может произойти, когда генератор JSON написан на PHP, а редактор каким-то образом проник в спецификацию перед открывающим тегом <?php. Поскольку ваш клиентский язык - PHP, я предполагаю, что это актуально.

Вы можете удалить его, используя сравнение substr — спецификация появляется только в начале документа. Но если у вас есть контроль над источником JSON, вам следует вместо этого удалить спецификацию из исходного документа.

person sapht    schedule 20.09.2012

Перед "{" никогда не будет более 3 символов. Эти 3 символа являются одним символом в UTF-8. Итак, если вы просто выполните $data = substr($data, 3); с тобой все будет в порядке.

Посмотрите здесь для получения дополнительной информации: json_decode возвращает NULL после вызова веб-службы

person Paul Moldovan    schedule 20.09.2012
comment
Это не очень хорошая идея, если вы перемещаетесь между разными платформами, где спецификация не всегда выводится, удаляйте ее только в том случае, если она обнаружена, иначе вы можете удалить фактические данные. - person nights; 05.03.2019