인코딩을 감지하고 모든 것을 UTF-8로 만듭니다.


304

다양한 RSS 피드에서 많은 텍스트를 읽고 데이터베이스에 삽입하고 있습니다.

물론 피드에 사용되는 여러 가지 다른 문자 인코딩 (예 : UTF-8 및 ISO 8859-1)이 있습니다.

불행히도 때때로 텍스트 인코딩에 문제가 있습니다. 예:

  1. "Fußball"의 "ß"는 내 데이터베이스에서 다음과 같아야합니다 : "Ÿ". "Â"인 경우 올바르게 표시됩니다.

  2. 때때로, "Fußball"의 "ß"는 내 데이터베이스에서 다음과 같이 보입니다 : "ßÂ". 그런 다음 물론 잘못 표시됩니다.

  3. 다른 경우에는 "ß"가 "ß"로 저장되므로 변경하지 않아도됩니다. 그런 다음 잘못 표시됩니다.

사례 2와 3을 피하려면 어떻게해야합니까?

모든 것을 동일한 인코딩, 어떻게 UTF-8로 만들 수 있습니까? 언제 사용해야합니까 utf8_encode(), 언제 사용해야합니까 utf8_decode()(효과는 무엇인지하지만 언제 기능을 사용해야합니까?) 그리고 입력으로 아무것도하지 않아야합니까?

모든 것을 동일한 인코딩으로 만들려면 어떻게합니까? 아마도 기능 mb_detect_encoding()? 이것에 대한 함수를 작성할 수 있습니까? 그래서 내 문제는 다음과 같습니다

  1. 텍스트가 어떤 인코딩을 사용하는지 어떻게 알 수 있습니까?
  2. 이전 인코딩이 무엇이든 UTF-8로 어떻게 변환합니까?

이와 같은 기능이 작동합니까?

function correct_encoding($text) {
    $current_encoding = mb_detect_encoding($text, 'auto');
    $text = iconv($current_encoding, 'UTF-8', $text);
    return $text;
}

테스트했지만 작동하지 않습니다. 무슨 일이야?


36
"Fußball"의 "ß"는 다음과 같습니다 : "Ÿ". " 아니요 ß처럼 보일 것입니다. 데이터 정렬 및 연결이 올바르게 설정되어 있는지 확인하십시오. 그렇지 않으면 정렬 및 검색이 중단됩니다.
Rich Bradshaw

5
데이터베이스가 잘못 설정되었습니다. 유니 코드 컨텐츠를 저장하려면 해당 컨텐츠를 구성하십시오. 따라서 PHP 코드에서 문제를 해결하려고 시도하는 대신 먼저 데이터베이스를 수정해야합니다.
dolmen

2
사용 : $ from = mb_detect_encoding ($ text); $ text = mb_convert_encoding ($ text, 'UTF-8', $ from);
Informate.it

답변:


363

utf8_encode()이미 UTF-8 문자열에 적용 하면 잘못된 UTF-8 출력이 반환됩니다.

이 모든 문제를 해결하는 기능을 만들었습니다. 이라고 Encoding::toUTF8()합니다.

문자열 인코딩이 무엇인지 알 필요가 없습니다. Latin1 ( ISO 8859-1) , Windows-1252 또는 UTF-8이거나 문자열에 혼합되어있을 수 있습니다. Encoding::toUTF8()모든 것을 UTF-8로 변환합니다.

서비스가 UTF-8과 Latin1을 동일한 문자열로 혼합하여 모든 엉망인 데이터 피드를 제공했기 때문에 그렇게했습니다.

용법:

require_once('Encoding.php');
use \ForceUTF8\Encoding;  // It's namespaced now.

$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);

$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);

다운로드 :

https://github.com/neitanod/forceutf8

또 다른 함수를 포함 시켰습니다.이 기능 Encoding::fixUFT8()은 깨져 보이는 모든 UTF-8 문자열을 수정합니다.

용법:

require_once('Encoding.php');
use \ForceUTF8\Encoding;  // It's namespaced now.

$utf8_string = Encoding::fixUTF8($garbled_utf8_string);

예 :

echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");

출력합니다 :

Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football

함수 ( forceUTF8)를라는 클래스에서 정적 함수 패밀리로 변환했습니다 Encoding. 새로운 기능은 Encoding::toUTF8()입니다.


1
코드를 보면 fixUTF8은 문자열이 변경되지 않고 리턴 될 때까지 forceUTF8을 여러 번 호출합니다. fixUTF8 ()에 대한 한 번의 호출은 forceUTF8 ()에 대한 호출 시간의 두 배 이상이 소요되므로 성능이 훨씬 떨어집니다. "encode-corrupted"파일을 수정하는 명령 행 프로그램을 작성하기 위해 fixUTF8 ()을 작성했지만 실제 환경에서는 거의 필요하지 않습니다.
Sebastián Grignoli

3
유효하지 않은 문자로 어떤 인코딩을 시작해야하는지 알지 못하는 상태에서 비 UTF8 문자를 UTF8로 어떻게 변환합니까?
philfreo

