src/GuzzleTranscoder.php
public function convertResponse(array $headers, $content) {
        $headerDeclaredEncoding = null;
        $bodyDeclaredEncoding = null;
        $replacements = [
            'headers' => [],
            'content' => null,
        ];

        $contentType = self::getByCaseInsensitiveKey($headers, 'content-type');
        if ($contentType === null) {
            $contentType = '';
        } elseif (\is_array($contentType)) {
            $contentType = $contentType[0];
        }

        $parsed = Utils::splitHttpHeaderWords($contentType);
        if (\count($parsed) > 0) {
            $parsed = reset($parsed);
        }
        //check the header
        $encoding = self::getByCaseInsensitiveKey($parsed, 'charset');
        if ($encoding !== null) {
            $headerDeclaredEncoding = $encoding;
        }
        $newParsed = self::setByCaseInsensitiveKey($parsed, 'charset', $this->targetEncoding);
        $replacements['headers']['content-type'] = Utils::joinHttpHeaderWords($newParsed);
        // else, check the body
        if (preg_match('#^text/html#i', $contentType)) {
            // find http-equiv
            $patternHtml4 = "#<meta[^>]+http-equiv=[\"']?content-type[\"']?[^>]*?>#i"; // html 4 - e.g. <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
            $patternHtml5 = "#(?P<before><meta[^>]+?)charset=(?P<quote>[\"'])(?P<charset>[^\"' ]+?)\\2(?P<after>[^>]*?>)#i"; // e.g. <meta charset=iso-8859-1> - for html 5 http://webdesign.about.com/od/metatags/qt/meta-charset.htm
            if (preg_match($patternHtml4, $content, $match)) {
                $pattern = "#(?P<before>.*)content=(?P<quote>[\"'])(?P<content>.*?)\\2(?P<after>.*)#";
                if (preg_match($pattern, $match[0], $innerMatch)) {
                    $parsed = Utils::splitHttpHeaderWords($innerMatch['content']);
                    if (\count($parsed) > 0) {
                        $parsed = reset($parsed);
                    }
                    $bodyDeclaredEncoding = self::getByCaseInsensitiveKey($parsed, 'charset');
                    $newParsed = self::setByCaseInsensitiveKey($parsed, 'charset', $this->targetEncoding);
                    $newContent = Utils::joinHttpHeaderWords($newParsed);
                    $newMeta = $innerMatch['before'] . "content={$innerMatch['quote']}" . $newContent . "{$innerMatch['quote']}" . $innerMatch['after'];
                    $replacements['content'][$match[0]] = $newMeta;
                }
            } elseif (preg_match($patternHtml5, $content, $match)) {
                $bodyDeclaredEncoding = $match['charset'];
                $newMeta = $match['before'] . "charset={$match['quote']}" . $this->targetEncoding . "{$match['quote']}" . $match['after'];
                $replacements['content'][$match[0]] = $newMeta;
            }
        } elseif (preg_match('#^(text|application)/xml#i', $contentType)) { // see http://stackoverflow.com/a/3272572/413531
            $patternXml = "#(?P<before><\\?xml[^>]+?)encoding=(?P<quote>[\"'])(?P<charset>[^\"']+?)\\2(?P<after>[^>]*?>)#i";
            if (preg_match($patternXml, $content, $match)) {
                $bodyDeclaredEncoding = $match['charset'];
                $newMeta = $match['before'] . "encoding={$match['quote']}" . $this->targetEncoding . "{$match['quote']}" . $match['after'];
                $replacements['content'][$match[0]] = $newMeta;
            }
        }

        $finalEncoding = null;
        if ($bodyDeclaredEncoding !== null) {
            $finalEncoding = $bodyDeclaredEncoding;
        } elseif ($headerDeclaredEncoding !== null) {
            $finalEncoding = $headerDeclaredEncoding;
        } else {
            return null;
        }

        $headers_new = $headers;
        if ($this->replaceHeaders) {
            foreach ($replacements['headers'] as $headerKey => $value) {
                $headers_new = self::setByCaseInsensitiveKey($headers_new, $headerKey, $value);
            }
        }

        $converted = $this->createTranscoder()->transcode($content, $finalEncoding, $this->targetEncoding);
        $converted_new = $converted;
        if ($this->replaceContent) {
            if ($replacements['content'] !== null) {
                foreach ($replacements['content'] as $oldContent => $newContent) {
                    $converted_new = str_replace($oldContent, $newContent, $converted_new);
                }
            }
        }

        return [
            'headers' => $headers_new,
            'content' => $converted_new,
        ];
    }
