UTF-8 przez całą drogę

Konfiguruję nowy serwer i chcę w pełni obsługiwać UTF-8 w mojej aplikacji internetowej. Próbowałem w przeszłości na istniejących serwerach i zawsze wydaje się, że muszę wrócić do ISO-8859-1.

Gdzie dokładnie muszę ustawić kodowanie / znaki? Zdaję sobie sprawę, że muszę skonfigurować Apache, MySQL i PHP, aby to zrobić - czy jest jakaś standardowa Lista kontrolna, którą mogę śledzić, lub może rozwiązać problem, gdzie występują niedopasowania?

To jest dla nowego serwera Linux, z MySQL 5, PHP 5 i Apache 2.

Author: Machavity, 2008-11-11

13 answers

Przechowywanie Danych :

  • Określ zestaw znaków utf8mb4 dla wszystkich tabel i kolumn tekstowych w bazie danych. To sprawia, że MySQL fizycznie przechowuje i pobiera wartości zakodowane natywnie w UTF-8. Zauważ, że MySQL będzie domyślnie używać kodowania utf8mb4, jeśli podana jest kolacja utf8mb4_* (bez jawnego zestawu znaków).

  • W starszych wersjach MySQL (utf8, który obsługuje tylko podzbiór Znaki Unicode. Chciałbym żartować.

Dostęp Do Danych :

  • W kodzie aplikacji (np. PHP), niezależnie od używanej metody dostępu do bazy danych, musisz ustawić kod połączenia na utf8mb4. W ten sposób MySQL nie dokonuje konwersji z natywnego UTF-8, gdy przekazuje dane do aplikacji i odwrotnie.

  • Niektóre sterowniki zapewniają własny mechanizm konfigurowania zestawu znaków połączenia, który aktualizuje jego własny stan wewnętrzny i informuje MySQL o kodowaniu, które ma być użyte w połączeniu-jest to zazwyczaj preferowane podejście. W PHP:

    • Jeśli używasz PDO warstwy abstrakcji z PHP ≥ 5.3.6, możesz określić charset w DSN :

      $dbh = new PDO('mysql:charset=utf8mb4');
      
    • Jeśli używasz mysqli, możesz wywołać set_charset():

      $mysqli->set_charset('utf8mb4');       // object oriented style
      mysqli_set_charset($link, 'utf8mb4');  // procedural style
      
    • Jeśli utkniesz z plain mysql ale przypadkiem używasz PHP ≥ 5.2.3, to może zadzwonić mysql_set_charset.

  • Jeśli sterownik nie zapewnia własnego mechanizmu ustawiania zestawu znaków połączenia, być może będziesz musiał wydać zapytanie, aby powiedzieć MySQL, w jaki sposób aplikacja oczekuje zakodowania danych w połączeniu: SET NAMES 'utf8mb4'.

  • To samo dotyczy utf8mb4/utf8 stosuje się jak powyżej.

Wyjście :

  • Jeśli aplikacja przesyła tekst do innych systemów, będą również musieli zostać poinformowani o kodowaniu znaków. W przypadku aplikacji internetowych przeglądarka musi być informowana o kodowaniu, w którym przesyłane są dane (poprzez nagłówki odpowiedzi HTTP lub metadane HTML ).

  • W PHP możesz użyć default_charset php.opcja ini, lub ręcznie wydać Content-Type nagłówek MIME samemu, który jest po prostu więcej pracy, ale ma ten sam efekt.

Wejście :

  • Niestety, powinieneś zweryfikuj każdy otrzymany ciąg znaków jako poprawny UTF-8, zanim spróbujesz go zapisać lub użyć w dowolnym miejscu. PHP ' S mb_check_encoding() robi sztuczkę, ale musisz używać jej religijnie. Naprawdę nie ma możliwości obejścia tego, ponieważ złośliwi klienci mogą przesyłać dane w dowolnym kodowaniu, które chcą, a ja nie znalazłem sztuczki, aby PHP zrobił to za Ciebie niezawodnie.

  • Z lektury aktualnegoHTML spec wynika, że poniższe podpunkty nie są już potrzebne ani nawet ważne dla nowoczesny HTML. Rozumiem, że przeglądarki będą pracować i przesyłać dane w zestawie znaków określonym dla dokumentu. Jeśli jednak używasz starszych wersji HTML (XHTML, HTML4 itp.), punkty te mogą być nadal użyteczne:

    • tylko dla HTML przed HTML5: chcesz, aby wszystkie dane wysyłane do ciebie przez przeglądarki były w UTF-8. Niestety, jedynym sposobem, aby to zrobić, jest dodanie atrybutu accept-charset do wszystkich tagów <form>: <form ... accept-charset="UTF-8">.
    • dla HTML przed HTML5 tylko : zauważ, że specyfikacja HTML W3C mówi, że klienci "powinni" domyślnie wysyłać formularze z powrotem do serwera w dowolnym zestawie znaków obsługiwanych przez serwer, ale jest to najwyraźniej tylko zalecenie, stąd potrzeba bycia jawnym dla każdego znacznika <form>.

Inne Uwagi Dotyczące Kodu :

  • Oczywiście, wszystkie pliki, które będziesz obsługiwać (PHP, HTML, JavaScript itp.) powinny być kodowane w poprawnym UTF-8.

  • Musisz się upewnić, że za każdym razem, gdy przetwarzasz ciąg UTF-8, robisz to bezpiecznie. To jest, niestety, najtrudniejsza część. Prawdopodobnie będziesz chciał szeroko korzystać z PHP mbstring przedłużenie.

  • Wbudowane operacje łańcuchowe PHP są , a nie domyślnie bezpieczne dla UTF-8. są pewne rzeczy, które możesz bezpiecznie zrobić przy zwykłych operacjach łańcuchowych PHP (jak konkatenacja), ale dla większości rzeczy powinieneś użyj równoważnej funkcji mbstring.

  • Aby wiedzieć, co robisz (Czytaj: nie psuj tego), naprawdę musisz znać UTF-8 i jak działa na najniższym możliwym poziomie. Sprawdź dowolny z linków z utf8.com dla dobrych zasobów, aby dowiedzieć się wszystkiego, co musisz wiedzieć.

 884
Author: chazomaticus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:44

Chciałbym dodać jedną rzecz do doskonałej odpowiedzi chazomatica :

Nie zapomnij META tagu (jak ten, lub w wersji HTML4 lub XHTML):

<meta charset="utf-8">

To wydaje się banalne, ale IE7 dawało mi problemy z tym wcześniej.

Robiłem wszystko dobrze; baza danych, połączenie z bazą danych i nagłówek HTTP typu treści były ustawione na UTF-8 i działało dobrze we wszystkich innych przeglądarkach, ale Internet Explorer nadal nalegał na używanie " Western Europejskie " kodowanie.

Okazało się, że strona nie posiada znacznika META. Dodanie tego rozwiązało problem.

Edit:

W3C faktycznie ma dość dużą sekcję poświęconą I18N . Mają wiele artykułów związanych z tym zagadnieniem-opisujących stronę HTTP, (X)HTML i CSS:

Zalecają używanie zarówno nagłówka HTTP, jak i meta tagu HTML (lub deklaracji XML w przypadku XHTML serwowanej jako XML).

 136
Author: mercator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:49

Oprócz ustawienia default_charset w php.ini, możesz wysłać poprawny kod używając header() z kodu, przed dowolnym wyjściem:

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

Praca z Unicode w PHP jest łatwa, o ile zdasz sobie sprawę, że większość funkcji łańcuchowych nie działa z Unicode, a niektóre mogą całkowicie mangle ciągów . PHP uważa ,że "znaki" mają długość 1 bajtu. Czasami jest to w porządku (na przykład explode() szuka tylko sekwencji bajtów i używa jej jako separatora-więc nie ma znaczenia co rzeczywiste postacie, których szukasz). Ale innym razem, gdy funkcja jest rzeczywiście zaprojektowana do pracy na znakach , PHP nie ma pojęcia, że Twój tekst ma wielobajtowe znaki, które można znaleźć w Unicode.

Dobrą biblioteką do sprawdzenia jest phputf8. To przepisuje wszystkie " złe " funkcje, dzięki czemu można bezpiecznie pracować na ciągach UTF8. Istnieją rozszerzenia, takie jak rozszerzenie mbstring, które próbują zrobić to za ciebie, ale wolę używać biblioteki, ponieważ jest bardziej przenośna (ale piszę produkty na rynek masowy, więc jest to dla mnie ważne). Ale phputf8 może używać mbstring za kulisami, w każdym razie, aby zwiększyć wydajność.

 55
Author: chroder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-10 21:35:46

Stary temat, wiem. Znalazłem problem z kimś używającym PDO i odpowiedzią było użycie tego dla łańcucha połączenia PDO:

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

Strona, z której to wziąłem jest w dół, był w stanie uzyskać go za pomocą Google cache Na szczęście.

 26
Author: Brad F Jacobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-26 19:02:46

W moim przypadku używałem mb_split, który używa regex. Dlatego też musiałem ręcznie upewnić się, że kodowanie regex jest utf-8, wykonując mb_regex_encoding('UTF-8');

Na marginesie, odkryłem również uruchamiając mb_internal_encoding(), że wewnętrzne kodowanie nie było utf-8, i zmieniłem to uruchamiając mb_internal_encoding("UTF-8");.

 20
Author: JDelage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-23 22:20:22

Po pierwsze jeśli jesteś w Dziwi mnie, że nikt nie wspomniał o intl biblioteka, która ma dobre wsparcie dla unicode, grafemes, operacje ciągów , Lokalizacja i wiele innych, patrz poniżej.

Przytoczę kilka informacji o obsłudze unicode w PHP przez Elizabeth Smith ' s slajdy w PHPBenelux'14

INTL

Dobre:

  • Wrapper around ICU library
  • znormalizowane lokalizacje, Ustaw lokalizacje na skrypcie
  • Formatowanie liczb
  • formatowanie waluty
  • formatowanie wiadomości (zastępuje gettext)
  • kalendarze, daty, Strefa czasowa i czas
  • Transliterator
  • Spoofchecker
  • pakiety zasobów
  • Konwertery
  • IDN Wsparcie
  • Grafemes
  • Zestawienie
  • Iteratory

Zły:

  • nie obsługuje zend_multibite
  • nie obsługuje konwersji danych wejściowych HTTP
  • nie obsługuje funkcji przeciążania

Mb_string

  • umożliwia obsługę zend_multibyte
  • obsługuje przezroczyste kodowanie HTTP in / out
  • zapewnia niektóre opakowania dla funtionallitycity, takie jak strtoupper

ICONV

  • Podstawowa konwersja zestawu znaków
  • output buffer handler
  • funkcja kodowania mime
  • konwersja
  • some string helpers (len, substr, strpos, strrpos)
  • Filtr Strumieniowy stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')

Bazy danych

  • mysql: Charset i collation na tabelach i przy połączeniach (Nie collation). Również nie używaj mysql-msqli lub PDO
  • postgresql: pg_set_client_encoding
  • SQLite (3): Upewnij się, że został skompilowany z obsługą unicode i intl

Niektóre inne Gotchas

  • nie możesz używać nazw plików unicode w PHP i windows, chyba że używasz rozszerzenia trzeciej części.
  • wyślij wszystko w ASCII, jeśli używasz exec, proc_open i innych wywołań linii poleceń
  • zwykły tekst nie jest zwykłym tekstem, pliki mają kodowanie
  • możesz konwertować pliki w locie za pomocą iconv filtr

Zaktualizuję tę odpowiedź na wypadek, gdyby coś zmieniło dodane funkcje i tak dalej.

 19
Author: Jimmy Kane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-16 17:37:22

Niedawno odkryłem, że użycie strtolower() może powodować problemy, w których dane są obcinane po znaku specjalnym.

Rozwiązaniem było użycie

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

Mb_ używa Wielobajtu. Obsługuje więcej znaków, ale ogólnie jest trochę wolniejszy.

 13
Author: Notflip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-04 12:26:56

Jedyną rzeczą, którą chciałbym dodać do tych niesamowitych odpowiedzi jest podkreślenie na zapisywanie plików w kodowaniu utf8, zauważyłem, że przeglądarki akceptują tę właściwość nad ustawieniem utf8 jako kodowanie kodu. Każdy porządny edytor tekstu pokaże ci to, na przykład Notepad++ ma opcję menu do kodowania plików, pokazuje aktualne kodowanie i umożliwia jego zmianę. Dla wszystkich moich plików php używam utf8 bez BOM.

Jakiś czas temu ktoś poprosił mnie o dodanie obsługi utf8 dla php / mysql aplikacja zaprojektowana przez kogoś innego, zauważyłem, że wszystkie pliki były zakodowane w ANSI, więc musiałem użyć ICONV do konwersji wszystkich plików, zmienić tabele bazy danych, aby używać UTF8 charset i utf8_general_ci zestawiać, dodać 'SET NAMES utf8' do warstwy abstrakcji bazy danych po połączeniu (Jeśli za pomocą 5.3.6 lub wcześniej, inaczej trzeba użyć charset = utf8 w łańcuchu połączenia) i zmienić funkcje łańcuchowe, aby używać PHP multibyte string functions równoważne.

 12
Author: Puerto AGP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 00:20:58

W PHP musisz albo użyć funkcji wielobajtowych , albo włączyć mbstring.func_overload . W ten sposób rzeczy takie jak strlen będą działać, jeśli masz znaki, które zajmują więcej niż jeden bajt.

Musisz również zidentyfikować zestaw znaków odpowiedzi. Możesz użyć AddDefaultCharset, jak powyżej, lub napisać kod PHP, który zwraca nagłówek. (Możesz też dodać META tag do dokumentów HTML.)

 8
Author: JW.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-10 21:29:21

Właśnie przeszedłem przez ten sam problem i znalazłem dobre rozwiązanie w podręcznikach PHP.

Zmieniłem kodowanie wszystkich plików na UTF8, a następnie domyślne kodowanie w moim połączeniu. To rozwiązało wszystkie problemy.

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());
}