4
그것은 ISO-8859-1을 가정하고 대답은 이미 이것을 말합니다. forceUTF8 ()과 utf8_encode ()의 유일한 차이점은 forceUTF8 ()이 UTF8 문자를 인식하여 변경하지 않고 유지한다는 것입니다.
Sebastián Grignoli

28
"문자열 인코딩이 무엇인지 알 필요가 없습니다." -매우 동의하지 않습니다. 추측하고 노력해도 효과가있을 수 있지만 조만간 그렇지 않은 경우가 있습니다.
deceze

4
전적으로 동의합니다. 사실, 나는 일반적으로이 수업이 당신이 자신을 발견 한 상황이라면 도움이 될 것이라고 설명하지는 않았습니다.
Sebastián Grignoli

74

먼저 어떤 인코딩이 사용되었는지 감지해야합니다. RSS 피드를 분석 할 때 (아마 HTTP를 통해) HTTP 헤더 필드charset매개 변수 에서 인코딩을 읽어야합니다 . 존재하지 않으면 XML 처리 명령 의 속성 에서 인코딩을 읽으십시오 . 그것이 누락 된 경우 사양에 정의 된 UTF-8을 사용하십시오 .Content-Typeencoding


편집    여기 내가 아마 할 것입니다 :

cURL 을 사용 하여 응답을 보내고 가져옵니다. 이를 통해 특정 헤더 필드를 설정하고 응답 헤더를 가져올 수 있습니다. 응답을 가져온 후 HTTP 응답을 구문 분석하고 헤더와 본문으로 분할해야합니다. 그런 다음 Content-Type헤더에는 MIME 유형과 charset인코딩 / 문자 세트가 있는 매개 변수가 포함 된 헤더 필드가 포함 되어야합니다 . 그렇지 않은 경우 encoding특성 이 있는지 XML PI를 분석하고 거기서 인코딩을 가져옵니다. 또한 누락 된 경우 XML 스펙은 UTF-8을 인코딩으로 사용하도록 정의합니다.

$url = 'http://www.lr-online.de/storage/rss/rss/sport.xml';

$accept = array(
    'type' => array('application/rss+xml', 'application/xml', 'application/rdf+xml', 'text/xml'),
    'charset' => array_diff(mb_list_encodings(), array('pass', 'auto', 'wchar', 'byte2be', 'byte2le', 'byte4be', 'byte4le', 'BASE64', 'UUENCODE', 'HTML-ENTITIES', 'Quoted-Printable', '7bit', '8bit'))
);
$header = array(
    'Accept: '.implode(', ', $accept['type']),
    'Accept-Charset: '.implode(', ', $accept['charset']),
);
$encoding = null;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
$response = curl_exec($curl);
if (!$response) {
    // error fetching the response
} else {
    $offset = strpos($response, "\r\n\r\n");
    $header = substr($response, 0, $offset);
    if (!$header || !preg_match('/^Content-Type:\s+([^;]+)(?:;\s*charset=(.*))?/im', $header, $match)) {
        // error parsing the response
    } else {
        if (!in_array(strtolower($match[1]), array_map('strtolower', $accept['type']))) {
            // type not accepted
        }
        $encoding = trim($match[2], '"\'');
    }
    if (!$encoding) {
        $body = substr($response, $offset + 4);
        if (preg_match('/^<\?xml\s+version=(?:"[^"]*"|\'[^\']*\')\s+encoding=("[^"]*"|\'[^\']*\')/s', $body, $match)) {
            $encoding = trim($match[1], '"\'');
        }
    }
    if (!$encoding) {
        $encoding = 'utf-8';
    } else {
        if (!in_array($encoding, array_map('strtolower', $accept['charset']))) {
            // encoding not accepted
        }
        if ($encoding != 'utf-8') {
            $body = mb_convert_encoding($body, 'utf-8', $encoding);
        }
    }
    $simpleXML = simplexml_load_string($body, null, LIBXML_NOERROR);
    if (!$simpleXML) {
        // parse error
    } else {
        echo $simpleXML->asXML();
    }
}

감사. 이것은 쉬울 것입니다. 그러나 실제로 작동합니까? HTTP 헤더 또는 XML 속성에 잘못된 인코딩이 제공되는 경우가 종종 있습니다.
caw

25
다시 : 그것은 당신의 문제가 아닙니다. 이러한 문제를 피하기 위해 표준이 확립되었습니다. 다른 사람들이 따르지 않으면 문제가 아니라 자신의 문제입니다.
Gumbo

좋아, 이제 네가 마침내 나를 설득했다고 생각한다. :)
caw

코드 주셔서 감사합니다. 그러나 왜 이것을 단순히 사용하지 않습니까? paste.bradleygill.com/index.php?paste_id=9651 코드가 훨씬 더 복잡합니다. 더 나은 점은 무엇입니까?
caw

