PHP, MySQL e UTF-8 (o guia)

Trabalhar com UTF-8 no PHP pode dar algumas dores de cabeça pra quem é novo, e até mesmo para alguns mais velhinhos… O PHP trabalha por padrão com ISO-8859-1, que são os caracteres latinos que estamos acostumados. Entretanto, o UTF-8 tem uma abrangência maior de caracteres e o ideal seria que nos acostumássemos a usar este charset nas páginas.
Este pequeno tutorial tem como objetivo deixar bem claro quais os passos a se tomar para construir uma aplicação totalmente baseada no charset UTF-8, desde as páginas HTML, passando pelo PHP e por fim no MySQL.
Antes de tudo, aconselho que aprenda a criar os seus arquivos utilizando o UTF-8 sem BOM, que evitará dores de cabeça futuras quando estiver trabalhando com cookies, sessões e headers.
O segundo passo é definir, no PHP que o charset dos arquivos que serão gerados terão a codificação UTF-8, com o seguinte código:
<?php
ini_set('default_charset','UTF-8');
?>

Só setar o charset no PHP não adianta muito, pois alguns navegadores usam a codificação padrão da região do usuário, a não ser que o seguinte código esteja entre as tags <head> e </head>:
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
Com isso, você já pode trabalhar tranquilamente com UTF-8 e PHP sem ter problemas com os caracteres.
Alguns cuidados são necessários quando for trabalhar com o MySQL, entretanto. Vou ensinar como se faz pelo PHPMyAdmin, que acredito que todos que começaram a trabalhar com MySQL estão acostumados.
Em primeiro lugar, ao criar o seu banco de dados, já crie usando o collation utf8_general_ci. Se o banco de dados já tiver um collation definido, não é necessário definir o collation das tabelas, pois elas herdarão o do banco. Mas mesmo assim é bom especificar o charset e collation de cada tabela. Como? Assim:
CREATE TABLE Clientes (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
nome VARCHAR(60) NOT NULL,
PRIMARY KEY(id)
)
TYPE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;

Ok. Nossa tabela está trabalhando com UTF-8 agora. Podemos começar a programar e relaxar porque nossos problemas com charset estão resolvidos, certo?
A resposta é não.
Se você continuar a programar com o sistema assim, os dados do banco serão inseridos e consultados de maneira correta, mas você vai perceber problemas quando tentar fazer buscas com palavras acentuadas insensível a maiúsculas, por exemplo: Água, água e agua serão palavras totalmente diferentes, sem contar que a ordenação de resultados com palavras que começam com letras acentuadas sairá bem bagunçada, coma letra Ó vindo antes de B, por exemplo.
Esse é o problema que eu tive e que demorei eras pra descobrir. O banco estava OK, o PHP também, o mesmo com as páginas HTML… e quando eu inseria algum dado pelo PHPMyAdmin, este era inserido corretamente, o que significava que o problema não era no banco e sim na aplicação.
Depois de meses na verdade foram apenas algumas horas de pesquisa, desconfiei que havia algo na conexão com o MySQL que estava dando esse problema. Fui fuçar no Manual do PHP e encontrei a seguinte solução:
<?php
ini_set('default_charset','UTF-8'); // Para o charset das páginas e
mysql_set_charset('utf8'); // para a conexão com o MySQL
?>

Com isso todos os meus problemas foram resolvidos. Na verdade não, pois tive que alterar todos os campos acentuados da tabela…
Dá para usar a função mysql_client_encoding para identificar o charset da conexão com o MySQL, mas não acho necessário pra quem quer trabalhar diretamente com UTF-8 e não com vários charsets.
Acho que por enquanto é só. Até o próximo semestre! Brincadeira…

