UTF-8


1191

새 서버를 설정하고 있으며 웹 응용 프로그램에서 UTF-8을 완전히 지원하려고합니다. 나는 과거에 기존 서버에서 이것을 시도했으며 항상 ISO-8859-1로 돌아 가야하는 것처럼 보입니다.

인코딩 / 문자 세트를 정확히 어디에 설정해야합니까? 이를 위해 Apache, MySQL 및 PHP를 구성해야한다는 것을 알고 있습니다. 따라야 할 표준 체크리스트가 있습니까?

MySQL 5, PHP, 5 및 Apache 2를 실행하는 새로운 Linux 서버용입니다.


8
다음은 가능한 인코딩 오류에 대한 개요입니다. sebastianviereck.de/en/…
Sebastian Viereck

13
다음은 일반적인 인코딩과 PHP에서의 인코딩에 대한 소개입니다. 모든 프로그래머가 텍스트로 작업하기 위해 인코딩 및 문자 집합에 대해 알아야 할 사항
deceze

PHP 7에 대한 최근의 논의에 따르면 2010 년의 "공식적으로 포기한"위치에는 변화가 없습니다. "PHP7 및 UTF-8"에 대한 자세한 내용이 있습니까?
피터 크라우스

이 문제는 일반적입니다. 그러나 바로 가기 솔루션이 없으므로 utf-8MySQL 5, PHP 5 또는 Apache 2 각각에 대해 별도로 설정해야합니다 .
Manish Shrivastava

답변:


1015

데이터 저장 :

  • utf8mb4데이터베이스의 모든 테이블 및 텍스트 열에 문자 세트를 지정하십시오 . 따라서 MySQL은 기본적으로 UTF-8로 인코딩 된 값을 실제로 저장하고 검색합니다. 데이터 정렬이 명시 적 문자 세트없이 지정된 utf8mb4경우 MySQL은 암시 적으로 인코딩을 사용 utf8mb4_*합니다.

  • 이전 버전의 MySQL (<5.5.3)에서는 불행히도 간단히 utf8유니 코드 문자의 하위 집합 만 지원하는 간단하게 사용해야 합니다. 농담하길 바래

데이터 액세스 :

  • 애플리케이션 코드 (예 : PHP)에서 사용하는 DB 액세스 방법에 관계없이 연결 문자셋을로 설정해야합니다 utf8mb4. 이런 식으로 MySQL은 데이터를 응용 프로그램으로 전달하거나 그 반대로 전달할 때 기본 UTF-8에서 변환하지 않습니다.

  • 일부 드라이버는 자체 내부 상태를 업데이트하고 연결에 사용될 인코딩을 MySQL에 알리는 연결 문자 세트 구성을위한 고유 한 메커니즘을 제공합니다. 이는 일반적으로 선호되는 방식입니다. PHP에서 :

    • 당신이 사용하는 경우 PDO의 PHP ≥ 5.3.6와 추상화 계층을 지정할 수 있습니다 charset에서 DSN :

      $dbh = new PDO('mysql:charset=utf8mb4');
    • mysqli를 사용하는 경우 다음 을 호출 할 수 있습니다 set_charset().

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • 일반 mysql 이 붙어 있지만 PHP ≥ 5.2.3을 실행하는 경우을 호출 할 수 있습니다 mysql_set_charset.

  • 드라이버가 연결 문자 세트를 설정하기위한 자체 메커니즘을 제공하지 않는 경우, 애플리케이션이 연결의 데이터가 인코딩 될 것으로 예상하는 방법을 MySQL에 알리기 위해 쿼리를 발행해야 할 수 있습니다 SET NAMES 'utf8mb4'.

  • 위와 마찬가지로 utf8mb4/ 에 관한 동일한 고려 사항이 utf8적용됩니다.