먼저 HTTP 헤더와 데이터에 대한 두 가지 요청을 수행합니다. 둘째, 당신은 어떤의 모습을 찾고 charset=encoding=뿐만 아니라 적절한 위치에서합니다. 셋째, 선언 된 인코딩이 허용되는지 확인하지 않습니다.
Gumbo

39

인코딩 감지가 어렵습니다.

mb_detect_encoding당신이 그것을 통과 많은 후보에 따라 추측하여 작동합니다. 일부 인코딩에서는 특정 바이트 시퀀스가 ​​유효하지 않으므로 다양한 후보를 구별 할 수 있습니다. 불행히도 동일한 바이트가 유효하지만 다른 인코딩이 많은 인코딩이 있습니다. 이 경우 인코딩을 결정할 방법이 없습니다. 이 경우 자신의 논리를 구현하여 추측 할 수 있습니다. 예를 들어, 일본어 사이트에서 오는 데이터는 일본어 인코딩을 가질 가능성이 높습니다.

오래 당신은 서유럽 언어를 다루는 등, 세 가지 주요 인코딩 고려 있습니다합니다 utf-8, iso-8859-1하고 cp-1252. 이는 많은 플랫폼의 기본값이므로 잘못보고 될 가능성이 가장 높습니다. 예 : 사람들이 다른 인코딩을 사용하는 경우 소프트웨어가 매우 자주 중단 될 수 있으므로 솔직 할 것입니다. 따라서 인코딩이이 세 가지 중 하나로보고되지 않는 한 공급자를 신뢰하는 것이 좋습니다. 당신은 여전히 사용, 실제로 유효한지 번 확인해야한다 mb_check_encoding(참고 유효가 동일하지 않습니다 되는 - 동일한 입력이 많은 인코딩 유효 할 수있다)를. 그 중 하나라면 다음을 사용할 수 있습니다.mb_detect_encoding그들 사이를 구별하기 위해. 운 좋게도 그것은 결정 론적입니다. 적절한 검색 순서를 사용해야합니다 UTF-8,ISO-8859-1,WINDOWS-1252.

인코딩을 감지하면 내부 표현으로 변환해야합니다 UTF-8. 함수 utf8_encode변환 ISO-8859-1으로는 UTF-8, 그래서 그것은 단지 특정 타입의 입력에 사용될 수있다. 다른 인코딩의 경우을 사용하십시오 mb_convert_encoding.


대단히 감사합니다! 더 나은 점 : mb-convert-encoding () 또는 iconv ()? 차이점이 무엇인지 모르겠습니다. 예, 서유럽 언어, 특히 영어, 독일어 및 프랑스어 만 구문 분석하면됩니다.
caw

7
방금 보았습니다 : mb-detect-encoding ()은 쓸모가 없습니다. UTF-8, UTF-7, ASCII, EUC-JP, SJIS, eucJP-win, SJIS-win, JIS 및 ISO-2022-JP 만 지원합니다. 나에게 가장 중요한 ISO-8859-1 및 WINDOWS-1252는 지원되지 않습니다. 따라서 mb-detect-encoding ()을 사용할 수 없습니다.
caw

1
내 말이 맞아 내가 사용한지 오래되었습니다. 그런 다음 자체 감지 코드를 작성하거나 외부 유틸리티를 사용해야합니다. 이스케이프 시퀀스는 특성상 UTF-8은 상당히 안정적으로 결정될 수 있습니다. wp-1252는 iso-8859-1에서 잘못된 바이트를 포함 할 수 있으므로 wp-1252와 iso-8859-1을 구별 할 수 있습니다. Wikipedia를 사용하여 자세한 정보를 얻거나 php.net의 의견 섹션에서 다양한 문자 세트 관련 함수를 찾으십시오.
troelskn

특수한 노래가 나오는 형식을 볼 때 다른 인코딩을 구별 할 수 있다고 생각합니다. 독일 "ß"는 다른 형식으로 나타납니다. 때때로 "Â", 때로는 "ß"및 "ß". 왜?
caw

그렇습니다. 그러나 문자열을 비교하기 전에 문자열의 내용을 알아야합니다. 그런 종류의 첫 번째 목적은 패배합니다. 독일어 ß는 인코딩마다 값이 다르기 때문에 다르게 나타납니다. Somce 문자는 다른 인코딩으로 동일한 방식으로 표시됩니다 (예 : ASCII 문자 집합의 모든 문자는 utf-8, iso-8859- * 및 wp-1252에서 동일한 방식으로 인코딩 됨). 그 캐릭터들만 다 똑같아 보입니다. 그렇기 때문에 그들은 종종 ascii 호환이라고합니다.
troelskn 2016 년

14

정말 구현하는 좋은 방법 isUTF8α- 함수는에서 찾을 수 있습니다 php.net :

function isUTF8($string) {
    return (utf8_encode(utf8_decode($string)) == $string);
}

