Qual character encoding usar em sites só para brasileiros?

Olá

Um assunto para discussão: em sites só para brasileiros devemos usar ISO-8859-1 ou partimos logo para UTF-8. Abaixo coloco uma série de considerações cuja maior parte vale para ambos os encodings apesar de que está feito para o UTF-8.

Resumo dos passos para usar encoding UTF-8 em sites servidos pelo Tomcat:

  1. Todas as páginas html devem começar por:<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  2. Os forms devem ser assim:<form action=". . ." accept-charset="iso-8859-1,utf-8">

  3. Os arquivos css devem começar por@charset "utf-8"

  4. Os arquivos xml devem começar por:<?xml version="1.0" encoding="UTF-8" ?>

  5. Os arquivos JSP devem conter:<%@ page contentType="text/html; charset=UTF-8" %>

  6. Os scripts Catalina.bat (Windows) e catalina.sh (Unix) precisam do seguinte parâmetro (não documentado) para chamar o Java:-Dfile.encoding=UTF-8

  7. No server.xml é preciso alterar o atributo URIEncoding do conector Coyote HTTP/1.1 cujo default é ISO-8859-1 para UTF-8.

  8. É preciso muita atenção com o método HttpServletRequest.setCharacterEncoding(“utf-8”); que só se aplica ao body e NÃO à URI. E este método PRECISA ser chamado ANTES de pegar os parâmetros e por isso não funciona quando há um filtro que chama antes request.getParameter()

  9. Considerar a seguinte importante diferença que há entre Tomcat 4 e Tomcat 5: O conector Coyote HTTP/1.1 tem um atributo useBodyEncodingForURI que setado para true usará o encoding do “request body” para decodificar os parametros que vem na URI

  • O default é true para TC4 (desacordo com a espec. porém mantém consistência com versões antigas)
  • O default é false para TC5 (cumpre a espec. mas pode exigir alterações em aplicações antigas)
  1. E adicionalmente se pode usar um método mais ou menos como o abaixo para traduzir o que possa vir como iso-8859-1 para UTF-8[code]/**
  • Converte o formato ISO8859-1 (default IE) para UTF-8
    */
    public String toUTF8(String isoString) {
    String utf8String = null;
    if (null != isoString && !isoString.equals(""))
    {
    try
    {
    byte[] stringBytesISO = isoString.getBytes("ISO-8859-1");
    utf8String = new String(stringBytesISO, "UTF-8");
    }
    catch(UnsupportedEncodingException e)
    {
    // Mostra exceção mas devolve a mesma String
    System.out.println("UnsupportedEncodingException: " + e.getMessage());
    utf8String = isoString;
    }
    }
    else
    {
    utf8String = isoString;
    }
    return utf8String;
    }[/code]

Se alguém discorda do resumo acima ou precisa acrescentar algum passo por favor se manifeste. Comentários e correções serão bem-vindos.

Depois de fixado o encoding temos um problema adicional: as senhas criptografadas na base de dados antes da mudança do encoding.

Perguntas:

  1. Qual encoding usar?

  2. Considerando uma base de dados sem nacionalizar o conjunto de caracteres (National Character Set default), quais problemas podem acontecer ao tentar modificar uma senha criptografada armazenada na base de dados antes das mudanças no encoding?

[]s
Luca

Muito bom. Alguns pontos eu nao sabia, e os outros acabei aprendendo na marra, quando alguns russos e chineses comecaram a reportar fatos que o jforum estava dando altos paus com caracteres cirilicos ( ainda da alguns hehehe ).

Em relacao ao banco de dados, ainda haveria o problema do db nao suportar o encoding, nao?!.. ( e uma eventual “migracao” de caracteres seria uma opcao? )

Rafael

Sticky’d. Muito bom esse post, Luca! Parabens :smiley:

Quanto as suas duvidas, o melhor encoding para os casos em que vc nao sabe bem ao certo qual eh o caso eh UTF-8, por ser 100% compativel com o codigo ASCII, e ser o mais usado em aplicacoes internacionalizadas por suportar todo o character set Unicode (coisa que, se nao me engano, encodings como ISO-8859-1 sambam um pouco).

Eu nao sei se faz muito sentido guardar senhas num banco de dados sem passar por um md5 antes, e como o md5 geralmente eh feito no lado Java da coisa, eh facil manter o encoding uniforme. Para os outros dados que podem vir com o encoding errado, eh soh especificar qual o encoding que voce quer para o driver JDBC, caso ele suporte isso, ou fazer uma migracaozinha (que, em alguns casos, como o do PostgreSQL, requer dropar a base de dados, recriar com o encoding certo e importar os dados novamente).

Em relacao ao usar md5 tudo bem, mas a representacao interna de um utf-8 nao eh diferente da representacao de um iso? digo, o codigo md5 gerado nao seria diferente? ( no caso de ja ter coisas onde foi gerado o md5 usando iso, e depois passa a ser usado caractered utf )

Rafael

Tem ainda o

response.setContentType("text/html; charset=utf-8");

