[php] PHP : 원래 문자 집합을 몰라도 문자열을 UTF-8로 변환하거나 최소한 시도

전 세계의 클라이언트를 다루는 응용 프로그램이 있으며 데이터베이스에 들어가는 모든 것이 UTF-8로 인코딩되기를 원합니다.

나에게 가장 큰 문제는 문자열의 소스가 어떤 인코딩인지 알지 못한다는 것입니다-텍스트 상자에서 ( <form accept-charset="utf-8">사용자가 실제로 양식을 제출 한 경우에만 유용합니다) 또는 업로드 된 텍스트 파일에서 입력을 제어 할 수 없습니다.

필요한 것은 내 데이터베이스에 들어가는 것들이 가능한 한 UTF-8로 인코딩되도록하는 함수 또는 클래스입니다. 시도 iconv(mb_detect_encoding($text), "UTF-8", $text);
했지만 문제가 있습니다 (입력이 ‘fiancée’이면 ‘fianc’를 반환합니다). 나는 많은 것들을 시도했다 = /

파일 업로드의 경우 최종 사용자에게 사용하는 인코딩을 지정하도록 요청하고 출력이 어떻게 표시되는지 미리보기를 표시하는 아이디어를 좋아하지만 불쾌한 해커에게는 도움이되지 않습니다 (사실, 삶을 살릴 수 있음) 조금 더 쉽게).

주제에 대한 다른 SO 질문을 읽었지만 “RSS 피드를 구문 분석해야합니다”또는 “웹 사이트에서 데이터를 긁습니다”(또는 실제로는 “당신이 할 수 없음”)와 같은 미묘한 차이가있는 것 같습니다.

그러나 적어도 좋은 시도 가 있어야합니다 !



답변

당신이 요구하는 것은 매우 어렵습니다. 가능하면 사용자가 인코딩을 지정하도록하는 것이 가장 좋습니다. 공격을 방지하는 것이 그렇게 쉬운 일이 아니거나 어렵지 않아야합니다.

그러나 이것을 시도해 볼 수 있습니다.

iconv(mb_detect_encoding($text, mb_detect_order(), true), "UTF-8", $text);

엄격하게 설정하면 더 나은 결과를 얻는 데 도움이 될 수 있습니다.


답변

조국 러시아에는 4 가지 인기있는 인코딩이 있으므로 귀하의 질문이 많이 필요합니다.

코드 페이지가 교차하기 때문에 문자의 문자 코드로만 인코딩을 감지 할 수 없습니다. 다른 언어로 된 일부 코드 페이지에는 완전한 교차점이 있습니다. 따라서 다른 접근 방식이 필요합니다 .

알 수없는 인코딩으로 작업 할 수있는 유일한 방법은 확률로 작업하는 것입니다. 따라서 “이 텍스트의 인코딩은 무엇입니까?”라는 질문에 대답하지 않고 “이 텍스트의 인코딩 가능성은 무엇 입니까?”를 이해하려고합니다 .

인기있는 러시아 기술 블로그의 한 사람 이이 접근법을 발명했습니다.

지원하려는 모든 인코딩에서 문자 코드의 확률 범위를 작성하십시오. 당신은 당신의 언어로 큰 텍스트를 사용하여 그것을 만들 수 있습니다 (예를 들어, 소설, 영어로 Shakespeare를 사용하고 러시아어로 lol Tolstoy를 사용하십시오). 당신은 이런 식으로 얻을 것입니다 :

    encoding_1:
    190 => 0.095249209893009,
    222 => 0.095249209893009,
    ...
    encoding_2:
    239 => 0.095249209893009,
    207 => 0.095249209893009,
    ...
    encoding_N:
    charcode => probabilty

다음. 알 수없는 인코딩으로 텍스트를 가져오고 “확률 사전”의 모든 인코딩에 대해 알 수없는 인코딩 된 텍스트에서 모든 심볼의 빈도를 검색합니다. 기호의 합 확률. 더 큰 등급의 인코딩이 승자가 될 것입니다. 더 큰 텍스트를위한 더 나은 결과.

관심 이 있으시면 기꺼이이 작업을 도와 드리겠습니다. 두 개의 문자 코드 확률 목록을 작성하여 정확도를 크게 높일 수 있습니다.

Btw. mb_detect_encoding이 작동하지 않습니다. 그렇습니다. “ext / mbstring / libmbfl / mbfl / mbfl_ident.c”에서 mb_detect_encoding 소스 코드를 살펴보십시오.


답변