16
불행히도 이것은 문자열이 ISO-8859-1에 포함 된 문자로만 구성된 경우에만 작동합니다. 그러나 이것은 작동 할 수 있습니다 : @iconv ( 'utf-8', 'utf-8 // IGNORE', $ str) == $ str
Christian Davén

@Christian : 사실, 그것은 고성능 MySQL의 저자들도 추천하는 것입니다.
Alix Axel

1
제대로 작동하지 않습니다 : echo (int) isUTF8 ( 'z'); # 1 에코 (int) isUTF8 (NULL); # 1
Yousha Aleayoub

1
완벽하지는 않지만 스케치 UTF-8 검사를 구현하는 좋은 방법이라고 생각합니다.
Mateng

1
mb_check_encoding($string, 'UTF-8')
deceze

13

이 치트 시트에는 PHP에서 UTF-8 처리와 관련된 몇 가지주의 사항이 나와 있습니다. http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

문자열에서 멀티 바이트 문자를 감지하는이 함수는 다음과 같이 유용 할 수도 있습니다 ( source ).


function detectUTF8($string)
{
    return preg_match('%(?:
        [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
        |\xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
        |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
        |\xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
        |\xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
        |[\xF1-\xF3][\x80-\xBF]{3}         # planes 4-15
        |\xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
        )+%xs', 
    $string);
}


2
나는 그것이 제대로 작동하지 않는다고 생각한다 : echo detectUTF8 ( '3٣3'); # 1
Yousha Aleayoub

10

작은 머리. 데이터베이스에서 "ß"가 "Ÿ"로 표시되어야한다고 말했습니다.

라틴 -1 문자 인코딩으로 데이터베이스를 사용 중이거나 PHP-MySQL 연결이 잘못 설정되어 있기 때문일 수 있습니다 .P는 MySQL이 UTF-8을 사용하도록 설정되어 있으므로 UTF-8로 데이터를 보냅니다. 그러나 MySQL은 PHP가 ISO 8859-1로 인코딩 된 데이터를 전송한다고 믿고 있으므로 전송 된 데이터를 UTF-8로 다시 인코딩하려고 시도하면 이런 종류의 문제가 발생할 수 있습니다.

mysql_set_charset을 살펴보십시오 . 도움이 될 수 있습니다.


4

인코딩은 UTF-8로 두 번 인코딩 된 것처럼 보입니다 . 즉, 다른 인코딩에서 UTF-8로, 다시 UTF-8로. ISO 8859-1이있는 것처럼 ISO 8859-1에서 UTF-8로 변환하고 UTF-8 로의 다른 변환을 위해 새 문자열을 ISO 8859-1로 처리했습니다.

다음은 수행 한 의사 코드입니다.

$inputstring = getFromUser();
$utf8string = iconv($current_encoding, 'utf-8', $inputstring);
$flawedstring = iconv($current_encoding, 'utf-8', $utf8string);

시도해야합니다 :

  1. 사용 mb_detect_encoding()하거나 원하는 것을 사용하여 인코딩 감지
  2. UTF-8 인 경우 ISO 8859-1로 변환하고 1 단계를 반복하십시오.
  3. 마지막으로 UTF-8로 다시 변환하십시오.

"중간"변환에서 ISO 8859-1을 사용했다고 가정합니다. Windows-1252를 사용한 경우 Windows-1252 (latin1)로 변환하십시오. 원본 소스 인코딩은 중요하지 않습니다. 결함이있는 두 번째 변환에서 사용한 것입니다.

이것이 일어난 일에 대한 나의 추측입니다. 하나의 확장 ASCII 바이트 대신 4 바이트를 얻기 위해 수행 할 수있는 다른 작업은 거의 없습니다.

독일어는 ISO 8859-2Windows-1250 (Latin-2)도 사용합니다.


3

재미있는 점 mb_detect_encodingmb_convert_encoding당신이 제안 인코딩의 순서가 중요합니까 것입니다 :

// $input is actually UTF-8

mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8");
// ISO-8859-9 (WRONG!)

mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9");
// UTF-8 (OK)

따라서 예상 인코딩을 지정할 때 특정 순서를 사용하려고 할 수 있습니다. 그럼에도 불구하고 이것이 절대적인 것은 아닙니다.


2
이것은 ISO-8859-9가 실제로 모든 이진 입력을 받아들이 기 때문에 발생합니다. Windows-1252와 친구도 마찬가지입니다. 입력을 받아 들일 수없는 인코딩을 먼저 테스트해야합니다.
Mikko Rantalainen

: @MikkoRantalainen는, 그래, 나는 문서의 일부가 비슷한라고 생각 php.net/manual/en/function.mb-detect-order.php#example-2985
할릴 오즈

WHATWG HTML 사양이 Windows 1252를 기본 인코딩으로 정의한다는 점을 고려하면 꽤 안전합니다 if ($input_is_not_UTF8) $input_is_windows1252 = true;. 참조 : html.spec.whatwg.org/multipage/...
미코 Rantalainen

3

응답은 다른 인코딩으로 코딩 될 수 있으므로 입력시 문자 세트를 테스트해야합니다.

