PHP : 원래의 문자 집합을 모른 채 모든 문자열을 UTF-8로 변환하거나 적어도 시도하십시오.



4 Answers

조국 러시아에서는 4 개의 인기있는 인코딩이 있으므로 여기에 귀하의 질문에 큰 요구가 있습니다.

코드 페이지가 교차하기 때문에 기호의 char 코드에 의해서만 인코딩을 감지 할 수 없습니다. 다른 언어로 된 일부 코드 페이지는 완전한 교차점을가집니다. 그래서 우리는 또 다른 접근법이 필요합니다 .

알 수없는 인코딩으로 작업하는 유일한 방법은 확률로 작업하는 것입니다. 그래서 우리는 "이 텍스트의 인코딩은 무엇입니까?"라는 질문에 답하기를 원하지 않습니다. "우리는 이 텍스트의 인코딩 가능성이 가장 높습니다 "라고 이해하려고합니다.

인기있는 러시아 기술 블로그에있는 한 사람이이 접근 방법을 고안했습니다.

지원하려는 모든 인코딩에서 char 코드의 확률 범위를 작성하십시오. 당신은 당신의 언어로 몇몇 큰 텍스트를 사용하여 그것을 만들 수 있습니다 (예를 들어 어떤 픽션, 영어의 경우 셰익스피어, 러시아어의 경우 톨스토이, 롤). 당신은 다음과 같이 스턴을 얻을 것입니다 :

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

다음 것. 알 수없는 인코딩으로 텍스트를 가져오고 "확률 사전"의 모든 인코딩에 대해 알 수없는 인코딩 된 텍스트의 모든 심볼의 빈도를 검색합니다. 심볼의 합계 확률. 더 큰 등급의 인코딩이 승자 일 가능성이 높습니다. 더 큰 텍스트에 대한 더 나은 결과.

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

Btw. mb_detect_encoding certanly 작동하지 않습니다. 네. "ext / mbstring / libmbfl / mbfl / mbfl_ident.c"에있는 mb_detect_encoding 소스 코드를보십시오.

Question

나는 전세계의 고객들과 거래하는 응용 프로그램을 가지고 있으며 당연히 모든 데이터베이스가 UTF-8로 인코딩되기를 원합니다.

필자가 생각하기에 가장 중요한 문제는 문자열의 소스를 인코딩하는 것이 무엇인지 알지 못한다는 것입니다. 텍스트 상자 ( <form accept-charset="utf-8"> 는 사용자가 실제로 양식을 제출 한 경우) 또는 업로드 된 텍스트 파일 일 수 있으므로 입력에 대한 제어권이 없습니다.

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

파일 업로드의 경우, 최종 사용자에게 그들이 사용하는 인코딩을 지정하고 결과물을 미리보기로 표시하도록 요청하는 아이디어가 마음에 들지만, 이는 해커의 불쾌감을 방지하는 데는 도움이되지 않습니다. 사실, 좀 더 쉽게).

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

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




어떤 인코딩이 사용되는지 추측하려고하는 일련의 메트릭을 설정할 수 있습니다. 다시 말하지만 완벽하지는 않지만 mb_detect_encoding ()에서 누락 된 부분을 잡을 수 있습니다.




귀하의 질문에 대한 답변이 많은 것 같지만 귀하의 사례를 단순화 할 수있는 방법이 있습니다.

비슷한 문제가 mysql에서 문자열 데이터를 반환하려고했는데 심지어 데이터베이스와 PHP를 모두 utf-8로 포맷 된 문자열을 반환하도록 구성했습니다. 오류가 발생하는 유일한 방법은 실제로 그들을 데이터베이스에서 반환하는 것입니다.

마지막으로 웹을 통해 항해하면 정말 쉽게 해결할 수 있습니다.

mysql에있는 모든 형식의 문자열 데이터를 다양한 형식과 데이터 정렬로 저장할 수 있으므로 PHP 연결 파일에서 다음과 같이 데이터 정렬을 utf-8로 설정하면됩니다.

$connection = new mysqli($server, $user, $pass, $db);
$connection->set_charset("utf8");

즉, 먼저 데이터를 모든 형식 또는 데이터 정렬로 저장하고 PHP 파일로 반환 할 때만 데이터를 변환한다는 의미입니다.

희망이 도움이되었다!




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

내 상황은 "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 클래스에서 인코딩 문제분리 하고 Sanitizer 의 구체적인 자식 인스턴스에 Encoder 객체를 삽입해야한다는 주장을 할 수 있습니다. 그러나, 내 접근법의 가장 큰 문제점은 더 많은 지식이 없으면 원하지 않는 인코딩 유형을 거부한다는 것입니다. PHP mb_ * 함수를 사용하고 있습니다. 더 많은 연구없이, 나는 그것이 어떤 인구를 아프게하는지 아닐지 (또는 내가 중요한 정보를 잃어 버리면) 알 수 없다. 그래서, 나는 더 많은 것을 배울 필요가있다. 나는이 기사를 발견했다.

모든 프로그래머가 텍스트 작업을위한 인코딩 및 문자 세트에 대해 절대적으로 알고 있어야하는 점

또한 암호화 된 데이터가 내 이메일 등록 링크 ( OpenSSL 또는 mcrypt 사용)에 추가되면 어떻게됩니까? 이것이 디코딩을 방해 할 수 있습니까? Windows-1252는 어떻습니까? 보안 관련 사항은 무엇입니까? Sanitizer::isUTF8 에서 utf8_decode()utf8_encode() 를 사용하는 것은 의심 스럽습니다.

사람들은 PHP mb_ * 함수의 단점을 지적했습니다. 나는 iconv 에 대해 조사한 적이 없지만 mb_ * 함수보다 더 잘 작동한다면 알려주지.




완전히 정확한 문자열의 문자 세트를 식별 할 수있는 방법은 없습니다. charset을 추측 해 볼 수있는 방법이 있습니다. 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가 문자열에서 ¤ 또는 €을 나타낼 것인지 여부를 알지 못해 문자열을 감지 할 수있는 방법이 없으므로 정확한 charset을 알 수있는 방법이 없습니다.

(참고 : 인간의 요소를 추가하거나, 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 헤더를 읽을 수 있습니다. 일반적으로 charset을 지정합니다. XML 파일을 구문 분석 할 때 XML 메타 데이터에 charset 정의가 포함되어 있는지 확인하십시오.

자동적으로 charset을 추측하려고 시도하기보다는 가능한 한 특정 charset을 확인하거나 감지에 의지하기 전에 (존재하는 경우) 소스에서 정의를 가져 오려고 시도해야합니다.




Related