출력 :

  • 응용 프로그램이 텍스트를 다른 시스템으로 전송하는 경우 문자 인코딩에 대해서도 알려야합니다. 웹 애플리케이션을 사용하면 브라우저에 HTTP 응답 헤더 또는 HTML 메타 데이터를 통해 데이터가 전송되는 인코딩을 알려야합니다 .

  • PHP에서는 default_charsetphp.ini 옵션을 사용 하거나 직접 Content-TypeMIME 헤더를 직접 발행 할 수 있습니다. 이는 더 많은 작업이지만 효과는 동일합니다.

  • 를 사용하여 출력을 인코딩 할 때 두 번째 매개 변수로 json_encode()추가하십시오 JSON_UNESCAPED_UNICODE.

입력 :

  • 불행히도, 수신 한 모든 문자열을 저장하거나 다른 곳에서 사용하기 전에 유효한 UTF-8인지 확인해야합니다. PHP mb_check_encoding()는 트릭을 수행하지만 종교적으로 사용해야합니다. 악의적 인 클라이언트가 원하는 인코딩으로 데이터를 제출할 수 있기 때문에이 문제를 해결할 방법이 없습니다. PHP가이 작업을 확실하게 수행 할 수있는 방법을 찾지 못했습니다.

  • 현재 HTML 사양을 읽었을 때 다음 하위 글 머리 기호는 더 이상 최신 HTML에 필요하지 않거나 더 이상 유효하지 않습니다. 브라우저가 문서에 지정된 문자 세트로 작업하고 데이터를 제출한다는 것을 이해합니다. 그러나 이전 버전의 HTML (XHTML, HTML4 등)을 타겟팅하는 경우 다음 사항이 여전히 유용 할 수 있습니다.

    • HTML5 이전의 HTML 전용 : 브라우저에서 전송 한 모든 데이터를 UTF-8로 만들려고합니다. 안타깝게도 확실하게이 작업을 수행 할 수있는 유일한 방법은 accept-charset모든 <form>태그에 속성을 추가하는 것 <form ... accept-charset="UTF-8">입니다.
    • HTML5 이전의 HTML 만 해당 : W3C HTML 사양에 따르면 클라이언트는 서버가 제공 한 모든 문자 집합에서 서버로 양식을 다시 보내도록 기본적으로 설정해야하지만 이는 권장 사항 일 뿐이므로 모든 단일 항목에 대해 명시 적이어야 할 필요가 있습니다. <form>꼬리표.

다른 코드 고려 사항 :

  • 분명히 제공 할 모든 파일 (PHP, HTML, JavaScript 등)은 유효한 UTF-8로 인코딩되어야합니다.

  • UTF-8 문자열을 처리 할 때마다 안전하게 처리해야합니다. 불행히도 어려운 부분입니다. PHP mbstring확장 을 광범위하게 사용하고 싶을 것입니다 .

  • PHP의 내장 문자열 연산은 기본적으로 UTF-8 안전 하지 않습니다 . 연결과 같은 일반적인 PHP 문자열 작업으로 안전하게 할 수있는 것이 있지만 대부분의 경우 동등한 mbstring기능을 사용해야합니다 .

  • 무엇을하고 있는지 (읽기 : 엉망으로 만들지 않기) 위해서는 UTF-8과 그것이 가능한 최저 수준에서 어떻게 작동하는지 알아야합니다. utf8.com 의 링크를 확인 하여 알아야 할 모든 것을 배울 수있는 유용한 자료를 찾아보십시오.


4
데이터 정렬을 utf8_ *로 지정하면 자동으로 utf8로 인코딩된다는 것을 이해합니다. 이것이 잘못 되었습니까?
chazomaticus

49
틀리지 않습니다 : COLLATE는 CHARACTER SET을 의미합니다. 예를 들어 dev.mysql.com/doc/refman/5.0/en/charset-database.html을 참조하십시오 .
chazomaticus

7
문자 세트 설정을위한 PDO 예제 추가도 고려하십시오.
Ja͢ck

97
MySQL은 다른 사람들과 동일한 언어를 사용하지 않습니다. MySQL이 "utf8"이라고 말하면 실제로는 "유일하게 3 바이트로 제한되는 UTF-8의 기이하게 지연된 일부 변형은 어떤 우스운 이유를 알고있다"는 것을 의미합니다. UTF-8을 정말로 원한다면 MySQL에게 utf8mb4 호출이 이상한 것을 원한다고 MySQL에 알려야 합니다. "WTF!"를 절약하지 마십시오.
R. Martinho Fernandes