다음 기능을 사용하여 감지 및 변환을 수행하여 모든 내용을 UTF-8로 보냅니다.

function fixRequestCharset()
{
  $ref = array(&$_GET, &$_POST, &$_REQUEST);
  foreach ($ref as &$var)
  {
    foreach ($var as $key => $val)
    {
      $encoding = mb_detect_encoding($var[$key], mb_detect_order(), true);
      if (!$encoding)
        continue;
      if (strcasecmp($encoding, 'UTF-8') != 0)
      {
        $encoding = iconv($encoding, 'UTF-8', $var[$key]);
        if ($encoding === false)
          continue;
        $var[$key] = $encoding;
      }
    }
  }
}

이 루틴은 원격 호스트에서 오는 모든 PHP 변수를 UTF-8로 바꿉니다.

또는 인코딩을 감지하거나 변환 할 수없는 경우 값을 무시하십시오.

필요에 따라 사용자 정의 할 수 있습니다.

변수를 사용하기 전에 호출하십시오.


인코딩 목록에 전달되지 않고 mb_detect_order ()를 사용하는 목적은 무엇입니까?
giorgio79

목적은 사용 된 php.ini에 정의 된 시스템 구성 순서의 인코딩 배열을 반환하는 것입니다. 이는 mb_detect_encoding에서 세 번째 매개 변수를 채우는 데 필요합니다.
cavila

2

RSS 피드의 문자 인코딩 작업은 복잡해 보입니다 . 일반적인 웹 페이지조차도 종종 인코딩을 생략하거나 거짓말을합니다.

따라서 올바른 방법으로 인코딩을 감지 한 다음 어떤 형태의 자동 감지 (추측)로 넘어갈 수 있습니다.


피드 정보에서 인코딩을 읽고 싶지 않습니다. 피드 정보가 틀리면 동일합니다. 텍스트에서 인코딩을 감지하고 싶습니다.
caw

@ marco92w : 선언 된 인코딩이 잘못되면 문제가되지 않습니다. 재미를위한 표준은 확립되지 않았습니다.
Gumbo

1
@ Gumbo : 그러나 실제 세계에서 일하고 있다면 잘못된 선언 된 인코딩과 같은 것들을 다룰 수 있어야합니다. 문제는 일부 텍스트에서 인코딩을 추측 (정확하게)하기가 매우 어렵다는 것입니다. 표준은 훌륭하지만 페이지 / 피드의 대부분 (대부분의 경우)이이를 준수하지 않습니다.
Kevin ORourke

@Kevin ORourke : 맞습니다. 그게 내 문제 야 @Gumbo : 네, 제 문제입니다. 피드를 읽고 집계하고 싶습니다. 따라서 잘못된 인코딩을 수정해야합니다.
caw

@ marco92w : 그러나 올바른 인코딩과 현재 인코딩을 모르면 인코딩을 수정할 수 없습니다. 그리고 그것이 다음과 같은 경우에 charset/ encoding선언입니다 : 데이터가 인코딩 된 인코딩을 기술하십시오.
Gumbo

2

나는 이것이 오래된 질문이라는 것을 알고 있지만 유용한 답변이 결코 아프지 않다고 생각합니다. 데스크톱 응용 프로그램, SQLite 및 GET / POST 변수 간의 인코딩에 문제가 있습니다. 일부는 UTF-8로, 일부는 ASCII로, 기본적으로 외국 문자가 포함되면 모든 것이 망칠 수 있습니다.

여기 내 해결책이 있습니다. 처리하기 전에 각 페이지로드에서 GET / POST / REQUEST (쿠키는 생략했지만 원하는 경우 추가 할 수 있음)를 제거합니다. 헤더에서 잘 작동합니다. PHP는 소스 인코딩을 자동으로 감지하지 못하면 경고를 표시하므로 @로 경고를 표시하지 않습니다.

//Convert everything in our vars to UTF-8 for playing nice with the database...
//Use some auto detection here to help us not double-encode...
//Suppress possible warnings with @'s for when encoding cannot be detected
try
{
    $process = array(&$_GET, &$_POST, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = $v;
                $process[] = &$process[$key][@mb_convert_encoding($k,'UTF-8','auto')];
            } else {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = @mb_convert_encoding($v,'UTF-8','auto');
            }
        }
    }
    unset($process);
}
catch(Exception $ex){}

대답 주셔서 감사합니다, jocull. mb_convert_encoding () 함수는 우리가 이미 가지고 있었던 것입니다. ;) 따라서 귀하의 답변에서 유일한 새로운 것은 모든 변수에서 인코딩을 변경하는 루프입니다.
caw

2

나이 이후 인코딩에 대한 솔루션을 확인하고있었습니다. 하고 있었고이 페이지는 아마도 수년간의 검색의 결론 일 것입니다! 언급 한 제안 중 일부를 테스트했으며 여기 내 메모가 있습니다.

이것은 내 테스트 문자열입니다.

