В моем сценарии я отправляю данные с помощью cURL и включаю CURLOPT_RETURNTRANSFER. Ответ – это json-кодированные данные. Когда я пытаюсь json_decode, он возвращает null. Затем я обнаружил, что ответ содержит символы спецификации utf-8 в начале строки (ï »¿).
Есть несколько экспериментов:
$data = $data = curl_exec($ch); echo $data;
результат: {"field_1": "text_1", "field_2": "text_2", "field_3": "text_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');
результат – ï »¿{" field_1 ":" text_1 "," field_2 ":" text_2 "," field_3 ":" text_3 "}
Единственное, что помогает – удалить первые 3 символа:
if (substr($data, 0, 3) == pack('CCC', 239, 187, 191)) { $data = substr($data, 3); }
Но что, если будет другая спецификация? Поэтому возникает вопрос: как определить правильное кодирование ответа cURL? ИЛИ как определить, какая спецификация появилась? Или, может быть, как преобразовать ответ с помощью спецификации?
Боюсь, что вы уже нашли ответ самостоятельно – это плохая новость в том, что лучшего ответа я не знаю.
Спецификация не должна быть там, и ответственность отправителя не должна посылать ее.
Но я могу вас успокоить, спецификация есть либо там, либо нет, и если да, это те три байта, которые вы знаете.
У вас может быть немного быстрее и обрабатывать другие 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) }
Я бы посоветовал не пытаться исправить возможную ошибку кодирования; вы рискуете нарушить свой собственный код, а также должны поддерживать чужую работу.
Эта страница описывает аналогичную проблему: спецификация на странице PHP, автоматически созданная WordPress
В принципе, это может произойти, когда генератор JSON написан на PHP, и редактор каким-то образом пробрался в спецификации перед открывающим <?php
. Поскольку ваш клиентский язык является PHP, я предполагаю, что это актуально.
Вы можете разбить его, используя сравнение substr
– спецификация только когда-либо встречается в начале документа. Но если у вас есть контроль над источником JSON, вы должны удалить спецификацию из исходного документа.
Перед «{» никогда не будет больше 3 символов. Эти 3 символа являются одним символом в UTF-8. Итак, если вы просто делаете $ data = substr ($ data, 3); с тобой все будет в порядке.
Взгляните сюда для получения дополнительной информации: json_decode возвращает NULL после вызова webservice