Por que seus acentos viram "Привет" e como corrigir isso de uma vez por todas
\n\nVocê já abriu seu site em PHP e, em vez do esperado "Olá, mundo!", viu algo como Привет, РјСЂСЂ!? Se sim, parabéns: você encontrou o clássico problema do UTF-8 all the way through. É aquela situação em que a codificação quebra em algum lugar entre o banco de dados e o navegador, e todo mundo culpa todo mundo.
No Stack Overflow, essa questão já acumulou milhares de visualizações e centenas de respostas. Não é à toa. Mesmo desenvolvedores experientes às vezes se perdem nas configurações de codificação. Neste tutorial, vamos seguir uma receita passo a passo para alinhar PHP, MySQL e navegador, garantindo que o UTF-8 funcione em todos os lugares. Sem mágica — apenas configurações corretas.
\n\nPasso 1. Banco de dados: a base da sua codificação
\n\nTudo começa no banco. Se seus dados no MySQL estão em latin1 ou cp1251 e você tenta exibi-los em UTF-8, o resultado serão caracteres estranhos. Mas mesmo que o banco esteja em UTF-8, há um detalhe: a codificação antiga utf8 no MySQL não suporta emojis nem alguns caracteres raros. A solução é o utf8mb4.
1.1. Criando tabelas com a codificação correta
\n\nAo criar uma nova tabela, sempre especifique:
\n\nCREATE TABLE artigos (\n id INT AUTO_INCREMENT PRIMARY KEY,\n titulo VARCHAR(255) NOT NULL,\n conteudo TEXT NOT NULL\n) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nAlternativamente, defina a codificação padrão para todo o banco de dados:
\n\nALTER DATABASE nome_do_banco CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nImportante: utf8mb4_unicode_ci é o collation (regra de comparação). Ele processa corretamente todos os caracteres Unicode. Se você não precisa de ordenação multilíngue, utf8mb4_general_ci também funciona.
1.2. Convertendo tabelas existentes
\n\nSe você já tem dados em outra codificação, converta-os primeiro:
\n\nALTER TABLE artigos CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nMas cuidado: se a tabela já tinha dados em latin1, eles podem virar codificação dupla (ex.: Привет). Nesse caso, é preciso converter as colunas para binary e depois para utf8mb4. Essa é outra história; para simplificar, considere que você está começando do zero.
Passo 2. Conexão PHP com o banco: configurando o PDO
\n\nNo PHP moderno, você usa PDO (ou mysqli). E há um ponto crítico: após conectar ao banco, é necessário definir explicitamente a codificação. Caso contrário, o PHP se comunicará com o MySQL na codificação padrão (geralmente latin1).
\n\n2.1. String de conexão PDO correta
\n\n$host = 'localhost';\n$dbname = 'seu_banco';\n$username = 'root';\n$password = '';\n\n$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";\n\n$options = [\n PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n PDO::ATTR_EMULATE_PREPARES => false,\n];\n\ntry {\n $pdo = new PDO($dsn, $username, $password, $options);\n} catch (PDOException $e) {\n echo "Falha na conexão: " . $e->getMessage();\n}\n\nRepare no charset=utf8mb4 no DSN. Isso força PHP e MySQL a negociarem a codificação no nível da conexão.
2.2. Método alternativo (se o DSN não funcionar)
\n\nÀs vezes, versões antigas do PHP ou servidores não leem o charset do DSN. Nesse caso, adicione após a conexão:
\n\n$pdo->exec("SET NAMES 'utf8mb4'");\n\nMas o primeiro método é preferível — é mais limpo e moderno.
\n\nPasso 3. Cabeçalhos HTTP e HTML: dizendo a verdade ao navegador
\n\nMesmo que o banco e o PHP estejam em UTF-8, o navegador pode achar que