이것은 "wrông wrìtten"문자열이지만 "sòme"특수 채널을 사용하여 fönctìon에 의해 변환 된 스템을 볼 필요가 없습니다 !! 그게 다야!

이 문자열을 데이터베이스에 저장하기 위해 INSERT를 수행합니다. utf8_general_ci

내 페이지의 문자 집합은 UTF-8입니다.

데이터베이스에 INSERT를 수행하면 화성에서 온 문자가 있습니다 ...

그래서 나는 그것들을 "정상적인"UTF-8로 변환해야합니다. 나는 시도 utf8_encode()했지만 여전히 외계인이 내 데이터베이스를 침범하고 있었다 ...

그래서 forceUTF8숫자 8에 게시 된 함수를 사용하려고했지만 데이터베이스에서 저장된 문자열은 다음과 같습니다.

이것은 "wrngng wrötten"문자열 bùt 내가 's'me'특별 한 chrs à mn, fùnctáon에 의해 변환을 볼 수있는 p 's n neded !! 그게 다야!

따라서이 페이지에서 더 많은 정보를 수집하고 다른 페이지의 다른 정보와 병합 하여이 솔루션의 문제를 해결했습니다.

$finallyIDidIt = mb_convert_encoding(
  $string,
  mysql_client_encoding($resourceID),
  mb_detect_encoding($string)
);

이제 내 데이터베이스에는 올바른 인코딩을 가진 문자열이 있습니다.

참고 :주의 사항 만 작동합니다 mysql_client_encoding! 이 기능은 자원 ID를 매개 변수로 원하므로 데이터베이스에 연결되어 있어야합니다.

그러나 글쎄, 나는 단지 INSERT 전에 다시 인코딩을 수행하므로 문제가되지 않습니다.


1
UTF-8먼저 mysql에 클라이언트 인코딩을 사용하지 않습니까? 이 방법으로 수동 변환이 필요하지 않음
Esailija

2

그것의 간단한 : 당신이 UTF-8이 아니다 뭔가를 얻을 때, 당신은해야한다 인코딩 것을 UTF-8.

따라서 ISO 8859-1 인 특정 피드를 가져 오면를 통해 구문 분석합니다 utf8_encode.

그러나 UTF-8 피드를 가져 오는 경우 별도의 작업이 필요하지 않습니다.


감사! 좋아, mb-detect-encoding ()을 사용하여 피드가 어떻게 인코딩되는지 알 수 있습니까? 그러나 피드가 ASCII 인 경우 어떻게해야합니까? utf8-encode ()는 ISO-8859-1에서 UTF-8에만 해당되지 않습니까?
caw

ASCII는 ISO-8859-1 및 UTF-8의 하위 집합이므로 utf8-encode ()를 사용하면 변경되지 않아야합니다. 실제로 ASCII 인 경우
Michael Borgwardt

UTF-8이 아닌 경우 항상 utf8_encode를 사용할 수 있습니까? 이것은 정말 쉽습니다. mb-detect-encoding ()에 따라 ASCII 인 텍스트에 "& # 228;"이 포함되어 있습니다. 이것은 ASCII 문자입니까? 아니면 HTML입니까?
caw

HTML입니다. 실제로 그것은 인코딩되어 있으므로 주어진 페이지에서 인쇄 할 때 ok로 표시됩니다. 먼저 ut8_encode () 다음 html_entity_decode ()를 사용할 수 있습니다.
Seb

1
문자 ß는 바이트 시퀀스 0xC39F로 UTF-8로 인코딩됩니다. Windows-1252로 해석 된이 시퀀스는 두 문자 Â (0xC3) 및 Ÿ (0x9F)를 나타냅니다. 그리고이 바이트 시퀀스를 UTF-8로 다시 인코딩하면 Windows-1252에서 Â를 나타내는 0xC383 0xC29F가 표시됩니다. 따라서이 UTF-8로 인코딩 된 데이터를 UTF-8 이외의 인코딩으로 처리하는 것은 실수입니다. 이 바이트 시퀀스는 당신이보고있는 문자로 제시된다는 것은 단지 해석의 문제 일뿐입니다. 다른 인코딩 / 문자 세트를 사용하는 경우 다른 문자가 표시 될 수 있습니다.
Gumbo

1

php.net/mb_detect_encoding

echo mb_detect_encoding($str, "auto");

또는

echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");

나는 실제로 결과가 무엇인지 모르지만 다른 인코딩으로 피드 중 일부를 가져 와서 mb_detect_encoding작동하는지 여부를 제안하는 것이 좋습니다 .

업데이트
자동은 "ASCII, JIS, UTF-8, EUC-JP, SJIS"의 약자입니다. iconv 를 사용하여 문자열을 utf-8로 변환하는 데 사용할 수있는 감지 된 문자 세트를 리턴합니다 .

<?php
function convertToUTF8($str) {
    $enc = mb_detect_encoding($str);

    if ($enc && $enc != 'UTF-8') {
        return iconv($enc, 'UTF-8', $str);
    } else {
        return $str;
    }
}
?>

