Problema de acentuação no MySQL: Latin1 x UTF8

Publicidade

Um cliente me forneceu o backup de seu banco de dados MySQL, porém, ao importá-lo alguns caracteres estranhos substituíam os esperados acentos. Palavra com "Olá" estava escrita como "Olá", "Termos de Serviço" estava como "Termos de Serviço".

O Problema obviamente era de codificação (charset, collation) utilizada entre os dois bancos: o Banco original estava no padrão Latin 1 (latin_swedish_ci) enquanto o outro estava em UTF8 (utf8_general_ci). Caracteres como "ç", "ã", "á" e etc pertence ao padrão Latin 1 (ISO-8859-1); o padrão UTF8 por utilizar menos dados para armazenar cada caractere é obrigado a representar as letras acentuadas (e a cedilha) utilizando dois caracteres, o que vem a causar este problema.

A solução óbvia para esta falha seria modificar o charset do banco de dados e da tabela. Mas isto não solucionou o meu caso. Resolvi então utilizar uma abordagem menos rebuscada: criei um script PHP para atualizar cada linha na tabela do banco de dados convertendo-as para o padrão desejado.

Para isso utilizei a função mb_convert_encoding:

[php]
<?php

set_time_limit(0); // Tempo máximo de execução: sem limite (0).

// ----------------------------------------------------------------------
// Configurações
// ----------------------------------------------------------------------

define("SETTINGS_SGBD_HOST", "localhost");
define("SETTINGS_SGBD_PORT", "3306");
define("SETTINGS_SGBD_USER", "");
define("SETTINGS_SGBD_PASSWORD", "");
define("SETTINGS_SGBD_DATABASE", "");

define("SETTINGS_SGBD_FIX_TABLE", "");
define("SETTINGS_SGBD_FIX_FIELD", "");

// ----------------------------------------------------------------------
// Conectar ao Banco de Dados
// ----------------------------------------------------------------------

$lobj_databaseObject = mysql_connect(SETTINGS_SGBD_HOST.":".SETTINGS_SGBD_PORT, SETTINGS_SGBD_USER, SETTINGS_SGBD_PASSWORD);
mysql_select_db(SETTINGS_SGBD_DATABASE);
if ( $lobj_databaseObject == false ) exit;
mysql_set_charset('latin1', $lobj_databaseObject);

// ----------------------------------------------------------------------
// Atualiza a tabela corrigindo a codificação
// ----------------------------------------------------------------------

$lstr_SQLQuery = "SELECT ".SETTINGS_SGBD_FIX_FIELD." FROM ".SETTINGS_SGBD_FIX_TABLE;

$lobj_recordsetFields = mysql_query ($lstr_SQLQuery, $lobj_databaseObject);

if ( mysql_num_rows($lobj_recordsetFields) > 0 ) {
while ($lobj_rowTerm = mysql_fetch_object( $lobj_recordsetFields )) {

$lstr_fixFieldContent = eval( "return $lobj_rowTerm->".SETTINGS_SGBD_FIX_FIELD.";");
$lstr_SQLQuery = "UPDATE ".SETTINGS_SGBD_FIX_TABLE." SET ".SETTINGS_SGBD_FIX_FIELD." = '".mb_convert_encoding($lstr_fixFieldContent, 'ISO-8859-1', 'UTF-8')."' WHERE ".SETTINGS_SGBD_FIX_FIELD." LIKE '$lstr_fixFieldContent'";
mysql_query ($lstr_SQLQuery, $lobj_databaseObject);

}
}

// ----------------------------------------------------------------------
// Desconectar do Banco de Dados
// ----------------------------------------------------------------------

mysql_close ( $lobj_databaseObject );

?>
[/php]

Para utilizar o script acima, modifique as constantes:

  • SETTINGS_SGBD_HOST: IP do servidor;

  • SETTINGS_SGBD_PORT: porta de conexão do servidor;

  • SETTINGS_SGBD_USER: nome do usuário;

  • SETTINGS_SGBD_PASSWORD: senha do usuário;

  • SETTINGS_SGBD_DATABASE: banco de dados onde se localiza o problema;

  • SETTINGS_SGBD_FIX_TABLE: tabela onde se localiza o problema;

  • SETTINGS_SGBD_FIX_FIELD: campo onde se localiza o problema.


  • Lembre-se: Este script deve ser executado apenas uma vez! Na segunda execução o script tentará converter novamente os textos para Latin1, removendo todas as letras que estão acentuadas.



    O que você achou? Tem alguma sugestão para resolver este problema ou algo a dizer que complemente este artigo. Deixe seu comentário!

    Até mais!
    Charset
    setembro 07, 2011
    4

    Comentários

    1. Muito bom cara! Resolveu meu problema

      ResponderExcluir
    2. Seu script é excelente, mas tenho uma dúvida, como eu poderia fazer para aplicar geral no banco, sem eu ter que ficar preenchendo o nome da tabela mais o campo, ou seja, que ele verificasse em todas as tabelas e em todos os campos. Teria como você me ajudar ?

      ResponderExcluir
    3. e como saber qual campo da tabela e a propria tabela está em látin1?

      ResponderExcluir
    4. Para arrumar a base:

      UPDATE tabela SET coluna1 = CONVERT(CAST(coluna1 as BINARY) USING utf8), coluna2 = CONVERT(CAST(coluna2 as BINARY) USING utf8);
      ALTER TABLE `tabela` CHARACTER SET utf8 COLLATE utf8_general_ci ROW_FORMAT = DYNAMIC;

      Para os arquivos PHP:
      header('Content-Type: text/html; charset=utf-8');
      mysql_query("SET NAMES 'utf8'");
      mysql_query('SET character_set_connection=utf8');
      mysql_query('SET character_set_client=utf8');
      mysql_query('SET character_set_results=utf8');

      NO HTML:

      ResponderExcluir

    Postar um comentário

    Menu

    Pesquisar

    Últimos Comentários

    Fale Comigo