【问题标题】:cannot convert JSON response from windows-1253 to utf8无法将 JSON 响应从 windows-1253 转换为 utf8
【发布时间】:2019-04-13 07:45:34
【问题描述】:

我正在尝试解析来自我无法控制的 Web 服务的 JSON 响应。

这些是标题

这是我在php中看到的隐藏敏感部分的主体

我正在使用 guzzle http 客户端发送请求并检索响应

如果我尝试直接解码它,我会收到一个空对象,所以我假设需要转换,所以我尝试像这样转换响应内容

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 发送相同的请求可以正确检索没有损坏字符的数据,并且似乎显示接收到的相同标头和正文。

我正在根据 cmets 进行更新。

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;
    }

显然没有编码工作,一切都给出了同样的例外。我假设问题在于通过 guzzle 正确检索响应 json 而不是 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 $result;
    }

我收到了完全相同的字符串和转换后的完全相同的结果。也许我缺少一个选项?

显然,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)

可能缺少一些依赖

【问题讨论】:

  • json_last_error_msg() 返回什么?
  • 另外,mb_detect_encoding 说的编码是什么?你知道它不是 UTF-8 吗?
  • 我刚刚用我所看到的更新了我的问题。这很混乱。
  • Guzzle 没有正确读取结果。
  • mb_convert_encoding() 不是 support Windows-1253 但 iconv() 应该可以正常工作。 JSON 必须编码为 UTF-8(它不是可选的),因此您需要在使用 JSON 函数之前对其进行修复。我建议你一次解决一件事。例如,将响应保存到文件,然后确定它是否真的使用 Windows-1253 以及 iconv() 是否可以修复它。

标签: php .net json guzzle


【解决方案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 = Psr7\parse_header($type);
    
    $original_body = (string)$response->getBody();
    $utf8_body = mb_convert_encoding($original_body, 'UTF-8', $parsed[0]['charset'] ?: 'UTF-8');
    

    【讨论】:

    • 我已经从 guzzle 存储库问题中尝试过这个确切的示例。结果和以前一样。
    猜你喜欢
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 2021-09-03
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    相关资源
    最近更新 更多