나는 그것을 테스트하지 않았으므로 보증하지 않습니다. 아마도 더 간단한 방법이있을 것입니다.


감사합니다. 두 번째 인수로 'auto'와 'UTF-8, ASCII, ISO-8859-1'의 차이점은 무엇입니까? '자동'은 더 많은 인코딩을 제공합니까? 그렇다면 'auto'를 사용하는 것이 낫지 않습니까? 실제로 버그없이 작동하면 "ASCII"또는 "ISO-8859-1"만 "UTF-8"로 변경해야합니다. 어떻게?
caw

2
모든 경우에 기능이 제대로 작동하지 않습니다. 때때로 오류가 발생합니다.주의 사항 : iconv () : 입력 문자열에서 잘못된 문자가 감지되었습니다.
caw

1

나를 위해 일한 @ harpax. 제 경우에는 이것으로 충분합니다.

if (isUTF8($str)) { 
    echo $str; 
}
else
{
    echo iconv("ISO-8859-1", "UTF-8//TRANSLIT", $str);
}

0

PHP 스크립트를 정렬 한 후 mysql에게 전달하고 수신하고 싶은 문자 세트를 알려주는 것을 잊지 마십시오.

예 : 문자 세트 utf8 설정

latin1 I / O 세션에서 utf8 데이터를 latin1 테이블로 전달하면 이러한 불쾌한 새가 생깁니다. 나는 매일 oscommerce 상점에서 이것을 본다. 앞뒤로 옳아 보일 수 있습니다. 그러나 phpmyadmin은 진실을 보여줄 것입니다. mysql에 전달하는 문자 세트를 알려 주면 mysql 데이터 변환이 처리됩니다.

기존 스크램블 된 mysql 데이터를 복구하는 방법은 논의해야 할 또 다른 스레드입니다. :)


0

이 버전은 독일어 용이지만 $ CHARSETS 및 $ TESTCHARS를 수정할 수 있습니다.

class CharsetDetector
{
private static $CHARSETS = array(
"ISO_8859-1",
"ISO_8859-15",
"CP850"
);
private static $TESTCHARS = array(
"€",
"ä",
"Ä",
"ö",
"Ö",
"ü",
"Ü",
"ß"
);
public static function convert($string)
{
    return self::__iconv($string, self::getCharset($string));
}
public static function getCharset($string)
{
    $normalized = self::__normalize($string);
    if(!strlen($normalized))return "UTF-8";
    $best = "UTF-8";
    $charcountbest = 0;
    foreach (self::$CHARSETS as $charset) {
        $str = self::__iconv($normalized, $charset);
        $charcount = 0;
        $stop   = mb_strlen( $str, "UTF-8");

        for( $idx = 0; $idx < $stop; $idx++)
        {
            $char = mb_substr( $str, $idx, 1, "UTF-8");
            foreach (self::$TESTCHARS as $testchar) {

                if($char == $testchar)
                {

                    $charcount++;
                    break;
                }
            }
        }
        if($charcount>$charcountbest)
        {
            $charcountbest=$charcount;
            $best=$charset;
        }
        //echo $text."<br />";
    }
    return $best;
}
private static function __normalize($str)
{

$len = strlen($str);
$ret = "";
for($i = 0; $i < $len; $i++){
    $c = ord($str[$i]);
    if ($c > 128) {
        if (($c > 247)) $ret .=$str[$i];
        elseif ($c > 239) $bytes = 4;
        elseif ($c > 223) $bytes = 3;
        elseif ($c > 191) $bytes = 2;
        else $ret .=$str[$i];
        if (($i + $bytes) > $len) $ret .=$str[$i];
        $ret2=$str[$i];
        while ($bytes > 1) {
            $i++;
            $b = ord($str[$i]);
            if ($b < 128 || $b > 191) {$ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;}
            else $ret2.=$str[$i];
            $bytes--;
        }
    }
}
return $ret; 
}
private static function __iconv($string, $charset)
{
    return iconv ( $charset, "UTF-8" , $string );
}
}


0

헤더에서 인코딩을 가져 와서 utf-8로 변환하십시오.

$post_url='http://website.domain';

/// Get headers ////////////////////////////////////////////////////////////
function get_headers_curl($url) 
{ 
    $ch = curl_init(); 

    curl_setopt($ch, CURLOPT_URL,            $url); 
    curl_setopt($ch, CURLOPT_HEADER,         true); 
    curl_setopt($ch, CURLOPT_NOBODY,         true); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_TIMEOUT,        15); 

    $r = curl_exec($ch); 
    return $r; 
}
$the_header = get_headers_curl($post_url);
/// check for redirect /////////////////////////////////////////////////
if (preg_match("/Location:/i", $the_header)) {
    $arr = explode('Location:', $the_header);
    $location = $arr[1];

    $location=explode(chr(10), $location);
    $location = $location[0];

$the_header = get_headers_curl(trim($location));
}
/// Get charset /////////////////////////////////////////////////////////////////////
if (preg_match("/charset=/i", $the_header)) {
    $arr = explode('charset=', $the_header);
    $charset = $arr[1];

    $charset=explode(chr(10), $charset);
    $charset = $charset[0];
    }
