USTAWIĆ NAZWY utf8 w MySQL?

110

Często widzę coś podobnego do tego poniżej w skryptach PHP używających MySQL

query("SET NAMES utf8");   

Nigdy nie musiałem tego robić dla żadnego projektu, więc mam kilka podstawowych pytań na ten temat.

  1. Czy robi się to tylko z PDO?
  2. Jeśli nie jest to rzecz specyficzna dla ChNP, to jaki jest cel tego robić? Zdaję sobie sprawę, że to ustawia kodowanie dla mysql, ale mam na myśli, że nigdy nie musiałem go używać, więc dlaczego miałbym go używać?
JasonDavis
źródło
4
Należy unikać „SET NAMES utf8” z powodu iniekcji SQL. Szczegółowe informacje można znaleźć na stronie php.net/manual/en/mysqlinfo.concepts.charset.php.
masakielastic
3
@masakielastic Nie widzę, gdzie ustawienie „set names utf8” jest zagrożeniem dla sql injection? Korzystanie z odpowiedniego API MySQL, gdzie jest wątek?
szerokopasmowy
3
Przepraszam za moją nieuprzejmość. Zobacz odpowiedź ircmaxell: stackoverflow.com/a/12118602/531320 Althogh "SET NAMES" nie ma problemu, o ile używasz UTF-8, możliwość użycia GBK lub Big5 (chiński) lub Shift_JIS (japoński) w przyszłości jest niezaprzeczalna .
masakielastic

Odpowiedzi:

74

Jest potrzebny, gdy chcesz wysłać dane do serwera zawierające znaki, których nie można przedstawić w czystym ASCII, takie jak „ñ” lub „ö”.

Jeśli instancja MySQL nie jest skonfigurowana tak, aby domyślnie oczekiwać kodowania UTF-8 od połączeń klientów (wiele z nich, w zależności od lokalizacji i platformy).

Przeczytaj http://www.joelonsoftware.com/articles/Unicode.html, jeśli nie wiesz, jak działa Unicode.

Przeczytaj, czy używać opcji „SET NAMES”, aby zobaczyć alternatywne opcje SET NAMES i o co dokładnie chodzi.

Vinko Vrsalovic
źródło
3
„ö” i „ñ” to rozszerzone znaki ASCII. Czy nadal będziesz tego potrzebować SET NAMES UTF8?
Tim
2
Odkryłem, że często muszę dodawać utf8_decode ($ my_text); w PHP, aby uzyskać specjalne znaki UTF-8 do prawidłowego wyświetlania na stronach internetowych, gdy dane były odpytywane z MySQL. Moje tabele i kolumny są ustawione na UTF-8 w MySQL - więc czy to powinno być konieczne?
NexusRex
1
@ Vinko Vrsalovic: Niekoniecznie ... Miałem wszystkie swoje pliki w utf8, ale mój poprzedni hoster miał zestaw znaków mysql ustawiony na latin1 i ponieważ nie powiedziałem mysql, że wysyłam znaki w utf8 (stąd ustawiłem nazwy utf8), zapisał je w alfabecie łacińskim i wszystkie moje znaki specjalne (słoweński čšž) wyglądały, jakby zostały przejechane przez samochód - jeszcze jedno: kiedy wyszukujesz w phpmyadmin, nie znajdziesz wyników, ponieważ č jest jak Å i tak dalej
Erik Čerpnjak
Należy zauważyć, że określa również zestaw znaków, których serwer powinien używać do wysyłania wyników z powrotem do klienta, dlatego jest również potrzebny podczas odbierania tych danych, na przykład przy użyciu SELECTinstrukcji.
Leopoldo Sanczyk
@Tim. Nie ma czegoś takiego jak „rozszerzone ASCII”. Istnieje cała masa różnych kodowań, które można nazwać rozszerzonym ASCII (dowolny zestaw znaków jednobajtowych, w którym pierwsza połowa jest taka sama jak ASCII, a jest ich mnóstwo).
TRiG
43

Z instrukcji :

SET NAMES wskazuje, jakiego zestawu znaków klient będzie używał do wysyłania instrukcji SQL do serwera.

Bardziej szczegółowo (i po raz kolejny bezpłatnie usunięty z podręcznika ):

SET NAMES wskazuje, jakiego zestawu znaków klient będzie używał do wysyłania instrukcji SQL do serwera. W związku z tym SET NAMES 'cp1251' mówi serwerowi, że „przyszłe wiadomości przychodzące od tego klienta mają zestaw znaków cp1251”. Określa również zestaw znaków, którego serwer powinien używać do wysyłania wyników z powrotem do klienta. (Na przykład wskazuje, jakiego zestawu znaków użyć dla wartości kolumn, jeśli używasz instrukcji SELECT).

karim79
źródło
6
Kocham Cię. Właśnie sprawiłem, że mój wieczór!
karim79
34

Właściwe kodowanie jest naprawdę trudne - jest zbyt wiele warstw:

  • Przeglądarka
  • Strona
  • PHP
  • MySQL

