SET NAMES utf8 no MySQL?

110

Costumo ver algo semelhante a isso abaixo em scripts PHP usando MySQL

query("SET NAMES utf8");   

Eu nunca tive que fazer isso para nenhum projeto ainda, então tenho algumas perguntas básicas sobre isso.

  1. Isso é algo que é feito apenas com o PDO?
  2. Se não for uma coisa específica do PDO, qual é o propósito de fazê-lo? Sei que está definindo a codificação para mysql, mas quero dizer, eu nunca tive que usá-lo, então por que eu iria querer usá-lo?
JasonDavis
fonte
4
"SET NAMES utf8" deve ser evitado por causa da injeção de SQL. Consulte php.net/manual/en/mysqlinfo.concepts.charset.php para obter detalhes.
masakielastic
3
@masakielastic Não vejo onde definir 'definir nomes utf8' é uma ameaça à injeção de sql? Usando a API MySQL adequada, onde está o segmento?
banda larga de
3
Desculpe pela minha indelicadeza. Veja a resposta do ircmaxell: stackoverflow.com/a/12118602/531320 Althogh "SET NAMES" não tem problemas, desde que use UTF-8, a possibilidade de você usar GBK ou Big5 (chinês) ou Shift_JIS (japonês) no futuro é inegável .
masakielastic

Respostas:

74

É necessário sempre que você deseja enviar dados ao servidor com caracteres que não podem ser representados em ASCII puro, como 'ñ' ou 'ö'.

Isso se a instância do MySQL não estiver configurada para esperar a codificação UTF-8 por padrão das conexões do cliente (muitas estão, dependendo de sua localização e plataforma).

Leia http://www.joelonsoftware.com/articles/Unicode.html caso você não saiba como o Unicode funciona.

Leia Se deve usar "SET NAMES" para ver as alternativas de SET NAMES e do que exatamente se trata.

Vinko Vrsalovic
fonte
3
'ö' e 'ñ' são ASCII estendidos. Você ainda precisa SET NAMES UTF8para eles?
Tim
2
Eu descobri que muitas vezes preciso adicionar utf8_decode ($ my_text); em PHP para obter caracteres UTF-8 especiais para serem exibidos em sites corretamente quando os dados foram consultados no MySQL. Minhas tabelas e colunas são definidas como UTF-8 no MySQL - então isso deve ser necessário?
NexusRex
1
@ Vinko Vrsalovic: Não necessariamente ... eu tinha todos os meus arquivos em utf8, mas meu hoster anterior tinha o conjunto de caracteres mysql definido como latin1 e como eu não disse ao mysql que estou enviando caracteres em utf8 (daí os nomes de conjunto utf8), ele os armazenou em caracteres latinos e todos os meus caracteres especiais (čšž esloveno) pareciam ter sido invadidos por um carro - mais uma coisa: quando você faz uma pesquisa no phpmyadmin, você não encontrará resultados, porque a č é como Å e assim por diante
Erik Čerpnjak
Observe que também especifica o conjunto de caracteres que o servidor deve usar para enviar os resultados de volta ao cliente, portanto, também é necessário ao receber esses dados, usando por exemplo uma SELECTinstrução.
Leopoldo Sanczyk de
@Tim. Não existe realmente algo como "ASCII estendido". Há um monte de codificações diferentes que podem ser chamadas de ASCII estendido (qualquer conjunto de caracteres de byte único em que a primeira metade é igual ao ASCII, e há muitos deles).
TRiG
43

Do manual :

SET NAMES indica qual conjunto de caracteres o cliente usará para enviar instruções SQL para o servidor.

Mais elaboradamente (e mais uma vez, retirado gratuitamente do manual ):

SET NAMES indica qual conjunto de caracteres o cliente usará para enviar instruções SQL para o servidor. Assim, SET NAMES 'cp1251' diz ao servidor, “as mensagens de entrada futuras deste cliente estão no conjunto de caracteres cp1251”. Ele também especifica o conjunto de caracteres que o servidor deve usar para enviar os resultados de volta ao cliente. (Por exemplo, indica qual conjunto de caracteres usar para valores de coluna se você usar uma instrução SELECT.)

karim79
fonte
6
Eu te amo. Acabei de fazer minha noite!
karim79
34