///////////////////////////////////////////////////////////////////////////////
// echo $charset;

if($charset && $charset!='UTF-8') { $html = iconv($charset, "UTF-8", $html); }

0

Ÿ에 대한 Mojibake입니다 ß. 데이터베이스에 16 진법이있을 수 있습니다.

DF if the column is "latin1",
C39F if the column is utf8 -- OR -- it is latin1, but "double-encoded"
C383C5B8 if double-encoded into a utf8 column

당신은해야 하지 PHP에서 함수를 디코딩 / 어떤 인코딩을 사용; 대신 데이터베이스와 데이터베이스에 대한 연결을 올바르게 설정해야합니다.

MySQL이 관련된 경우 다음을 참조하십시오. utf8 문자 문제; 내가 보는 것은 내가 저장 한 것이 아니다


0

여기에 해결책이 있습니다 http://deer.org.ua/2009/10/06/1/

class Encoding
{
    /**
     * http://deer.org.ua/2009/10/06/1/
     * @param $string
     * @return null
     */
    public static function detect_encoding($string)
    {
        static $list = ['utf-8', 'windows-1251'];

        foreach ($list as $item) {
            try {
                $sample = iconv($item, $item, $string);
            } catch (\Exception $e) {
                continue;
            }
            if (md5($sample) == md5($string)) {
                return $item;
            }
        }
        return null;
    }
}

$content = file_get_contents($file['tmp_name']);
$encoding = Encoding::detect_encoding($content);
if ($encoding != 'utf-8') {
    $result = iconv($encoding, 'utf-8', $content);
} else {
    $result = $content;
}

@ 가 잘못된 결정 이라고 생각하고 deer.org.ua에서 솔루션을 약간 변경하십시오.


0

가장 투표 된 답변이 효과가 없습니다. 여기 내 것이 도움이되기를 바랍니다.

function toUTF8($raw) {
    try{
        return mb_convert_encoding($raw, "UTF-8", "auto"); 
    }catch(\Exception $e){
        return mb_convert_encoding($raw, "UTF-8", "GBK"); 
    }
}

1
왜 또는 어떻게 파일이 다른지에 대한 통찰력이 있습니까? 어떤 부분이 효과가 없었습니까? 예 : 대문자 독일어 ​​문자가 올바르게 변환되지 않았습니다. 궁금합니다. "GBK"는 무엇입니까?
SherylHohman

-1

일본어 나 한국어와 같은 다국어를 다룰 때 어려움을 겪을 수 있습니다. 'auto'매개 변수가있는 mb_convert_encoding이 제대로 작동하지 않습니다. mb_detect_order ( 'ASCII, UTF-8, JIS, EUC-JP, SJIS, EUC-KR, UHC')를 설정하면 EUC- *를 잘못 감지하므로 도움이되지 않습니다.

입력 문자열이 HTML에서 오는 한 메타 요소에 'charset'을 사용해야한다고 결론을 내 렸습니다. 유효하지 않은 HTML을 지원하기 때문에 Simple HTML DOM Parser를 사용 합니다.

아래 스 니펫은 웹 페이지에서 제목 요소를 추출합니다. 전체 페이지를 변환하려면 일부 행을 제거 할 수 있습니다.

<?php
require_once 'simple_html_dom.php';

echo convert_title_to_utf8(file_get_contents($argv[1])), PHP_EOL;

function convert_title_to_utf8($contents)
{
    $dom = str_get_html($contents);
    $title = $dom->find('title', 0);
    if (empty($title)) {
        return null;
    }
    $title = $title->plaintext;
    $metas = $dom->find('meta');
    $charset = 'auto';
    foreach ($metas as $meta) {
        if (!empty($meta->charset)) { // html5
            $charset = $meta->charset;
        } else if (preg_match('@charset=(.+)@', $meta->content, $match)) {
            $charset = $match[1];
        }
    }
    if (!in_array(strtolower($charset), array_map('strtolower', mb_list_encodings()))) {
        $charset = 'auto';
    }
    return mb_convert_encoding($title, 'UTF-8', $charset);
}

-1

phpQuery ( UTF-8 대신 ISO-8859-1) 와 동일한 문제가 있었고이 해킹이 도움이되었습니다.

$html = '<?xml version="1.0" encoding="UTF-8" ?>' . $html;

mb_internal_encoding('UTF-8'), phpQuery::newDocumentHTML($html, 'utf-8'), mbstring.internal_encoding등의 조작은 적용되지 않았다.


-1

'자동'없이 시도

그건:

mb_detect_encoding($text)

대신에:

mb_detect_encoding($text, 'auto')

자세한 정보는 여기에서 찾을 수 있습니다 : mb_detect_encoding

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.