Zobacz Źródło

 8
Author: Abdul Sadik Yalcin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-21 14:24:09

Obsługa Unicode w PHP to nadal ogromny bałagan. Chociaż jest w stanie konwertować ciąg ISO8859 (którego używa wewnętrznie) do utf8, nie ma możliwości pracy z ciągami unicode natywnie, co oznacza, że wszystkie funkcje przetwarzania ciągów będą mangle i uszkodzone ciągi. Więc musisz albo użyć oddzielnej biblioteki dla właściwej obsługi utf8, albo przepisać wszystkie funkcje obsługi łańcuchów samodzielnie.

Łatwa część to tylko określenie zestawu znaków w nagłówkach HTTP i w bazy danych i tym podobne, ale nic z tego nie ma znaczenia, jeśli twój kod PHP nie wyświetla poprawnego UTF8. To jest najtrudniejsza część, A PHP nie daje tam praktycznie żadnej pomocy. (Myślę, że PHP6 ma naprawić najgorsze z tego, ale to jeszcze chwilę)

 6
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-11 19:49:45

Najlepsza odpowiedź jest doskonała. Oto, co musiałem zrobić na zwykłej konfiguracji debian / 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
To wszystko !
 5
Author: commonpike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-14 16:13:18

Jeśli chcesz, aby to serwer MySQL decydował o zestawie znaków, a nie PHP jako klient( stare zachowanie; moim zdaniem preferowane), spróbuj dodać skip-character-set-client-handshake do swojego my.cnf, pod [mysqld], i uruchom ponownie mysql.

Może to powodować problemy w przypadku, gdy używasz czegoś innego niż UTF8.

 5
Author: Nikola Tulimirovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-11 23:52:55