Acertar a codificação é realmente complicado - existem muitas camadas:

  • Navegador
  • Página
  • PHP
  • MySQL

O comando SQL "SET CHARSET utf8" do PHP irá garantir que o lado do cliente (PHP) irá obter os dados em utf8, não importa como eles estão armazenados no banco de dados. Claro, eles precisam ser armazenados corretamente primeiro.

Definição DDL vs. dados reais

A codificação definida para uma tabela / coluna não significa realmente que os dados estão nessa codificação. Se por acaso você tiver uma tabela definida como, utf8mas armazenada com codificação diferente, o MySQL irá tratá-la como utf8e você terá problemas. O que significa que você tem que consertar isso primeiro.

O que verificar

Você precisa verificar em qual codificação o fluxo de dados em cada camada.

  • Verifique os cabeçalhos HTTP, cabeçalhos.
  • Verifique o que realmente foi enviado no corpo da solicitação.
  • Não se esqueça de que o MySQL possui codificação em quase todos os lugares:
    • Base de dados
    • Mesas
    • Colunas
    • Servidor como um todo
    • Cliente
      Certifique-se de que haja o correto em todos os lugares.

Conversão

Se você receber dados, por exemplo windows-1250, e quiser armazenar utf-8, use este SQL antes de armazenar:

SET NAMES 'cp1250';

Se você tem dados no banco de dados windows-1250e deseja recuperá-los utf8, use:

SET CHARSET 'utf8';

Mais algumas notas:

  • Não confie em ferramentas muito "inteligentes" para mostrar os dados. Por exemplo, phpMyAdmin faz (fazia quando eu o estava usando) a codificação muito ruim. E passa por todas as camadas, então é difícil descobrir.
  • Além disso, o Internet Explorer tinha um comportamento realmente estúpido de "adivinhar" a codificação com base em regras estranhas.
  • Use editores simples onde você pode alternar a codificação. Eu recomendo o MySQL Workbench.
Ondra Žižka
fonte
19

Esta consulta deve ser escrita antes da consulta que cria ou atualiza os dados no banco de dados, esta consulta se parece com:

mysql_query("set names 'utf8'");

Observe que você deve escrever a codificação que está usando no cabeçalho, por exemplo, se estiver usando utf-8 e adicioná-la assim no cabeçalho ou isso causará um problema com o Internet Explorer

então sua página se parece com esta

<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
fonte
8
Você não deve usar a biblioteca PHP mysql em vez disso, deve usar MySQLi ou PDO.
André Figueira
Ótima resposta, obrigado pelo exemplo. Esta é a única resposta que me ajudou a visualizar o que eu precisava fazer e resolveu meu problema!
GTS Joe
1
A última tag deve ser </html> e não <html>
GTS Joe
9

A solução é

 $conn->set_charset("utf8");
nurp
fonte
5

Em vez de fazer isso por meio de uma consulta SQL, use a função 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.

Consulte a seção de conceitos do conjunto de caracteres MySQL para obter mais informações.

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

user1783273
fonte
1

Obrigado @todos!

não use: query ("SET NAMES utf8"); isso é coisa de configuração e não uma consulta. coloque-o imediatamente após o início da conexão com setCharset () (ou método semelhante)

alguma coisinha em parctice:

status:

  • O servidor mysql por padrão fala latin1
  • seu aplicativo completo está em utf8
  • a conexão é feita sem nenhum extra (então: latin1) (nenhum SET NAMES utf8 ..., nenhum método / função set_charset ())

Armazenar e ler dados não é problema, desde que o mysql possa lidar com os caracteres. se você olhar no banco de dados, verá que há porcaria nele (por exemplo, usando phpmyadmin).

até agora isso não é problema! (errado, mas funciona com frequência (na Europa)) ..

..a menos que outro cliente / programa ou uma biblioteca alterada, que funcione corretamente, irá ler / salvar os dados. então você está em apuros!

user3162905
fonte
0

Não apenas PDO. Se sql responder como '????' símbolos, preset de seu charset (espero UTF-8) realmente recomendado:

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

ou via estilo de procedimento mysqli_set_charset($db,"utf8")

dmitry_podyachev
fonte