아마도 이것을 시도했지만 mb_convert_encoding 함수를 사용하지 않는 이유는 무엇입니까? 제공된 텍스트의 문자 세트를 자동 감지하려고 시도하거나 목록을 전달할 수 있습니다.

또한 나는 달리기를 시도했다.

$text = "fiancée";
echo mb_convert_encoding($text, "UTF-8");
echo "<br/><br/>";
echo iconv(mb_detect_encoding($text), "UTF-8", $text);

결과는 둘 다 동일합니다. 텍스트가 ‘가족’으로 잘리는 것을 어떻게 알 수 있습니까? DB 또는 브라우저에 있습니까?


답변

완전히 정확한 문자열의 문자셋을 식별 할 수있는 방법이 없습니다. 문자셋을 추측하는 방법이 있습니다. 이 방법들 중 하나, 그리고 아마도 현재 / 현재 PHP에서 가장 좋은 방법은 mb_detect_encoding ()입니다. 문자열을 스캔하여 특정 문자 집합에 고유 한 항목이 있는지 찾습니다. 당신의 문자열에 따라, 그러한 구별 가능한 사건이 없을 수 있습니다.

ISO-8859-1 문자 세트와 ISO-8859-15 비교 ( http://en.wikipedia.org/wiki/ISO/IEC_8859-15#Changes_from_ISO-8859-1 )

소수의 다른 문자 만 있으며 더 악화시키기 위해 동일한 바이트로 표시됩니다. 바이트 0xA4가 문자열에서 ¤ 또는 €을 의미하는지 여부를 인코딩하지 않고 문자열을 제공받을 수있는 방법이 없으므로 정확한 문자 집합을 알 수있는 방법이 없습니다.

(참고 : 캐릭터가 ¤ 또는 € 여야하지만 주변 캐릭터를 기준으로 알아 내기 위해 인적 요소 또는 훨씬 고급 스캔 기술 (예 : Oroboros102가 제안한 것)을 추가 할 수 있습니다. 너무 멀어)

예를 들어 UTF-8과 ISO-8859-1 사이에는 더 뚜렷한 차이점이 있으므로 확실하지 않은 경우이를 파악하는 것이 좋습니다.

재미있는 읽을 거리 : http://kore-nordmann.de/blog/php_charset_encoding_FAQ.html#how-do-i-determine-the-charset-encoding-of-a-string

올바른 문자셋을 보장하는 다른 방법이 있습니다. 양식과 관련하여 가능한 한 UTF-8을 시행하십시오 (모든 브라우저에서 제출이 UTF-8인지 확인하기 위해 눈사람을 확인하십시오 : http://intertwingly.net/blog/2010/07/29/Rails-and -Snowmen ) 완료되면 적어도 양식을 통해 제출 된 모든 텍스트가 utf_8인지 확인할 수 있습니다. 업로드 된 파일에 대해서는 exec () (가능한 경우 서버에서)를 통해 unix ‘file -i’명령을 실행하여 탐지를 도와줍니다 (문서의 BOM 사용). 스크래핑 데이터에 대해서는 HTTP 헤더를 읽을 수 있습니다. 일반적으로 문자셋을 지정합니다. XML 파일을 구문 분석 할 때 XML 메타 데이터에 문자 세트 정의가 포함되어 있는지 확인하십시오.

자동으로 문자셋을 추측하려고하기보다는, 가능한 경우 특정 문자셋을 직접 확보하거나 감지에 의존하기 전에 (해당되는 경우) 소스에서 정의를 얻으려고 시도해야합니다.


답변

정말 좋은 답변이 있으며 여기에 귀하의 질문에 대한 답변을 시도합니다. 나는 인코딩 마스터가 아니지만 순수한 UTF-8 스택을 데이터베이스에 가져 가고 싶다는 당신의 이해를 이해합니다 . utf8mb4테이블, 필드 및 연결에 MySQL의 인코딩을 사용 하고 있습니다.

“상황은 데이터가 HTML 양식 또는 전자 메일 등록 링크에서 올 때 UTF-8을 처리하기 위해 소독제, 유효성 검사기, 비즈니스 논리 및 준비된 명령문이 필요합니다.” 그래서 간단한 방법으로이 아이디어로 시작했습니다.

  1. 인코딩을 감지하려고 시도하십시오. $encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];
  2. 인코딩이 감지되지 않으면 throw new RuntimeException
  3. 입력이 계속 UTF-8되면 계속하십시오.
  4. 그렇지 않으면 ISO-8859-1또는ASCII

    ㅏ. UTF-8 로의 변환을 시도하십시오 (대기, 완료되지 않음)

    비. 변환 된 값의 인코딩을 감지

    씨. 보고 된 인코딩 및 변환 된 값이 모두 인 UTF-8경우 계속하십시오.

    디. 그밖에,throw new RuntimeException

내 추상 수업에서 Sanitizer

살균제

    private function isUTF8($encoding, $value)
    {
        return (($encoding === 'UTF-8') && (utf8_encode(utf8_decode($value)) === $value));
    }

    private function utf8tify(&$value)
    {
        $encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];

        mb_internal_encoding('UTF-8');
        mb_substitute_character(0xfffd); //REPLACEMENT CHARACTER
        mb_detect_order($encodings);

        $stringEncoding = mb_detect_encoding($value, $encodings, true);

        if (!$stringEncoding) {
            $value = null;
            throw new \RuntimeException("Unable to identify character encoding in sanitizer.");
        }

        if ($this->isUTF8($stringEncoding, $value)) {
            return;
        } else {
            $value = mb_convert_encoding($value, 'UTF-8', $stringEncoding);
            $stringEncoding = mb_detect_encoding($value, $encodings, true);

            if ($this->isUTF8($stringEncoding, $value)) {
                return;
            } else {
                $value = null;
                throw new \RuntimeException("Unable to convert character encoding from ISO-8859-1, or ASCII, to UTF-8 in Sanitizer.");
            }
        }

        return;
    }

