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? ИЛИ как определить, какая спецификация была получена? Или, может быть, как преобразовать ответ в спецификацию?

Author: Cœur, 2012-09-20

3 answers

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

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

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

Вы можете немного ускорить и обработать еще 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, BOM или не BOM, но нужна mb_string поддержка и вы должны использовать строгий режим, чтобы получить некоторые крайние случаи:

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

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

 4
Author: LSerni, 2017-09-27 09:06:11

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

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

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

 0
Author: sapht, 2017-05-23 12:30:12

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

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

 0
Author: Paul Moldovan, 2017-05-23 12:14:09