4
이 답변은 많은 도움이되었지만 제 경우에는 ajax를 통해 DB 쿼리 결과를 다시 전달할 때 JSON jUN_encode에 JSON_UNESCAPED_UNICODE를 추가해야한다는 것을 알았습니다.
Petay87

150

chazomaticus의 훌륭한 답변에 한 가지를 추가하고 싶습니다 .

META 태그를 잊지 마십시오 (예 : HTML4 또는 XHTML 버전 ).

<meta charset="utf-8">

그것은 사소한 것처럼 보이지만 IE7은 전에 그 문제를 겪었습니다.

나는 모든 일을 올바르게하고있었습니다. 데이터베이스, 데이터베이스 연결 및 Content-Type HTTP 헤더는 모두 UTF-8로 설정되었으며 다른 모든 브라우저에서 제대로 작동했지만 Internet Explorer는 여전히 "서유럽 어"인코딩 사용을 주장했습니다.

페이지에 META 태그가 누락되었습니다. 그것을 추가하면 문제가 해결되었습니다.

편집하다:

W3C는 실제로 I18N 전용 의 상당히 큰 섹션을 가지고 있습니다. HTTP, (X) HTML 및 CSS 측면을 설명하는이 문제와 관련된 많은 기사가 있습니다.

HTTP 헤더와 HTML 메타 태그 (또는 XHTML이 XML로 제공되는 경우 XML 선언)를 모두 사용하는 것이 좋습니다.


HTTP 헤더에 문자 세트를 지정할 수도 있습니까? 아마도 웹 서버를위한 설정 옵션이 필요할 것입니다.
oliver

2
@oliver : 예. HTTP 헤더로 보낼 수는 있지만 클라이언트가 파일을 저장하면 항상 메타 태그를 저장하기 때문에 콘텐츠로 보내는 것이 좋습니다. 브라우저가 스마트 한 파일을 저장된 파일의 메타 태그에 복사 할 수 없다면 HTTP 헤더는 사라질 것입니다.

5
또한 line이 head 요소의 첫 번째 자식인지 확인하십시오 (유니 코드 항목 이전). 브라우저는 위에서 설명한 해당 메타 요소에 도달 한 후 페이지를 해석 할 수 있습니다.
alex

64

default_charsetphp.ini에서 설정 하는 것 외에도 header()출력 전에 코드 내에서 올바른 문자 세트를 보낼 수 있습니다 .

header('Content-Type: text/html; charset=utf-8');

대부분의 문자열 함수가 유니 코드에서 작동하지 않으며 일부는 문자열을 완전히 엉망 으로 만들 수 있다는 점을 알고 있다면 PHP에서 유니 코드로 작업하는 것은 쉽습니다 . PHP는 "문자"가 1 바이트 길이 인 것으로 간주합니다. 때때로 이것은 괜찮습니다 (예를 들어 explode()바이트 시퀀스 만 찾아서 구분자로 사용하기 때문에 실제 문자를 찾는 것이 중요하지 않습니다). 그러나 다른 경우에, 함수가 실제로 문자 에서 작동하도록 설계되었을 때 , PHP는 텍스트에 유니 코드로 찾은 멀티 바이트 문자가 있다는 것을 알지 못합니다.

체크인하기에 좋은 라이브러리는 phputf8 입니다. 이것은 모든 "나쁜"기능을 다시 작성하므로 UTF8 문자열에서 안전하게 작업 할 수 있습니다. mbstring 확장과 같은 확장 프로그램 도이 작업을 시도하지만 더 이식성이 있기 때문에 라이브러리를 사용하는 것이 좋습니다 (그러나 대량 시장 제품을 작성하므로 나에게 중요합니다). 그러나 phputf8은 어쨌든 mbstring을 사용하여 성능을 향상시킬 수 있습니다.


php.ini에서 과부하 설정을 설정하십시오. 멀티 바이트 문자열을 사용할 때 도움이됩니다.
Anthony Rutledge