public function convertResponse(array $headers, $content) {
        $headerDeclaredEncoding = null;
        $bodyDeclaredEncoding = null;
        $replacements = [
            'headers' => [],
            'content' => null,
        ];

        $contentType = self::getByCaseInsensitiveKey($headers, 'content-type');
        if ($contentType === null) {
            $contentType = '';
        } elseif (\is_array($contentType)) {
            $contentType = $contentType[0];
        }

        $parsed = Utils::splitHttpHeaderWords($contentType);
        if (\count($parsed) > 0) {
            $parsed = reset($parsed);
        }
        //check the header
        $encoding = self::getByCaseInsensitiveKey($parsed, 'charset');
        if ($encoding !== null) {
            $headerDeclaredEncoding = $encoding;
        }
        $newParsed = self::setByCaseInsensitiveKey($parsed, 'charset', $this->targetEncoding);
        $replacements['headers']['content-type'] = Utils::joinHttpHeaderWords($newParsed);
        // else, check the body
        if (preg_match('#^text/html#i', $contentType)) {
            // find http-equiv
            $patternHtml4 = "#<meta[^>]+http-equiv=[\"']?content-type[\"']?[^>]*?>#i"; // html 4 - e.g. <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
            $patternHtml5 = "#(?P<before><meta[^>]+?)charset=(?P<quote>[\"'])(?P<charset>[^\"' ]+?)\\2(?P<after>[^>]*?>)#i"; // e.g. <meta charset=iso-8859-1> - for html 5 http://webdesign.about.com/od/metatags/qt/meta-charset.htm
            if (preg_match($patternHtml4, $content, $match)) {
                $pattern = "#(?P<before>.*)content=(?P<quote>[\"'])(?P<content>.*?)\\2(?P<after>.*)#";
                if (preg_match($pattern, $match[0], $innerMatch)) {
                    $parsed = Utils::splitHttpHeaderWords($innerMatch['content']);
                    if (\count($parsed) > 0) {
                        $parsed = reset($parsed);
                    }
                    $bodyDeclaredEncoding = self::getByCaseInsensitiveKey($parsed, 'charset');
                    $newParsed = self::setByCaseInsensitiveKey($parsed, 'charset', $this->targetEncoding);
                    $newContent = Utils::joinHttpHeaderWords($newParsed);
                    $newMeta = $innerMatch['before'] . "content={$innerMatch['quote']}" . $newContent . "{$innerMatch['quote']}" . $innerMatch['after'];
                    $replacements['content'][$match[0]] = $newMeta;
                }
            } elseif (preg_match($patternHtml5, $content, $match)) {
                $bodyDeclaredEncoding = $match['charset'];
                $newMeta = $match['before'] . "charset={$match['quote']}" . $this->targetEncoding . "{$match['quote']}" . $match['after'];
                $replacements['content'][$match[0]] = $newMeta;
            }
        } elseif (preg_match('#^(text|application)/xml#i', $contentType)) { // see http://stackoverflow.com/a/3272572/413531
            $patternXml = "#(?P<before><\\?xml[^>]+?)encoding=(?P<quote>[\"'])(?P<charset>[^\"']+?)\\2(?P<after>[^>]*?>)#i";
            if (preg_match($patternXml, $content, $match)) {
                $bodyDeclaredEncoding = $match['charset'];
                $newMeta = $match['before'] . "encoding={$match['quote']}" . $this->targetEncoding . "{$match['quote']}" . $match['after'];
                $replacements['content'][$match[0]] = $newMeta;
            }
        }

        $finalEncoding = null;
        if ($bodyDeclaredEncoding !== null) {
            $finalEncoding = $bodyDeclaredEncoding;
        } elseif ($headerDeclaredEncoding !== null) {
            $finalEncoding = $headerDeclaredEncoding;
        } else {
            return null;
        }

        $headers_new = $headers;
        if ($this->replaceHeaders) {
            foreach ($replacements['headers'] as $headerKey => $value) {
                $headers_new = self::setByCaseInsensitiveKey($headers_new, $headerKey, $value);
            }
        }

        $converted = $this->createTranscoder()->transcode($content, $finalEncoding, $this->targetEncoding);
        $converted_new = $converted;
        if ($this->replaceContent) {
            if ($replacements['content'] !== null) {
                foreach ($replacements['content'] as $oldContent => $newContent) {
                    $converted_new = str_replace($oldContent, $newContent, $converted_new);
                }
            }
        }

        return [
            'headers' => $headers_new,
            'content' => $converted_new,
        ];
    }
Converts the given $content to the $targetEncoding.

The original encoding is defined by (in order):
- the 'charset' parameter of the 'content-type' header
- the meta information in the body of an HTML (content-type: text/html)or XML (content-type: text/xml or application/xml) document

If the original encoding could not be determined, null is returned.

Otherwise an object of type EncodingResult is returned. Please see the description of the properties of said class.

@param array $headers
@param string $content

@return EncodingResult|null