Com as duas entregas anteriores sobre problemas de codificação de caracteres (Parte I – Apache e Parte II – PHP), praticamente todos os erros de codificação de caracteres (charset) deveriam estar solucionados.
No entanto, cada vez mais projectos PHP utilizam comunicações com base de dados. Uma das base de dados livres mais conhecida é MySQL. As base de dados servem basicamente para armazenar e enviar informação.
Os que utilizam esta tecnologia já reparam que muitas vezes a informação armazenada é diferente da informação enviada ou vice-versa. Exacto, que por vezes se vê uns caracteres esquisitos no conteúdo das tabelas da base de dados ou se vê caracteres esquisitos quando recebemos a informação da base de dados.
E porque? A informação não deveria ser igual em ambas as partes?
Sim… De facto, deveria ser igual em ambas as partes. Mas esta situação devesse a que ambos sistemas (MySQL e PHP) se comunicam com um sistema de codificação de caracteres diferente. Se usamos o exemplo do capitulo anterior, PHP se esta comunicando em UTF-8, no entanto, MySQL por defeito se comunica em “Latin 1″. Por isso, esses caracteres esquisitos.
Vamos recordar a teoria referida na primeira parte:
“Se trabalhamos com UTF-8, então todos os ficheiros e comunicações devem de se realizar com este tipo de codificação de caracteres.”
Portanto que temos que fazer?
Temos de por o servidor MySQL a comunicar-se com a mesma codificação de caracteres.
Exemplo com uma base de dados MySQL em “Latin1″ e ficheiro PHP em UTF-8:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt" lang="pt">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Charset</title>
</head>
<body>
<?php
if($db = mysql_connect('127.0.0.1', 'root', '1234'))
{
mysql_select_db('demos');
$query = "SELECT * FROM demos;";
if($dadosDb = mysql_query($query, $db))
{
while ($obj = mysql_fetch_object($dadosDb))
{
echo '<div>' . $obj->name . ' - ' . $obj->value . ' - ' . $obj->obs . '';
}
mysql_free_result($dadosDb);
}
else { echo 'Erro na petição.'; };
}
else { echo 'Erro na conexão.'; };
mysql_close($db);
?>
</body>
</html>
Conteúdo da tabela MySQL:

Resultado:

O resultado foi o esperado… Como a base de dados está em “Latin 1″ e o nosso ficheiro e a respectiva meta tag está em UTF-8, o resultado só podia ser caracteres esquisitos.
Que acontece se inserimos algo na base de dados através do ficheiro PHP?
Consulta:
Resultado:

Como podemos observar como não existe uma comunicação na mesma codificação de caracteres, tudo o que inserimos será mal interpretado pela base de dados.
Como solucioná-lo?
Se queremos solucionar este problema de uma vez nas nossas base de dados MySQL devemos fazer as seguintes alterações no ficheiro “my.ini” ou “my.cnf” (dependendo das versões).
Na secção [client] adiconar:
Algo como isto:
port = 3306
socket = "mysql.sock"
#### UTF8 ####
default-character-SET = utf8
Na secção [mysqld] adicionar:
character_set_server = utf8
collation_server = utf8_unicode_ci
skip-character-set-client-handshake
Algo como isto:
port = 3306
... ...
wait_timeout = 180
#### UTF8 ####
default-character-SET = utf8
character_set_server = utf8
collation_server = utf8_unicode_ci
skip-character-set-client-handshake
skip-locking
... ...
Deste modo todas as base de dados que criemos e todas que estejam definidas como por definição de sistema, ficarão em formato UTF-8.
Repetimos o exemplo anterior para testar esta configuração.
Conteúdo da tabela MySQL:

Resultado:

Agora como ambos sistemas comunicam com a mesma codificação de caracteres tudo saiu como deveria sair. Isto é, sem caracteres esquisitos.
Que acontece agora se inserimos algo na base de dados através do ficheiro PHP?
Consulta:
Resultado:

Como o tipo de comunicação é igual entre ambos os sistemas, não aconteceu nada de anormal. Os dados foram inseridos sem caracteres esquisitos.
Problema resolvido.
Mas… E se eu não tenho acesso ao ficheiro de configuração do servidor MySQL?
Para esta situação também existem soluções. Para isso, tens de dizer ao servidor MySQL que queres usar uma determinada codificação de caracteres durante a transferência de informação.
Sempre que se abra uma conexão nova com a base de dados MySQL deverás fazer a seguinte consulta:
Depois desta consulta podemos fazer quantas consultas queiramos que o servidor MySQL já sabe que estamos utilizando o protocolo referido.
Caso se feche a conexão e se abra outra nova, então devemos repetir a consulta acima referida.
Para quem tem uma versão de PHP superior à 5.2.3 (para mysqli superior à 5.0.5) e uma versão de MySQL superior à 5.0.6, pode usar outra solução através de uma função PHP.
mysql_set_charset
ou
mysqli_set_charset
O uso desta função é exactamente igual à solução anterior. Isto é, sempre que se abra uma conexão nova com a base de dados MySQL deverás executar esta função de PHP.
Depois desta função podemos fazer quantas consultas queiramos que o servidor MySQL já sabe que estamos utilizando o protocolo referido.
Caso se feche a conexão e se abra outra nova, então devemos repetir a função acima referida.
No entanto para evitar problemas de versões e de modo a que seja uma solução mais universal, recomendo a primeira solução apresentada (SET NAMES ‘utf8′;).
Exemplo para uma base de dados MySQL em “Latin 1″ e ficheiro PHP em UTF-8:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt" lang="pt">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Charset</title>
</head>
<body>
<?php
if($db = mysql_connect('127.0.0.1', 'root', '1234'))
{
mysql_select_db('demos');
$query = "SET NAMES 'utf8';";
mysql_query($query, $db);
$query = "SELECT * FROM demos;";
if($dadosDb = mysql_query($query, $db))
{
while ($obj = mysql_fetch_object($dadosDb))
{
echo '<div>' . $obj->name . ' - ' . $obj->value . ' - ' . $obj->obs . '';
}
mysql_free_result($dadosDb);
}
else { echo 'Erro na petição.'; };
echo '<div> </div>';
$query = "SELECT * FROM demos;";
if($dadosDb = mysql_query($query, $db))
{
while ($obj = mysql_fetch_object($dadosDb))
{
echo '<div>' . $obj->name . ' - ' . $obj->value . ' - ' . $obj->obs . '</div>';
}
mysql_free_result($dadosDb);
}
else { echo 'Erro na petição.'; };
}
else { echo 'Erro na conexão.'; };
mysql_close($db);
?>
</body>
</html>
Conteúdo da tabela MySQL:

Resultado:

Resultado sem caracteres esquisitos, porque estamos a dizer à base de dados que utilize uma codificação de caracteres de UTF-8 para se comunique com o nosso ficheiro PHP que também utiliza a o mesmo sistema de codificação de caracteres.
NOTA: Devemos reiniciar o servidor MySQL quando se modifique algumas das directivas do ficheiro de configuração (my.ini ou my.cnf).
Espero que estes 3 posts vos ajude a solucionar este tipo de problemas e a extinguir, de uma vez por todas, essas páginas web com caracteres esquisitos.