Konfiguruję nowy serwer i chcę w pełni obsługiwać UTF-8 w mojej aplikacji internetowej. Próbowałem tego w przeszłości na istniejących serwerach i zawsze wydaje mi się, że muszę wrócić do ISO-8859-1.
Gdzie dokładnie muszę ustawić kodowanie / zestawy znaków? Zdaję sobie sprawę, że muszę skonfigurować Apache, MySQL i PHP, aby to zrobić - czy istnieje jakaś standardowa lista kontrolna, którą mogę śledzić, a może rozwiązywać problemy w przypadku wystąpienia niezgodności?
Dotyczy to nowego serwera Linux z systemem MySQL 5, PHP, 5 i Apache 2.
utf-8
osobno dla każdego z nich - MySQL 5, PHP 5 OR Apache 2.Odpowiedzi:
Przechowywanie danych :
Określ
utf8mb4
zestaw znaków 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łutf8mb4
kodowania, jeśli określonoutf8mb4_*
sortowanie (bez żadnego jawnego zestawu znaków).W starszych wersjach MySQL (<5.5.3) niestety będziesz zmuszony używać po prostu
utf8
, który obsługuje tylko podzbiór znaków Unicode. Chciałbym żartować.Dostęp do danych :
W kodzie aplikacji (np. PHP), niezależnie od używanej metody dostępu do bazy danych DB, musisz ustawić zestaw znaków połączenia na
utf8mb4
. W ten sposób MySQL nie dokonuje konwersji ze swojego natywnego UTF-8, gdy przekazuje dane do twojej aplikacji i odwrotnie.Niektóre sterowniki zapewniają własny mechanizm konfigurowania zestawu znaków połączenia, który zarówno aktualizuje swój wewnętrzny stan, jak 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 warstwy abstrakcji PDO z PHP ≥ 5.3.6, możesz określić
charset
w DSN :Jeśli używasz mysqli , możesz zadzwonić
set_charset()
:Jeśli utknąłeś z zwykłym mysql, ale akurat używasz PHP ≥ 5.2.3, możesz zadzwonić
mysql_set_charset
.Jeśli kierowca nie przewiduje własny mechanizm ustawiania zestawu znaków połączenia, być może trzeba będzie wydać zapytanie do powiedzenia MySQL jak aplikacja oczekuje dane dotyczące połączenia mają być zakodowane:
SET NAMES 'utf8mb4'
.Ta sama uwaga dotycząca
utf8mb4
/utf8
obowiązuje jak powyżej.Wyjście :
Jeśli Twoja aplikacja przesyła tekst do innych systemów, będą one również musiały zostać poinformowane o kodowaniu znaków. W przypadku aplikacji internetowych przeglądarka musi być informowana o kodowaniu, w którym dane są wysyłane (za pomocą nagłówków odpowiedzi HTTP lub metadanych HTML ).
W PHP możesz użyć
default_charset
opcji php.ini lub ręcznie wydaćContent-Type
nagłówek MIME, co jest po prostu więcej pracy, ale ma ten sam efekt.Podczas kodowania danych wyjściowych za pomocą
json_encode()
dodajJSON_UNESCAPED_UNICODE
jako drugi parametr.Wejście :
Niestety, powinieneś zweryfikować każdy otrzymany ciąg jako poprawny UTF-8, zanim spróbujesz go zapisać lub użyć w dowolnym miejscu. PHP
mb_check_encoding()
załatwia sprawę, ale musisz używać jej religijnie. Naprawdę nie ma takiej możliwości, ponieważ złośliwi klienci mogą przesyłać dane w dowolnym pożądanym przez siebie kodowaniu, a ja nie znalazłem sposobu, aby PHP rzuciło się za ciebie niezawodnie.Z mojej lektury aktualnej specyfikacji HTML , następujące podpunkty nie są już potrzebne, a nawet aktualne dla współczesnego HTML. Rozumiem, że przeglądarki będą współpracować i przesyłać dane w zestawie znaków określonym dla dokumentu. Jeśli jednak kierujesz reklamy na starsze wersje HTML (XHTML, HTML4 itp.), Te punkty mogą być nadal przydatne:
accept-charset
atrybut do wszystkich<form>
tagów:<form ... accept-charset="UTF-8">
.<form>
etykietka.Inne uwagi dotyczące kodu :
Oczywiście wszystkie pliki, które będziesz obsługiwać (PHP, HTML, JavaScript itp.), Powinny być zakodowane w prawidłowym UTF-8.
Musisz upewnić się, że za każdym razem, gdy przetwarzasz ciąg UTF-8, robisz to bezpiecznie. To niestety trudna część. Prawdopodobnie będziesz chciał skorzystać z
mbstring
rozszerzenia PHP .Wbudowane operacje PHP na łańcuchach nie są domyślnie bezpieczne dla UTF-8. Są pewne rzeczy, które możesz bezpiecznie zrobić przy pomocy normalnych operacji na łańcuchach PHP (np. Konkatenacja), ale dla większości rzeczy powinieneś użyć równoważnej
mbstring
funkcji.Aby wiedzieć, co robisz (czytaj: nie zepsuć), naprawdę musisz znać UTF-8 i jak działa na najniższym możliwym poziomie. Sprawdź dowolne linki z utf8.com, aby znaleźć dobre zasoby, aby dowiedzieć się wszystkiego, co musisz wiedzieć.
źródło
Chciałbym dodać jedną rzecz do doskonałej odpowiedzi chazomaticus :
Nie zapomnij o znaczniku META (takim jak ten lub jego wersji HTML4 lub XHTML ):
Wydaje się to trywialne, ale IE7 już dawało mi z tym problemy.
Zrobiłem wszystko dobrze; baza danych, połączenie z bazą danych i nagłówek HTTP Content-Type zostały ustawione na UTF-8 i działało dobrze we wszystkich innych przeglądarkach, ale Internet Explorer nadal nalegał na stosowanie kodowania „zachodnioeuropejskiego”.
Okazało się, że na stronie brakuje tagu META. Dodanie to rozwiązało problem.
Edytować:
W3C faktycznie ma dość dużą sekcję poświęconą I18N . Mają wiele artykułów związanych z tym problemem - opisujących strony HTTP, (X) HTML i CSS:
Zalecają używanie zarówno nagłówka HTTP, jak i metatagu HTML (lub deklaracji XML w przypadku XHTML podanego jako XML).
źródło
Oprócz ustawienia
default_charset
w php.ini, możesz wysłać prawidłowy zestaw znaków za pomocąheader()
z twojego kodu, przed jakimkolwiek wyjściem:Praca z Unicode w PHP jest łatwa, pod warunkiem, że zdajesz sobie sprawę, że większość funkcji łańcuchowych nie działa z Unicode, a niektóre mogą całkowicie zakłócać łańcuchy . PHP uważa, że „znaki” mają długość 1 bajta. 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, jakich rzeczywistych znaków szukasz). Ale innym razem, kiedy funkcja jest rzeczywiście zaprojektowana do pracy na znakach , PHP nie ma pojęcia, że twój tekst zawiera znaki wielobajtowe znalezione w Unicode.Dobrą biblioteką do sprawdzenia jest phputf8 . Spowoduje to przepisanie wszystkich „złych” funkcji, abyś mógł bezpiecznie pracować na łańcuchach UTF8. Istnieją rozszerzenia, takie jak rozszerzenie mbstring, które również próbują to zrobić dla Ciebie, ale wolę korzystać z biblioteki, ponieważ jest ona bardziej przenośna (ale piszę produkty na rynek masowy, więc to jest dla mnie ważne). Ale phputf8 może i tak używać mbstringa za kulisami, aby zwiększyć wydajność.
źródło
Znalazłem problem z osobą używającą PDO i odpowiedzią było użycie tego dla ciągu połączenia PDO:
Witryna, z której to wziąłem, nie działa, ale na szczęście udało mi się ją uzyskać przy użyciu pamięci podręcznej Google.
źródło
$dbh->exec("set names utf8");
; wolę przedstawioną tutaj metodę). Btw. jest również podobna uwaga na ten temat jako komentarz w podręczniku PHP: php.net/manual/en/pdo.construct.php#96325 .W moim przypadku
mb_split
korzystałem z wyrażeń regularnych. Dlatego musiałem też ręcznie upewnić się, że kodowanie wyrażenia regularnego to utf-8mb_regex_encoding('UTF-8');
Na marginesie, odkryłem również przez uruchomienie,
mb_internal_encoding()
że wewnętrzne kodowanie nie było utf-8, i zmieniłem to przez uruchomieniemb_internal_encoding("UTF-8");
.źródło
Przede wszystkim, jeśli jesteś w <5.3PHP, to nie. Masz mnóstwo problemów do rozwiązania.
Dziwi mnie, że żadna nie wspomniała o bibliotece intl , która ma dobre wsparcie dla Unicode , grafemów , operacji na łańcuchach znaków , lokalizacji i wielu innych, patrz poniżej.
Przytoczę kilka informacji o obsłudze Unicode w PHP przez slajdy Elizabeth Smith na PHPBenelux'14
INTL
Dobrze:
Zły:
mb_string
ICONV
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
BAZY DANYCH
Niektóre inne Gotchas
Zaktualizuję tę odpowiedź na wypadek, gdyby coś zmieniło dodane funkcje i tak dalej.
źródło
--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd
opcjami.Jedyne, co chciałbym dodać do tych niesamowitych odpowiedzi, to podkreślić nacisk na zapisywanie plików w kodowaniu utf8, zauważyłem, że przeglądarki akceptują tę właściwość zamiast ustawiania utf8 jako kodowania kodu. Każdy przyzwoity edytor tekstu to pokaże, na przykład Notepad ++ ma opcję menu do kodowania plików, pokazuje bieżące kodowanie i umożliwia jego zmianę. Do wszystkich moich plików php używam utf8 bez BOM.
Jakiś czas temu ktoś poprosił mnie o dodanie obsługi utf8 dla aplikacji php / mysql zaprojektowanej przez kogoś innego, zauważyłem, że wszystkie pliki zostały zakodowane w ANSI, więc musiałem użyć ICONV do konwersji wszystkich plików, zmienić tabele bazy danych, aby użyć utf8 charset i utf8_general_ci zestawiają, dodaj 'SET NAMES utf8' do warstwy abstrakcji bazy danych po połączeniu (jeśli używasz 5.3.6 lub wcześniejszej wersji, w przeciwnym razie musisz użyć charset = utf8 w łańcuchu połączenia) i zmień funkcje łańcucha, aby użyć wielobajtowego php ekwiwalent funkcji łańcuchowych.
źródło
Niedawno odkryłem, że używanie
strtolower()
może powodować problemy, w których dane są obcinane po znaku specjalnym.Rozwiązaniem było użyć
źródło
Właśnie przejrzałem ten sam problem i znalazłem dobre rozwiązanie w instrukcjach 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.
Pokaż źródło
źródło
set_charset('utf8mb4')
nie działało, ale działało>set_charset("utf8")
i nie zostało to pokazane w innych odpowiedziach.set_charset("utf8")
mogą działać, ale będzie się zachowywał inaczej (patrz uwagi na temat różnicy międzyutf8
iutf8mb4
oraz historii wersji MySQL). Użyj,utf8
jeśli musisz TYLKO, jeśli wiesz, co robisz !W PHP musisz albo użyć funkcji wielobajtowej , 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 także zidentyfikować zestaw znaków swoich odpowiedzi. Możesz użyć AddDefaultCharset, jak wyżej, lub napisać kod PHP, który zwraca nagłówek. (Lub możesz dodać tag META do swoich dokumentów HTML.)
źródło
Obsługa Unicode w PHP jest nadal ogromnym bałaganem. Chociaż jest w stanie przekonwertować ciąg ISO8859 (którego używa wewnętrznie) na utf8, brakuje mu możliwości pracy z ciągami Unicode natywnie, co oznacza, że wszystkie funkcje przetwarzania łańcucha będą mangować i uszkadzać twoje ciągi. Musisz więc albo użyć oddzielnej biblioteki, aby zapewnić odpowiednią obsługę utf8, albo samodzielnie przepisać wszystkie funkcje obsługi ciągów.
Najłatwiejszą częścią jest po prostu określenie zestawu znaków w nagłówkach HTTP i bazie danych, ale nic z tego nie ma znaczenia, jeśli kod PHP nie wyświetla prawidłowego kodu UTF8. To jest najtrudniejsza część, a PHP nie daje praktycznie żadnej pomocy. (Myślę, że PHP6 powinien naprawić najgorsze z tego, ale wciąż jest trochę czasu)
źródło
Jeśli chcesz, aby 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 swojegomy.cnf
, poniżej[mysqld]
i uruchom ponowniemysql
.Może to powodować problemy, jeśli używasz czegokolwiek innego niż UTF8.
źródło
Najlepsza odpowiedź jest doskonała. Oto, co musiałem zrobić podczas regularnej instalacji debian / php / mysql:
to było wszystko !
źródło
jeśli chcesz rozwiązania mysql, po migracji serwera miałem podobne problemy z 2 moimi projektami. Po przeszukaniu i wypróbowaniu wielu rozwiązań natknąłem się na ten / nic, zanim ten zadziałał):
Po dodaniu tej linii do mojego pliku konfiguracyjnego wszystko działa dobrze!
Znalazłem to rozwiązanie https://www.w3schools.com/PHP/func_mysqli_set_charset.asp, kiedy szukałem rozwiązania wstawki z zapytania HTML
powodzenia!
źródło
Tylko uwaga:
Stoją problemu swoimi niełacińskie znaków pokazuje jak
?????????
, ty zadał pytanie, a on został zamknięty z odniesieniem do tej kanonicznej pytanie, próbowałem wszystkiego i nie ważne co robisz jeszcze dostać??????????
odMySQL
.Wynika to głównie z tego, że testujesz swoje stare dane, które zostały wstawione do bazy danych przy użyciu niewłaściwego zestawu znaków i zostały przekonwertowane i zapisane w postaci znaków znaku zapytania
?
. Co oznacza, że na zawsze utraciłeś oryginalny tekst i bez względu na to, co spróbujesz, otrzymasz???????
.ponowne zastosowanie tego, czego nauczyłeś się z odpowiedzi na to pytanie, na świeże dane, może rozwiązać Twój problem.
źródło
Miałem ten problem podczas wyświetlania tabel. Po prostu umieszczam to na każdej zmiennej wyjściowej echa:
źródło