Rafael

Vale algumas outras notas importantes:

-Os fontes java da aplicação devem ser desenvolvidos usando o dado encoding e o compilador informado desse encoding.

-No caso de uso de JSP’s e tomcat5 precisa mexer no build.xml dele para passar o encoding dos fontes, com o 4 não sei exatamente qual o parametro.

-Sempre que usar Reader/Writers, obter primeiro um In(out)putStream e converter para um reader fornecendo o devido encoding, dessa forma fica mais portavel que usando -Dfile.encondig…

Olá

Rafael, obrigado pelo acréscimo.

CV, na verdade meu problema com senha criptografada foi o que originou meu estudo de encoding. Tudo começou com uma aplicação que rodava no Linux e criptografava a senha usando a biblioteca BouncyCastle. Esta mesma aplicação rodando no Windows encripta a senha para algo diferente do que foi armazenado pelo Linux no Oracle.

Louds, o parametro na linha de comando -Dfile.encoding=UTF-8 serve justamente para os JSPs. O parametro do web.xml javaEncoding (Java file encoding to use for generating java source files) já tem UTF-8 como default. Este mesmo parametro já existia no tomcat 4.1 também com default UTF-8.

Quanto as suas dicas sobre os Reader/Writers se entendi bem com Java 1.4 para obter um Reader devemos obter primeiro um InputStreamReader e passar um java.nio.charset.Charset
no construtor. Algo como está abaixo usando o construtor InputStreamReader(InputStream in, Charset cs):BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "utf-8") );
É isso?

[]s
Luca

[quote=“Luca”]Olá

Quanto as suas dicas sobre os Reader/Writers se entendi bem com Java 1.4 para obter um Reader devemos obter primeiro um InputStreamReader e passar um java.nio.charset.Charset
no construtor. Algo como está abaixo usando o construtor InputStreamReader(InputStream in, Charset cs):BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "utf-8") );
É isso?

[]s
Luca[/quote]

Sim.

Luca, o javac le os arquvos no encoding nativo, então vc tem que passar na linha de comando -encoding=utf-8 para funcionar corretamente, eu tenho um ambiente quase com a mesma configuração sugerida por voce, mas não tenho como usar o -Dfile.encoding porque o mesmo servidor tem aplicações feitas com encodings diferentes (e algumas que foram feitas por pessoas que não entendem encodings).

luca

quando voce criptografar algo, nao mande o array de bytes para o construtor da string, isso da uma dor de cabeca por causa do char encoding.

o que eh legal fazer eh gerar, atraves desses bytes, uma sequencia hexadecimal. ai nao tem erro!

Que thread linda, pena que tá em português!!

Eu pensei que o javac gerava as strings internas sempre em UTF-8…

Aqui dá bastante problema com o CVS, a gente comita, e quando volta vem zuado…

[]s

Olá

Duke

Abaixo o cvswrappers que uso:[code]

This file affects handling of files based on their names.

The -m option specifies whether CVS attempts to merge files.

The -k option specifies keyword expansion (e.g. -kb for binary).

Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)

wildcard [option value][option value]…

where option is one of

-m update methodology value: MERGE or COPY

-k expansion mode value: b, o, kkv, &c

and value is a single-quote delimited value.

For example:

#*.gif -k ‘b’
*.CLASS -k ‘b’ -m ‘COPY’
*.DOC -k ‘b’ -m ‘COPY’
*.EAR -k ‘b’ -m ‘COPY’
*.GIF -k ‘b’ -m ‘COPY’
*.JPG -k ‘b’ -m ‘COPY’
*.PDF -k ‘b’ -m ‘COPY’
*.TAR -k ‘b’ -m ‘COPY’
*.WAR -k ‘b’ -m ‘COPY’
*.ZIP -k ‘b’ -m ‘COPY’
*.avi -k ‘b’ -m ‘COPY’
*.bin -k ‘b’ -m ‘COPY’
*.bz -k ‘b’ -m ‘COPY’
*.bz2 -k ‘b’ -m ‘COPY’
*.class -k ‘b’ -m ‘COPY’
*.doc -k ‘b’ -m ‘COPY’
*.ear -k ‘b’ -m ‘COPY’
*.exe -k ‘b’ -m ‘COPY’
*.gif -k ‘b’ -m ‘COPY’
*.gz -k ‘b’ -m ‘COPY’
*.hqx -k ‘b’ -m ‘COPY’
*.jar -k ‘b’ -m ‘COPY’
*.jpeg -k ‘b’ -m ‘COPY’
*.jpg -k ‘b’ -m ‘COPY’
*.mov -k ‘b’ -m ‘COPY’
*.mp3 -k ‘b’ -m ‘COPY’
*.mpg -k ‘b’ -m ‘COPY’[/code]

Caso use Linux no servidor do cvs pode ajeitar o encoding em um arquivo que no caso do fedora fica em /etc/sysconfig/i18n. Outras distribuições tem coisa semelhante.

[]s
Luca