인코딩 문제 를 추상 Sanitizer클래스와 분리 하고 Encoder객체를의 구체적인 자식 인스턴스에 삽입 해야한다고 주장 할 수 Sanitizer있습니다. 그러나 내 접근 방식의 주요 문제는 더 많은 지식이 없으면 원하지 않는 인코딩 유형을 거부한다는 것입니다 (PHP mb_ * 함수에 의존하고 있음). 더 이상의 연구가 없다면, 그것이 일부 인구에 해를 끼치는 지 아닌지 (또는 중요한 정보를 잃어버린 경우) 알 수 없습니다. 그래서 더 배울 필요가 있습니다. 이 기사를 찾았습니다.

모든 프로그래머가 텍스트로 작업하기 위해 인코딩 및 문자 세트에 대해 긍정적으로 알아야 할 사항

또한 암호화 된 데이터가 전자 메일 등록 링크에 추가되면 ( OpenSSL또는 사용 mcrypt) 어떻게됩니까? 이것이 디코딩을 방해 할 수 있습니까? Windows-1252는 어떻습니까? 보안 영향은 어떻습니까? 사용 utf8_decode()하고 utf8_encode()있는이 Sanitizer::isUTF8모호한 있습니다.

사람들은 PHP mb_ * 함수의 단점을 지적했습니다. 조사하는 데 시간 iconv이 걸리지 않았지만 mb_ * functions보다 효과가 좋으면 알려주십시오.


답변

나에게 가장 큰 문제는 문자열의 소스가 어떤 인코딩인지 알지 못한다는 것입니다-텍스트 상자에서 (사용자가 실제로 양식을 제출 한 경우에만 유용합니다) 또는 업로드 된 텍스트 파일에서 입력을 제어 할 수 없습니다.

나는 그것이 문제라고 생각하지 않습니다. 응용 프로그램은 입력 소스를 알고 있습니다. 양식에서 온 경우에는 UTF-8 인코딩을 사용하십시오. 작동합니다. 제공된 데이터가 올바르게 인코딩되어 있는지 확인하십시오 (확인). 모든 데이터베이스가 전체 범위에서 UTF-8을 지원하는 것은 아닙니다.

파일 인 경우 UTF-8 인코딩 된 데이터베이스로 저장하지 않고 이진 형식으로 저장합니다. 파일을 다시 출력 할 때 이진 출력도 사용하면 완전히 투명합니다.

당신은 사용자가 인코딩을 말할 수 있다는 것이 기쁩니다. 파일을 다운로드 한 후 바이너리 파일이므로 어쨌든 말할 수 있기 때문입니다.

따라서 귀하의 질문에 대해 제기 한 특정 문제가 보이지 않는다는 것을 인정해야합니다. 그러나 문제가 무엇인지 더 자세히 설명 할 수 있습니다.


답변

사용중인 인코딩을 추측하기 위해 일련의 메트릭을 설정할 수 있습니다. 다시 말하지만, 완벽하지는 않지만 mb_detect_encoding ()에서 누락 된 부분을 잡을 수 있습니다.