Polecenie SQL „SET CHARSET utf8” z PHP zapewni, że strona klienta (PHP) otrzyma dane w utf8, niezależnie od tego, jak są one przechowywane w bazie danych. Oczywiście najpierw należy je prawidłowo przechowywać.

Definicja DDL a dane rzeczywiste

Kodowanie zdefiniowane dla tabeli / kolumny nie oznacza tak naprawdę, że dane są w tym kodowaniu. Jeśli zdarzyło ci się mieć tabelę zdefiniowaną jako, utf8ale przechowywaną jako inne kodowanie, MySQL potraktuje je jako utf8i masz kłopoty. Co oznacza, że ​​musisz najpierw to naprawić.

Co sprawdzić

Musisz sprawdzić, jakie kodowanie przepływu danych na każdej warstwie.

  • Sprawdź nagłówki HTTP, nagłówki.
  • Sprawdź, co tak naprawdę zostało wysłane w treści żądania.
  • Nie zapominaj, że MySQL ma kodowanie prawie wszędzie:
    • Baza danych
    • Tabele
    • Kolumny
    • Serwer jako całość
    • Klient
      Upewnij się, że wszędzie jest właściwy.

Konwersja

Jeśli otrzymujesz dane np. windows-1250I chcesz je przechowywać utf-8, użyj tego SQL przed zapisaniem:

SET NAMES 'cp1250';

Jeśli masz dane w DB jako windows-1250i chcesz je odzyskać utf8, użyj:

SET CHARSET 'utf8';

Jeszcze kilka uwag:

  • Nie polegaj na zbyt „inteligentnych” narzędziach do przedstawiania danych. Np. PhpMyAdmin nie (robił tego, kiedy go używałem) kodował naprawdę źle. I przechodzi przez wszystkie warstwy, więc trudno się tego dowiedzieć.
  • Ponadto Internet Explorer miał naprawdę głupie zachowanie polegające na „zgadywaniu” kodowania na podstawie dziwnych reguł.
  • Użyj prostych edytorów, w których możesz przełączać kodowanie. Polecam MySQL Workbench.
Ondra Žižka
źródło
19

To zapytanie powinno być wpisane przed zapytaniem, które tworzy lub aktualizuje dane w bazie danych, takie zapytanie wygląda następująco:

mysql_query("set names 'utf8'");

Zauważże powinieneś napisać kod, którego używasz w nagłówku np. Jeśli używasz utf-8 dodajesz go w ten sposób w nagłówku albo spowoduje to problem z Internet Explorerem

więc twoja strona wygląda tak

<html>
    <head>
        <title>page title</title>
        <meta charset="UTF-8" />   
    </head>
    <body>
    <?php
            mysql_query("set names 'utf8'");   
            $sql = "INSERT * FROM ..... ";  
            mysql_query($sql);
    ?>    

    </body>
</html>
usama sulaiman
źródło
8
Nie powinieneś używać biblioteki PHP mysql zamiast tego powinieneś używać MySQLi lub PDO.
André Figueira
Świetna odpowiedź, dzięki za przykład. To jedyna odpowiedź, która pomogła mi wyobrazić sobie, co muszę zrobić, i rozwiązała mój problem!
GTS Joe
1
Ostatni tag powinien być </html> a nie <html>
GTS Joe
9

Rozwiązaniem jest

 $conn->set_charset("utf8");
nurp
źródło
5

Zamiast robić to za pomocą zapytania SQL, użyj funkcji php: mysqli :: set_charset mysqli_set_charset

Note:

This is the preferred way to change the charset. Using mysqli_query() to set it (such as SET NAMES utf8) is not recommended.

Więcej informacji można znaleźć w sekcji Pojęcia dotyczące zestawów znaków MySQL.

z http://www.php.net/manual/en/mysqli.set-charset.php

user1783273
źródło
1

Dziękuje wszystkim!

nie używaj: query ("SET NAMES utf8"); to jest konfiguracja, a nie zapytanie. umieść to zaraz po rozpoczęciu połączenia za pomocą setCharset () (lub podobnej metody)

mała rzecz na parctice:

status:

  • serwer mysql domyślnie rozmawia latin1
  • Twoja aplikacja dziury jest w utf8
  • połączenie jest tworzone bez żadnych dodatkowych elementów (więc: latin1) (brak SET NAMES utf8 ..., brak metody / funkcji set_charset ())

Przechowywanie i odczytywanie danych nie stanowi problemu, o ile mysql może obsługiwać znaki. jeśli zajrzysz do bazy danych, zobaczysz, że jest w niej bzdura (np. używając phpmyadmin).

do tej pory nie stanowi to problemu! (źle, ale działa często (w Europie)).

.. chyba, że ​​inny klient / program lub zmieniona biblioteka, która działa poprawnie, odczyta / zapisze dane. to masz duże kłopoty!

user3162905
źródło
0

Nie tylko PDO. Jeśli sql odpowie jak „????” symbole, twój zestaw znaków (mam nadzieję, że UTF-8) naprawdę polecam:

if (!$mysqli->set_charset("utf8")) 
 { printf("Can't set utf8: %s\n", $mysqli->error); }

lub za pomocą stylu procedury mysqli_set_charset($db,"utf8")

dmitry_podyachev
źródło