mais uma questão sobre encoding e Web: XMLHttpRequest. eu pelo menos estou tendo uma dor de cabeça imensa ao usar essa classe pra postar dados. mesmo colocando o encoding pra iso-8859-1 (no meu caso está tudo em iso-8859-1) qdo envio algo via POST sempre vai como utf-8. eu não sei onde está definido isso, mas não adianta mandar como iso-8859-1 (estou tendo q usar um remendo na hora de receber os dados do POST e converter tudo pra iso-8859-1).

minhas tentativas vãs sao era mais ou menos assim:

xmlhttp.open("POST",url,true);
xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=iso-8859-1');
xmlhttp.send(data);

PS1 se alguem souber como arrumar, diga. senão fica dado o recado.

PS2 se vc nao sabe o q eh XMLHttpRequest, eh uma classe JavaScript que permite enviar ou receber dados (embora o nome, nao necessariamente XML). no IE chama-se Msxml2.XMLHTTP

[quote=louds]Vale algumas outras notas importantes:

-Os fontes java da aplicação devem ser desenvolvidos usando o dado encoding e o compilador informado desse encoding.

-No caso de uso de JSP’s e tomcat5 precisa mexer no build.xml dele para passar o encoding dos fontes, com o 4 não sei exatamente qual o parametro.

-Sempre que usar Reader/Writers, obter primeiro um In(out)putStream e converter para um reader fornecendo o devido encoding, dessa forma fica mais portavel que usando -Dfile.encondig…[/quote]

Consegui resolver esse problema criando um filtro no web.xml

Para quem já tentou as opções acima, tem essa que resolveu meu problema (que tive usando Struts2 onde, no Struts1.3.8 eu não tinha esse problema)

colocar no struts.properties: [color=blue]struts.i18n.encoding=ISO-8859-1[/color]

abs

Em meu projeto web, o formulário envia dados para o banco e recebe com caracteres assim: á para os acentos á e ã para os acentos ã.

Já tentei utilizar accept-charset=“iso-8859-1,utf-8” nos inputs mas também não deu certo.
Mudei a codificação do banco de latin1 para utf8 mas deu na mesma.

Bom, criei um novo projeto contendo apenas a página com o formulário com método de envio get.
E também acontece o mesmo com esse projeto.

Uma imagem de um fato que me faz pensar isso:

O código é simples:

[code]<%@page contentType=“text/html” pageEncoding=“UTF-8”%>

JSP Page <% String title = request.getParameter("title"); String msg = request.getParameter("msg"); %>

Título: <%=title%> e mensagem: <%=msg%>

 <form name="form1" action="" method="get">
<input type="text" name="title" size="30" maxlength="30">
       <br>
<input type="text" name="msg" size="60" maxlength="100">
        <br>
    <input type="submit" value="Salvar">    
  </form> 
</body>
[/code]

Não entendi o porquê dos caracteres estarem assim e na barra de
endereços ficar normal.

Bom, deixo a dúvida com quem puder me ajudar.

Obrigado.
[]s

Resolvi este problema.
Bastava mesmo codificar em modo iso.

Até enviei para o banco de dados depois.

Mas no primeiro projeto que eu tinha, um com
template e tudo, não vai em modo brasileiro de jeito nenhum.

Será que é oss?

*Já codifiquei o css em utf-8 e iso-8859-1 mas não adiantou.

Para complementar as informações sobre encoding.

O atributo accept-charset do form não funciona no Internet Explorer.

http://www.w3schools.com/TAGS/att_form_accept_charset.asp

[quote=dark123]Bom, criei um novo projeto contendo apenas a página com o formulário com método de envio get.
E também acontece o mesmo com esse projeto.

Uma imagem de um fato que me faz pensar isso:

O código é simples:

[code]<%@page contentType=“text/html” pageEncoding=“UTF-8”%>

JSP Page <% String title = request.getParameter("title"); String msg = request.getParameter("msg"); %>

Título: <%=title%> e mensagem: <%=msg%>

 <form name="form1" action="" method="get">
<input type="text" name="title" size="30" maxlength="30">
       <br>
<input type="text" name="msg" size="60" maxlength="100">
        <br>
    <input type="submit" value="Salvar">    
  </form> 
</body>
[/code]

Não entendi o porquê dos caracteres estarem assim e na barra de
endereços ficar normal.

Bom, deixo a dúvida com quem puder me ajudar.

Obrigado.
[]s[/quote]

Só o metodo POST aceita a codificação UTF-8 que vc colocou na sua pagina… se você tentar enviar pelo GET vai ficar tudo quadrado!
abraços

Para complementar esse post: Eclipse + Tomcat

Quem costuma startar o tomcat pelo botão do eclipse pode se ferrar geral se a configuração do encoding do workspace não estiver com UTF-8.

Eu penei pra tentar entender por que que quando dava o startup do tomcat manualmente (fora do eclipse) o encoding funcionava, mas quando
dava o startup pelo eclipse o encoding era uma loucura.

Bom, basta no eclipse ir em window>preferences>General>Workspace>TextFileEncoding>UTF-8

Valeu!