LoginSignup
0
0

More than 3 years have passed since last update.

【Laravel】GuzzleでEUC-JPのページを受信すると文字化け→cURLの受信結果を適切にエンコードして解決

Posted at

現象

  1. LaravelでHTTP通信するならGuzzleらしい
  2. 試す。受信結果が文字化けする
  3. cURLベースで書き直す
  4. やっぱり文字化けする
  5. EUC-JPのページで発生している

解決

以下のエントリを参考に、cURLでの受信結果を適切に変換することで文字化けを防ぐことができた。

コード

function curl_get_contents($url, $timeout = 60) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
    $result = $this->curl_exec_utf8($ch);
    curl_close($ch);
    return $result;
  }

  function curl_exec_utf8($ch) {
    $data = curl_exec($ch);
    if (!is_string($data))
        return $data;

    unset($charset);
    $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

    /* 1: HTTP Content-Type: header */
    preg_match('@([\w/+]+)(;\s*charset=(\S+))?@i', $content_type, $matches);
    if (isset($matches[3]))
        $charset = $matches[3];

     /* 2: <meta> element in the page */
     if (!isset($charset)) {
      preg_match( '@<meta\s+http-equiv="Content-Type"\s+content="([\w/]+)(;\s*charset=([^\s"]+))?@i', $data, $matches );
      if ( isset( $matches[3] ) ) {
          $charset = $matches[3];
          /* In case we want do do further processing downstream: */
          $data = preg_replace('@(<meta\s+http-equiv="Content-Type"\s+content="[\w/]+\s*;\s*charset=)([^\s"]+)@i', '$1utf-8', $data, 1);
      }
    }

    /* 3: <xml> element in the page */
    if (!isset($charset)) {
        preg_match( '@<\?xml.+encoding="([^\s"]+)@si', $data, $matches );
        if ( isset( $matches[1] ) ) {
            $charset = $matches[1];
            /* In case we want do do further processing downstream: */
            $data = preg_replace('@(<\?xml.+encoding=")([^\s"]+)@si', '$1utf-8', $data, 1);
        }
    }

    /* 4: PHP's heuristic detection */
    if (!isset($charset)) {
        $encoding = mb_detect_encoding($data);
        if ($encoding)
            $charset = $encoding;
    }

    /* 5: Default for HTML */
    if (!isset($charset)) {
        if (strstr($content_type, "text/html") === 0)
            $charset = "ISO 8859-1";
    }

    /* Convert it if it is anything but UTF-8 */
    /* You can change "UTF-8"  to "UTF-8//IGNORE" to
      ignore conversion errors and still output something reasonable */
    if (isset($charset) && strtoupper($charset) != "UTF-8")
        $data = iconv($charset, 'UTF-8', $data);

    return $data;
  }

gzipオプションについて

curl_setopt($ch, CURLOPT_ENCODING, 'gzip');はサーバー依存です。

筆者の環境では、gzipで圧縮されたレスポンスが返ってくるため必要でした。
(参考:PHPのcurl()でレスポンスが文字化けしたら確認すること2つ - PHP | ゆるりの足あと

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0