не удается преобразовать ответ JSON из windows-1253 в utf8

#php #.net #json #guzzle

#php #.net #json #жрать

Вопрос:

Я пытаюсь проанализировать ответ JSON из веб-службы, которую я не контролирую.

Это заголовки

введите описание изображения здесь

Это тело, которое я вижу в php со скрытыми чувствительными частями

введите описание изображения здесь

Я использую http-клиент guzzle для отправки запроса и получения ответа

Если я попытаюсь декодировать его напрямую, я получу пустой объект, поэтому я предполагаю, что требуется преобразование, поэтому я пытаюсь преобразовать содержимое ответа следующим образом

json_decode(iconv($charset, 'UTF-8', $contents))

или

mb_convert_encoding($contents, 'UTF-8', $charset);

оба из которых генерируют исключение.

Notice: iconv(): Wrong charset, conversion from 'windows-1253' to 'UTF-8' is not allowed in Client.php on line 205

Warning: mb_convert_encoding(): Illegal character encoding specified in Client.php on line 208

Я успешно использовал этот фрагмент кода раньше, но я не могу понять, почему он не работает сейчас.

Отправка того же запроса с использованием POSTMAN корректно извлекает данные без прерывистых символов и, похоже, показывает те же заголовки и тело, что и полученные.

Я обновляю на основе комментариев.

mb_detect_encoding($response->getBody()) -> UTF-8

mb_detect_encoding($response->getBody->getContents()) -> ASCII

json_last_error_msg -> Искаженные символы UTF-8, возможно, неправильно закодированные

Кроме того, в качестве попытки проб и ошибок я перепробовал все кодировки iconv, чтобы узнать, может ли кто-либо преобразовать его в utf-8 без ошибок, чтобы определить кодировку, используя эту

         private function detectEncoding($str){
        $iconvEncodings = [...]
        $finalEncoding = "unknown";
        foreach($iconvEncodings as $encoding){
            try{
                iconv($encoding, 'UTF-8', $str);
                return $encoding;
            }
            catch (Exception $exception){
                continue;
            }
        }
        return $finalEncoding;
    }
  

По-видимому, кодировка не работала, и все выдавало одно и то же исключение. Я предполагаю, что проблема заключается в правильном получении ответа json через guzzle, а не с самим iconv. Не может быть, чтобы это был не один из 1000 .

Еще немного информации с CURL

Я только что повторил ту же полезную нагрузку, используя CURL

   /**
     * @param $options
     * @return bool|string
     */
    public function makeCurlRequest($options)
    {

        $payload = json_encode($options);
        // Prepare new cURL resource
        $ch = curl_init($this->softoneurl);

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,   // return web page
            CURLOPT_HEADER => false,  // don't return headers
            CURLOPT_FOLLOWLOCATION => true,   // follow redirects
            CURLOPT_MAXREDIRS => 10,     // stop after 10 redirects
            CURLOPT_ENCODING => "",     // handle compressed
            CURLOPT_USERAGENT => "test", // name of client
            CURLOPT_AUTOREFERER => true,   // set referrer on redirect
            CURLOPT_CONNECTTIMEOUT => 120,    // time-out on connect
            CURLOPT_TIMEOUT => 120,    // time-out on response
            CURLINFO_HEADER_OUT => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $payload,
        ]);

        // Set HTTP Header for POST request
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json',
                'Content-Length: ' . strlen($payload))
        );

        // Submit the POST request
        $result = curl_exec($ch);

        // Close cURL session handle
        curl_close($ch);
        return $resu<
    }
  

Я получил точно такую же строку и точно такие же результаты при ее преобразовании. Возможно, мне не хватает опции?

По-видимому, что-то не так с самим iconv в среде, и это не зависит от конкретного приложения. Запуск следующего кода через SSH

 php -r "var_dump(iconv('Windows-1253', 'UTF-8', 'test'));"
  

выдает

 PHP Notice:  iconv(): Wrong charset, conversion from `Windows-1253' to `UTF-8' is not allowed in Command line code on line 1
PHP Stack trace:
PHP   1. {main}() Command line code:0
PHP   2. iconv(*uninitialized*, *uninitialized*, *uninitialized*) Command line code:1
Command line code:1:
bool(false)
  

Возможно, какая-то зависимость отсутствует

Комментарии:

1. Что json_last_error_msg() возвращает?

2. Кроме того, что mb_detect_encoding говорит о кодировке? Вы знаете, что это не UTF-8?

3. Я только что обновил свой вопрос тем, что я вижу. Это очень запутанно.

4. Guzzle неправильно считывает результат.

5. mb_convert_encoding() не поддерживает Windows-1253, но iconv() должен работать нормально. JSON должен быть закодирован как UTF-8 (это необязательно), поэтому вам нужно исправить это, прежде чем использовать функции JSON. Я предлагаю вам исправить одну вещь за раз. Например, сохраните ответ в файл, а затем выясните, действительно ли он использует Windows-1253 и iconv() можно ли это исправить.

Ответ №1:

Примерно через 14 часов устранения неполадок я могу правильно ответить на свой вопрос. В моем случае, поскольку это выполнялось в контексте команды CLI, это вызвало проблему из-за отсутствия библиотек. В основном двоичный файл CLI php не имел доступа к некоторым библиотекам, необходимым iconv.

Более конкретно, библиотеки gconv. В моем случае в Debian 9 он был расположен в

/usr/lib/x86_64-linux-gnu/gconv

и эта папка содержит множество библиотек для каждой используемой кодировки. Хороший способ понять это, если вы запускаете в системе, в которой у вас есть root-доступ к команде

strace iconv -f <needed_encoding> -t utf-8

Это приведет к появлению множества папок, к которым iconv пытается получить доступ, включая папку gconv, и укажет вам расположение тех, которые вам нужно включить в вашу среду SSH. Если у вас нет доступа от имени root, вы должны обратиться к своему хостинг-провайдеру.

Ответ №2:

Попробуйте это:

 $response = $guzzle->request('GET', $url);

$type = $response->getHeader('content-type');
$parsed = Psr7parse_header($type);

$original_body = (string)$response->getBody();
$utf8_body = mb_convert_encoding($original_body, 'UTF-8', $parsed[0]['charset'] ?: 'UTF-8');
  

Комментарии:

1. Я уже пробовал этот точный пример из проблем с репозиторием guzzle. Тот же результат, что и раньше.

Ответ №3:

Для тех, у кого была такая же проблема, есть самый простой способ ее решения, я знаю его 3 года спустя, но вы также можете установить некоторые заголовки.

 header('Content-Type: application/json; charset=windows-1253');
  

это мгновенно решило мою проблему.

Комментарии:

1. Если вы проверите, заголовки уже есть в ответе от веб-службы. Однако для них установлено значение windows-1253, в то время как спецификации JSON определяют, что оно должно быть UTF-8. В этом вся проблема. Поскольку мы не можем изменить заголовки для отправки правильной кодировки для JSON, мы должны преобразовать его для чтения, иначе json_decode будет путать символы.