48 respostas para “PHP, MySQL e UTF-8 (o guia)”

  1. Paulo Dias disse:

    Aeee o/ Até que enfim atualizou aqui hein, e foi um puta post maluco…
    Muito legal, realmente, conciliar Utf-8, Mysql e Php as vezes é o pontapé pra uma dor de cabeça!
    o/
    Quando eu atualizar o meu blog, de uma passadinha por lá, hehehe.

  2. Mahatma disse:

    Ouw beleza ??

    Veio muito bom seu blog gostei cara

    você explicando tals com certeza ajudará muitas pessoas

    grande abraço

  3. Esse guia do Lee Rain me salvou :D
    Muito bom.

    Abraços,
    Newton Calegari

  4. Xani disse:

    Muito bom o artigo.
    Dessa eu ainda não sabia, vou começar a usar esse esquema aí.
    Valeu
    Abraços

  5. Ricardo disse:

    Rapaz vc solucionou um grande problema que eu estava quebrando a cabeça e não achava a saída!

    Muito obrigado!

    Parabéns pela postagem e assim como me ajudou vai ajudar muitos outros!

    Sucesso meu camarada!!

  6. Vitor disse:

    Você esclareceu muito bem esta questão, parabéns!

    Daqui pra frente, UTF-8 always D:

  7. Felipe Saboya disse:

    Alessandro, você salvou meu final de semana.
    A um ano que eu penso em fazer um bando de dados para o meu site, sexta-feira agora 6/11/09 finalmente aprendi a criar um banco e tudo mais, no sábado criei as páginas em php e hoje domingo estava testando e o problema dos acentos apareceu… finalmente resolvi.
    Você salvou meu final de semana.

    Muitíssimo obrigado.
    Muito sucesso… fique com Deus.

  8. Roger disse:

    Opa!… tche, parabéns. muito bom o post.

    Resolvi meu problema!

    Gracias!

  9. Glaydson disse:

    São Google me trouxe aqui e meu problema foi solucionando. Obrigado pelo post.

  10. Betogroo disse:

    Parabéns pela matéria! Tirou todas as dúvidas!

  11. Luis Francisco disse:

    Ola Alessandro, tudo certo?

    Eu estou enfrentando um problema com o ini_set, eu preciso fazer um upload de um arquivo de 6m, mas ele não vai. O diretorio .ini do servidor está como 2m. Gostaria de saber, você sabe como posso ter certeza que o ini_set está surtindo efeito no código?
    Obrigado pela atenção.

  12. Carlos disse:

    Sensacional este artigo! Me auxiliou bastante!

  13. Alessandro Santos disse:

    Luis, eu acho que o .ini do servidor tem preferência sobre o ini_set. Isso depende de servidor para servidor. Se não me engano no phpinfo() tem alguma variável dentro de $_SERVER que te ajuda a saber o tamanho máximo de upload.

  14. João disse:

    Estou com problema na hora de ordenar.
    No banco todos os dados estão,por exemplo, assim:”Diretor clínico”.
    A conexão está em utf8.
    Vou ter que mudar e colocar a acentuação normal?
    Não entendi quando você disse: “Na verdade não, pois tive que alterar todos os campos acentuados da tabela…”

  15. Alessandro Santos disse:

    João, tive que alterar um por um “/ deve ter um jeito mais rápido, um script sei lá… eu escreveria um script que fizesse a conversão automática.

  16. José Willams disse:

    Esse foi o melhor post que eu já li sobre como resolver esses problemas com UTF-8.

  17. Vilson disse:

    Oi, eu tinha esse mesmo problema, em um sistema adm, mas agora onde o meu charset header é iso e meu banco é utf8 – utf8_general_ci, e tudo aparentemente normal em localhost, ai um problema acontece, nas páginas e não na área adm, o charset header é utf8 e os caracteres do banco parecem desconfigurados, hehe.
    E agora que achei o seu post, vou testar esse método para ver se ajuda, obrigado.

    Abraço.

  18. Muito bom o post, como sou novato no PHP passei dias pesquisando sobre isso e não tinha visto nenhuma solução boa e simples como essa.

    Obrigado !!

  19. Fernando Hannemann disse:

    Parabéns Alessandro!!!

    Este post é nota dez. muito bem explicado.

    Vlw.

  20. Ola Alessandro, muito bom post, parabéns pelo trabalho… Aqui deu tudo certinho, só estou com um probleminha, veja se consegue me ajudar.
    Estou fazendo cadastro no banco de dados enviando as informações pro servidor assíncronamente, via ajax. E no banco os caracteres são subistituidos pelo ‘?”.
    Acredito que esse problema está nos códigos javascript… Você saberia como sulucionar isso?

    Um abraço!

  21. ahh esqueci de falar uma coisa..
    este problema que citei acima só ocorreu no IE… ooo maravilha!

  22. Alessandro Santos disse:

    @julio, nas requisições assíncronas você pode usar encodeURIComponent nas variáveis… pode ser isso. Também uma vez tive problemas com o IE pois defini a tag como “utf-8″ em minúsculas, mas não sei se foi por isso que deu problema.

  23. Bingo… fiquei horas olhando a codificação do Jquery pra ver se achava algo a respeito, mas o problema era bem mais simples de resolver, e o Alessandro acertou na mosca, é só usar o encodeURIComponent.

    Concluindo,… quem tiver usando transferência de dados assíncona com o servidor php, faça um pequeno tratamento nas strings usando o encodeURIComponent.

    Minha aplicação está supimpa em qualquer browser…

    Muito obrigado cara!
    Sucesso!

  24. Andre disse:

    Parabéns! Sempre tive essas confusões. Muito esclarecedor! Vou tentar sempre usar UTF.

    Abração

  25. André disse:

    Muito boas as dicas! Engraçado que fiz um site do zero assim e deu certo.

    Porém, agora estou modificando um que estava pronto e a acentuação fica toda bonitinha no LOCALHOST… Quando visualizo no servidor web fica com os ‘?’ no lugar dos acentos… =/

    Dicas?

  26. Alessandro Santos disse:

    Veja como está a collation do banco e das tabelas no servidor, talvez seja preciso um trabalho extra pra acertar os dados que já existem por lá. Insira novos dados com acentos pra ver se eles aparecem.

  27. André disse:

    Mas nesse caso nem é problema com o BD, já que o texto que aparece com os acentos errados está dentro do próprio html. Já o que vem do BD, com as suas dicas, deu certinho. :)

    Fiz assim:
    Coloquei no topo da página:
    ini_set(‘default_charset’,'UTF-8′);

    Dentro da head:

    E o texto eu acentuo normalmente…
    Dai funciona no meu Localhost, mas quando jogo pra web, da erro. :(

    Um exemplo:
    http://www.avesportes.com.br/argentinamania86/status_pedido.php?id_venda=80&email=fr.andre@gmail.com

    O texto que está no retangulo verde, vem do BD… repare que GRÊMIO está devidamente acentuado. Correto.
    Já o resto do texto, está no html, acentuado da mesma forma que grêmio, porém aparecem ‘?’.

    Obrigado pela força

  28. Alessandro Santos disse:

    André, um dos arquivos include deve estar com outro charset. Digo, charset do arquivo mesmo. Dá mais uma olhada em cada um lá veja se vc atualizou esses arquivos no servidor, as vezes algum passa batido.

  29. André disse:

    Charset do arquivo? Mas mesmo assim, não tem nenhum include… Apenas o de conexão com o BD, que só tem código php…

    Em todo caso, valeu pela força! Abração e parabéns pelo blog.

  30. Tofolê disse:

    Alessandro boa. Sei que o tópico em um pouco antigo, mas como não entendo bulhufas de php vou tentar esclarecer minha duvida, seguinte:
    Tenho na pagina de contato um form que manda a mensagem através de e-mail “acredito que sejam todos assim” e manda uma confirmação de envio a pessoa na qual mandou a mensagem. O meu problema não está do db o meu problema é que tanto o e-mail que recebo e a resposta que a pessoa recebe vem com aqueles caracteres estranhos (é = é), depende na mensagem que a pessoa te manda não da para entender nada, nesse caso já está tudo como UTF-8 , já tentei passar para ISSO-8859-1 o e-mail de resposta a pessoa sai correto mas o de destinatário sempre a mesma bagunça de caracteres e também bagunça o db. Tenho os arquivos db, conexão, form e contato compactado no seguinte link: http://www.megaupload.com/?d=Y789YBC8 (não contem vírus) se alguém puder me ajudar ficaria muito grato já que não entendo nada de php o pouco que estou fazendo graças a “SÃO GOOGLE” obrigado a atenção de todos.

  31. Bruno Costa disse:

    Com esse post, eu consegui solucionar um problema que tive por muito tempo. Obrigado pela ajuda

  32. paulophp disse:

    Opa, o mysql_set_charset me salvou tbm! Ainda nao tinha usado!
    Valeu!

  33. [...] UTF-8 resolve muitos problemas com acentuação de palavras, fazer sua implementação pode ser um pouco trabalhoso mais vai lhe evitar futuras dores de cabeça, veja um bom tutorial aqui. [...]

  34. Ricardo disse:

    Opa, você me salvou nessa rsrs!

    tava doido, exclui a tabela umas 50x, criei ela com todos os tipos diferentes de UTF e sempre aparecia os caracteres estranhos, sorte minha que a sua pagina foi um dos primeiros resultados no “santo google”!

    Valeu pela dica e parabens pelo site!

  35. Carlos H. Fructuoso M. Rodrigues disse:

    Cara esse POST foi muito bom, parabéns.

    Me ajudou muito, e pode ter certeza muita gente tem dúvidas sobre e sofre pra entender isso,

    valew obrigado

  36. Júnior disse:

    Valeu cara, você me ajudou muito com esse POST! Muito bom mesmo… :)

  37. Alberto disse:

    Fiz tudo passo a passo e não rolou.
    Pelo que vi acima, o pessoal elogiou, elogiou, mas ninguém disse que testou pra ver se funciona.

  38. Cara, com certeza é uma grande ajuda!
    Valeu mesmo, bem explicado e prático ao mesmo tempo.

    Obrigado.

  39. Danillo disse:

    Bom, a galera já falo o que eu ia falar então eu vou falar o que eles não falaram. Você ta com uma cara de safadinho lá em cima ein ;].

    rs
    É sério, mesmo que não seja relevante, mas ta com cara.
    .
    .
    .
    Eu tava fazendo certo só não sabia dessa parte da função mysql_set_charset().
    Naverdade eu prefiro usar sempre arquivos xml ou txt ou sem extensão por que são mais simples de usar.

    T+

  40. Flavio Souza disse:

    Sensacional este post. Salvou o dia! Parabéns!

  41. Junior Lemos disse:

    Excelente Post! Me ajudou bastante. Parabéns pelo trabalho.

  42. marcelo disse:

    é rapaz, 2011 e esse post ainda ajuda, vlw viu. jocas

  43. Márcio disse:

    Cara vlw mesmo . . .ajudou mt . .estava com um grande problema em um formulario de envio de arquivos . . . .como nao estava enviando os arquivos mas o php mostrava que eles tinha vindo para a pasta temporaria o unico problema que poderia existir era codificação . . . dps de converter os .php’s para UTF-8 tudo se resolveu ! !
    vlww

  44. Paula C. Laun disse:

    Gostei muito de seu post. Explica de forma simples e esclarecedora o ordenamento de listas geradas a partir de bancos MySQL setados com UTF-8. Obrigada.

  45. Kassio PS disse:

    Me ajudou muito, valeu!

  46. Valeu cara. Solucionou geral aqui. Passei horas aqui tentando e nada. Trocava a codificação do html e os dados recuperados do mysql ficavam ruim e vice-versa.

  47. [...] PHP, MySQL e UTF-8 (o guia) - http://alessandrosantos.com.br/2009/08/18/php-mysql-e-utf-8-o-guia/ [...]

Deixe um comentário