32

PDO를 사용하는 사람과 문제가 있음을 발견했으며 PDO 연결 문자열에이를 사용했습니다.

$pdo = new PDO(
    'mysql:host=mysql.example.com;dbname=example_db',
    "username",
    "password",
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

내가 가져온 사이트는 다운되었지만 운 좋게도 Google 캐시를 사용하여 얻을 수있었습니다.


1
이것을 조금 더 찾아 보면 이것은 5.3.6 이전의 PHP 버전에만 필요합니다. 참조 : http://stackoverflow.com/a/4361485/2286722 (별도 사용하지만 $dbh->exec("set names utf8");여기에 제시된 방법을 선호합니다). Btw. PHP 매뉴얼에 php.net/manual/en/pdo.construct.php#96325 와 같은 주석이 있습니다.
Marten Koetsier


24

제 경우 mb_split에는 정규 표현식을 사용하는을 사용했습니다. 따라서 수동으로 정규식 인코딩이 utf-8인지 확인해야했습니다.mb_regex_encoding('UTF-8');

부수적으로 mb_internal_encoding()내부 인코딩이 utf-8이 아니라는 것을 실행 하여 발견 했으며을 실행하여 변경했습니다 mb_internal_encoding("UTF-8");.


22

우선 <5.3PHP 인 경우 아니요. 해결해야 할 수많은 문제가 있습니다.

unicode , graphemes , string operation , localization 등 을 잘 지원 하는 intl 라이브러리 를 언급 한 사람이 아무도 없습니다 . 아래를 참조하십시오.

PHPBenelux'14 에서 Elizabeth Smith의 슬라이드통해 PHP에서 유니 코드 지원에 대한 정보를 인용 하겠습니다.

국제

좋은:

  • ICU 라이브러리를 감싸는 래퍼
  • 표준화 된 로캘, 스크립트 당 로캘 설정
  • 숫자 서식
  • 통화 형식
  • 메시지 형식 (gettext를 대체 함)
  • 달력, 날짜, 시간대 및 시간
  • 음역
  • 위장 검사기
  • 리소스 번들
  • 변환기
  • IDN 지원
  • 그래 핀
  • 대조
  • 반복자

나쁜:

  • zend_multibite를 지원하지 않습니다
  • HTTP 입력 출력 변환을 지원하지 않습니다
  • 기능 과부하를 지원하지 않습니다

mb_string

  • zend_multibyte 지원 가능
  • 투명한 HTTP 인 / 아웃 인코딩 지원
  • strtoupper와 같은 기능을위한 래퍼를 제공합니다

아이콘

  • 문자셋 변환의 기본
  • 출력 버퍼 핸들러
  • 마임 인코딩 기능
  • 변환
  • 일부 문자열 도우미 (len, substr, strpos, strrpos)
  • 스트림 필터 stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

데이터베이스

  • mysql : 테이블과 연결시 문자셋과 콜 레이션 (콜 레이션이 아님). 또한 MySQL을 사용하지 마십시오-msqli 또는 PDO
  • postgresql : pg_set_client_encoding
  • sqlite (3) : 유니 코드 및 국제 지원으로 컴파일되었는지 확인하십시오

다른 몇 가지

  • 세 번째 부분 확장명을 사용하지 않으면 PHP 및 창에서 유니 코드 파일 이름을 사용할 수 없습니다.
  • exec, proc_open 및 기타 명령 줄 호출을 사용하는 경우 ASCII로 모든 것을 보내십시오.
  • 일반 텍스트는 일반 텍스트가 아니며 파일에는 인코딩이 있습니다.
  • iconv 필터를 사용하여 파일을 즉석에서 변환 할 수 있습니다

기능 변경 등이 추가되는 경우이 답변을 업데이트하겠습니다.


2
네, 그러죠. Mysqli와 PDO는 기본 드라이버를 사용할 수 있습니다. 또한 --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd옵션으로 PHP를 컴파일하는 경우 mysqlnd 드라이버를 사용할 수 있습니다.
Alexander Yancharuk

14

이 놀라운 답변에 추가 할 수있는 유일한 것은 utf8 인코딩으로 파일을 저장하는 것을 강조하는 것입니다. 브라우저는 utf8을 코드 인코딩으로 설정하는 것보다 브라우저 가이 속성을 허용한다는 것을 알았습니다. 예를 들어 Notepad ++에는 파일 인코딩을위한 메뉴 옵션이 있으며 현재 인코딩을 보여주고 변경할 수 있습니다. 모든 PHP 파일에는 BOM없이 utf8을 사용합니다.

언젠가 누군가 누군가가 디자인 한 php / mysql 응용 프로그램에 대한 utf8 지원을 추가하도록 요청했습니다. 모든 파일이 ANSI로 인코딩 된 것을 알았으므로 ICONV를 사용하여 모든 파일을 변환하고 데이터베이스 테이블을 사용하도록 변경해야했습니다. utf8 문자셋과 utf8_general_ci 조합, 연결 후 데이터베이스 추상화 계층에 'SET NAMES utf8'을 추가하고 (5.3.6 이하를 사용하는 경우 연결 문자열에 charset = utf8을 사용해야 함) php 멀티 바이트를 사용하도록 문자열 함수를 변경하십시오. 문자열 함수에 해당합니다.


13

최근에 사용 strtolower()하면 특수 문자 다음에 데이터가 잘리는 문제가 발생할 수 있음을 발견했습니다 .

해결책은

mb_strtolower($string, 'UTF-8');

mb_는 멀티 바이트를 사용합니다. 더 많은 문자를 지원하지만 일반적으로 조금 느립니다.


9

방금 동일한 문제를 겪고 PHP 매뉴얼에서 좋은 해결책을 찾았습니다.

모든 파일 인코딩을 UTF8로 변경 한 다음 연결의 기본 인코딩을 변경했습니다. 이것은 모든 문제를 해결했습니다.

if (!$mysqli->set_charset("utf8")) {
    printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
   printf("Current character set: %s\n", $mysqli->character_set_name());
}

소스보기


2
작업중 인 페이지에서 인코딩 문제를 파악하기 위해 한 시간을 보냈으며 일반적으로 물건을 알아내는 데 꽤 능숙합니다. 나는 항상이 페이지를 참고하고 당신의 대답은 저에게 많은 도움이되었습니다. 내 투표를했습니다. 제 경우 set_charset('utf8mb4')에는 효과가 없었지만 >set_charset("utf8")실제로는 다른 답변에 표시되지 않았습니다.
Funk Forty Niner

주의 @FunkFortyNiner : set_charset("utf8")작동 할 수 있지만 다르게 동작 (사이의 차이에 대한 발언 볼 utf8utf8mb4와 MySQL의 버전 기록). 사용 utf8 당신이있는 경우 에만 당신이 무슨 일을하는지 알고 있다면 !
Martin Hennings

5 별 솔루션, 텍스트 파일을 한 줄씩 읽고 얻었습니다. 각 문자에 대해 ansi 대신 save-as를 사용하여 utf8을 사용했습니다. 감사.
Atef Farouk

8

PHP에서는 멀티 바이트 함수 를 사용하거나 mbstring.func_overload를 켜야합니다 . 그렇게하면 1 바이트 이상을 차지하는 문자가 있으면 strlen과 같은 것이 작동합니다.

또한 응답의 문자 세트를 식별해야합니다. 위와 같이 AddDefaultCharset을 사용하거나 헤더를 반환하는 PHP 코드를 작성할 수 있습니다. 또는 HTML 문서에 META 태그를 추가 할 수 있습니다.


func_overload 설정에 대한 유용한 팁-기존 코드를 최소한으로 수정할 수 있습니다.
Simon East

4
일부 코드는 실제로 표준 문자열 함수의 문자 당 1 바이트 특성에 의존 할 수 있습니다.
JW.

위의 @JW 주석에 언급 된 문제로 인해 mbstring.func_overload 기능은 PHP 7.2부터 더 이상 사용되지 않습니다. 따라서 최선의 조언은 다음과 같습니다. 그렇습니다. mbstring 함수를 반드시 사용해야하지만 표준 기능이 멀티 바이트로 작동하도록 과부하 기능을 사용하지 마십시오.
Simba

6

PHP에서의 유니 코드 지원은 여전히 ​​엉망입니다. 내부적으로 사용되는 ISO8859 문자열을 utf8로 변환 할 수는 있지만 유니 코드 문자열을 기본적으로 사용할 수있는 기능이 없기 때문에 모든 문자열 처리 기능이 문자열을 엉망으로 만들 수 있습니다. 따라서 적절한 utf8 지원을 위해 별도의 라이브러리를 사용하거나 모든 문자열 처리 기능을 직접 작성해야합니다.

쉬운 부분은 HTTP 헤더와 데이터베이스 등에서 문자 세트를 지정하는 것입니다. 그러나 PHP 코드가 유효한 UTF8을 출력하지 않는 경우에는 아무 것도 중요하지 않습니다. 어려운 부분이며 PHP는 거의 도움이되지 않습니다. (PHP6이 이것의 최악의 문제를 해결해야한다고 생각하지만, 아직 멀었습니다.)


6

당신은 MySQL 서버가 클라이언트와 같은 문자 세트, 그리고 PHP를 결정하려는 경우 (이전 동작을, 내 의견으로는, 선호), 추가하려고 skip-character-set-client-handshake당신에 my.cnf, 아래 [mysqld], 다시 시작합니다 mysql.

UTF8 이외의 것을 사용하는 경우 문제가 발생할 수 있습니다.


5

최고 답변이 우수합니다. 다음은 일반적인 데비안 / php / mysql 설정에서해야 할 일입니다.

// storage
// debian. apparently already utf-8

// retrieval
// the mysql database was stored in utf-8, 
// but apparently php was requesting iso. this worked: 
// ***notice "utf8", without dash, this is a mysql encoding***
mysql_set_charset('utf8');

// delivery
// php.ini did not have a default charset, 
// (it was commented out, shared host) and
// no http encoding was specified in the apache headers.
// this made apache send out a utf-8 header
// (and perhaps made php actually send out utf-8)
// ***notice "utf-8", with dash, this is a php encoding***
ini_set('default_charset','utf-8');

// submission
// this worked in all major browsers once apache
// was sending out the utf-8 header. i didnt add
// the accept-charset attribute.

// processing
// changed a few commands in php, like substr,
// to mb_substr

그게 전부였다 !


1

mysql 솔루션을 원한다면 서버 마이그레이션 후 2 개의 프로젝트와 비슷한 문제가 있습니다. 많은 솔루션을 검색하고 시도한 후이 솔루션을 사용하기 전에이 솔루션을 찾지 못했습니다.

mysqli_set_charset($con,"utf8");

이 줄을 구성 파일에 추가하면 모든 것이 잘 작동합니다!

html 쿼리에서 삽입을 해결하려고 할 때이 솔루션 https://www.w3schools.com/PHP/func_mysqli_set_charset.asp를 찾았습니다.

행운을 빕니다!


1

참고 사항 :

당신은 당신의 비 라틴 문자의 문제로 보여주고있다 직면하고있다 ?????????, 당신이 질문을하고이 표준 질문에 대한 참조를 폐쇄있어, 당신은 모든 노력을하고 당신을 무엇을 여전히 상관없이 얻을 ??????????에서 MySQL.

잘못된 문자셋을 사용하여 데이터베이스에 삽입되어 실제로 물음표 문자로 변환되어 저장된 기존 데이터 를 테스트하기 때문 ?입니다. 당신이 무엇을 시도하더라도 당신은 원본 텍스트를 영원히 잃어버린 것을 의미합니다 ???????.

이 질문에 대한 답변에서 얻은 내용을 새로운 데이터에 다시 적용하면 문제를 해결할 수 있습니다.


0

테이블을 표시 할 때이 문제가 발생했습니다. 방금 각 에코 출력 변수에 넣었습니다.

<td><?php echo utf8_encode ($Local) ?></td>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.