← Voltar ao blog

Encoding: como detectar e corrigir double-encoding (UTF-8 interpretado como ISO-8859-1)

# Encoding: como detectar e corrigir double-encoding (UTF-8 interpretado como ISO-8859-1) Double-encoding é quando texto UTF-8 é tratado como ISO-8859-1 e re-codificado. Resultado: "São Paulo" vira "...


Double-encoding é quando texto UTF-8 é tratado como ISO-8859-1 e re-codificado. Resultado: "São Paulo" vira "São Paulo". Veja como detectar e corrigir.

O que é double-encoding

  1. Texto original: São Paulo (UTF-8)
  2. Sistema lê como ISO-8859-1: São Paulo
  3. Sistema re-codifica para UTF-8: São Paulo (double-encoded)

Como detectar

No banco (Firebird)

-- Registros com padrão de double-encoding
SELECT nome FROM clientes
WHERE nome CONTAINING 'Ã' OR nome CONTAINING 'Â' OR nome CONTAINING 'ÃÂ'

Em PHP

// Detectar se string está double-encoded
function isDoubleEncoded(string $s): bool {
    $decoded = mb_convert_encoding($s, 'ISO-8859-1', 'UTF-8');
    return mb_check_encoding($decoded, 'UTF-8') && $decoded !== $s;
}

Como corrigir

Solução 1: Decodificar duas vezes

$texto = mb_convert_encoding($texto, 'ISO-8859-1', 'UTF-8'); // primeira decodificação
$texto = mb_convert_encoding($texto, 'ISO-8859-1', 'UTF-8'); // segunda (se necessário)

Solução 2: Corrigir no banco

-- Atualizar registros com double-encoding (Firebird)
UPDATE clientes
SET nome = CAST(nome AS VARCHAR(100) CHARACTER SET ISO8859_1)
WHERE nome CONTAINING 'Ã';

Solução 3: Prevenir na origem

Sempre declare o charset na conexão:

$pdo = new PDO('firebird:dbname=localhost:/db.fdb;charset=UTF8', $user, $pass);

E no HTML:

<meta charset="UTF-8">

Checklist de prevenção

  • Banco de dados com charset definido (UTF8 ou ISO8859_1)
  • Conexão PDO com charset explícito
  • HTML com <meta charset="UTF-8">
  • Headers HTTP com Content-Type: text/html; charset=utf-8
  • Arquivos PHP salvos em UTF-8 sem BOM

Precisa gerar queries para detectar e corrigir encoding no seu banco? Descreva o problema em português no Sqlify.

Conclusão

Double-encoding é silencioso e difícil de detectar. A melhor defesa é declarar charset em todas as camadas: banco, conexão, HTML e headers.