Estou configurando um novo servidor e quero dar suporte total ao UTF-8 no meu aplicativo da web. Eu tentei isso no passado em servidores existentes e sempre parece ter que voltar à ISO-8859-1.
Onde exatamente eu preciso definir a codificação / conjuntos de caracteres? Estou ciente de que preciso configurar o Apache, MySQL e PHP para fazer isso - há alguma lista de verificação padrão que posso seguir ou talvez solucionar problemas onde ocorrem incompatibilidades?
Isto é para um novo servidor Linux, executando o MySQL 5, PHP, 5 e Apache 2.
utf-8
para cada um deles seprately - MySQL 5, PHP 5 ou Apache 2.Respostas:
Armazenamento de dados :
Especifique o
utf8mb4
conjunto de caracteres em todas as tabelas e colunas de texto no seu banco de dados. Isso faz com que o MySQL armazene e recupere fisicamente valores codificados nativamente no UTF-8. Note que o MySQL implicitamente usaráutf8mb4
codificação se umutf8mb4_*
agrupamento for especificado (sem nenhum conjunto explícito de caracteres).Nas versões mais antigas do MySQL (<5.5.3), infelizmente você será forçado a usar simplesmente
utf8
, que suporta apenas um subconjunto de caracteres Unicode. Eu gostaria de estar brincando.Acesso a dados :
No código do seu aplicativo (por exemplo, PHP), seja qual for o método de acesso ao banco de dados usado, você precisará definir o conjunto de caracteres da conexão
utf8mb4
. Dessa forma, o MySQL não converte seu UTF-8 nativo quando entrega os dados ao seu aplicativo e vice-versa.Alguns drivers fornecem seu próprio mecanismo para configurar o conjunto de caracteres da conexão, que atualiza seu próprio estado interno e informa o MySQL da codificação a ser usada na conexão - essa é geralmente a abordagem preferida. Em PHP:
Se você estiver usando a camada de abstração PDO com PHP ≥ 5.3.6, poderá especificar
charset
no DSN :Se você estiver usando o mysqli , pode chamar
set_charset()
:Se você está preso com o mysql comum, mas está rodando o PHP ≥ 5.2.3, pode chamar
mysql_set_charset
.Se o motorista não fornece seu próprio mecanismo para definir o conjunto de caracteres de conexão, você pode ter que emitir uma consulta para contar MySQL como o aplicativo espera que os dados sobre a conexão a ser codificado:
SET NAMES 'utf8mb4'
.A mesma consideração em relação a
utf8mb4
/utf8
se aplica como acima.Saída :
Se o seu aplicativo transmitir texto para outros sistemas, eles também precisarão ser informados da codificação de caracteres. Com aplicativos da Web, o navegador deve ser informado sobre a codificação na qual os dados são enviados (por meio de cabeçalhos de resposta HTTP ou metadados HTML ).
No PHP, você pode usar a
default_charset
opção php.ini ou emitir manualmente oContent-Type
cabeçalho MIME, que é apenas mais trabalho, mas tem o mesmo efeito.Ao codificar a saída usando
json_encode()
, adicioneJSON_UNESCAPED_UNICODE
como um segundo parâmetro.Entrada :
Infelizmente, você deve verificar cada sequência de caracteres recebida como sendo UTF-8 válida antes de tentar armazená-la ou usá-la em qualquer lugar. O PHP
mb_check_encoding()
faz o truque, mas você deve usá-lo religiosamente. Não há realmente nenhuma maneira de contornar isso, pois os clientes mal-intencionados podem enviar dados da forma que quiserem, e não encontrei um truque para que o PHP faça isso por você de maneira confiável.Pela minha leitura da especificação atual do HTML , os seguintes sub-marcadores não são mais necessários nem válidos para o HTML moderno. Meu entendimento é que os navegadores irão trabalhar e enviar dados no conjunto de caracteres especificado para o documento. No entanto, se você estiver segmentando versões mais antigas de HTML (XHTML, HTML4 etc.), esses pontos ainda poderão ser úteis:
accept-charset
atributo para todas as suas<form>
tags:<form ... accept-charset="UTF-8">
.<form>
tag.Outras considerações de código :
Obviamente, todos os arquivos que você fornecerá (PHP, HTML, JavaScript etc.) devem ser codificados em UTF-8 válido.
Você precisa garantir que, toda vez que processar uma sequência UTF-8, faça isso com segurança. Infelizmente, essa é a parte mais difícil. Você provavelmente desejará fazer uso extensivo da
mbstring
extensão do PHP .As operações de string incorporadas do PHP não são, por padrão, UTF-8 seguras. Há algumas coisas que você pode fazer com segurança com operações normais de string PHP (como concatenação), mas para a maioria das coisas você deve usar a
mbstring
função equivalente .Para saber o que você está fazendo (leia-se: não estrague tudo), você realmente precisa conhecer o UTF-8 e como ele funciona no nível mais baixo possível. Confira qualquer um dos links de utf8.com para obter bons recursos para aprender tudo o que você precisa saber.
fonte
Gostaria de acrescentar uma coisa à excelente resposta de chazomaticus :
Não esqueça a tag META (assim, ou a versão HTML4 ou XHTML ):
Isso parece trivial, mas o IE7 me deu problemas com isso antes.
Eu estava fazendo tudo certo; o banco de dados, a conexão com o banco de dados e o cabeçalho HTTP do tipo de conteúdo foram definidos como UTF-8 e funcionaram bem em todos os outros navegadores, mas o Internet Explorer ainda insistia em usar a codificação "Europa Ocidental".
Acabou que a página estava faltando a tag META. Adicionando isso resolveu o problema.
Editar:
O W3C, na verdade, possui uma seção bastante grande dedicada à I18N . Eles têm vários artigos relacionados a esse problema - descrevendo o lado HTTP, (X) HTML e CSS:
Eles recomendam o uso do cabeçalho HTTP e da meta tag HTML (ou declaração XML no caso de XHTML serido como XML).
fonte
Além de definir
default_charset
no php.ini, você pode enviar o conjunto de caracteres correto usandoheader()
de dentro do seu código, antes de qualquer saída:Trabalhar com Unicode no PHP é fácil, desde que você perceba que a maioria das funções de string não funciona com Unicode e algumas podem alterar completamente as strings . O PHP considera "caracteres" com 1 byte de comprimento. Às vezes, isso é bom (por exemplo,
explode()
apenas procura uma sequência de bytes e a usa como um separador - portanto, não importa quais caracteres reais você procura). Mas outras vezes, quando a função é realmente projetada para funcionar com caracteres , o PHP não faz ideia de que seu texto possui caracteres de vários bytes encontrados no Unicode.Uma boa biblioteca para verificar é o phputf8 . Isso reescreve todas as funções "ruins" para que você possa trabalhar com segurança em seqüências de caracteres UTF8. Existem extensões como a extensão mbstring que tentam fazer isso por você também, mas prefiro usar a biblioteca porque é mais portátil (mas eu escrevo produtos de mercado de massa, então isso é importante para mim). Mas o phputf8 pode usar o mbstring nos bastidores, de qualquer maneira, para aumentar o desempenho.
fonte
Encontrei um problema com alguém usando o DOP e a resposta foi usá-lo para a cadeia de conexão do DOP:
O site do qual tirei esse site está fora do ar, mas consegui obtê-lo usando o cache do Google, por sorte.
fonte
$dbh->exec("set names utf8");
; prefiro o método apresentado aqui). Btw. também há uma observação semelhante a isso como um comentário no manual do PHP: php.net/manual/en/pdo.construct.php#96325 .No meu caso, eu estava usando
mb_split
, que usa regex. Portanto, eu também tive que me certificar manualmente de que a codificação regex era utf-8 fazendomb_regex_encoding('UTF-8');
Como uma observação lateral, também descobri ao executar
mb_internal_encoding()
que a codificação interna não era utf-8 e mudei isso executandomb_internal_encoding("UTF-8");
.fonte
Primeiro de tudo, se você estiver em <5.3PHP, então não. Você tem muitos problemas para resolver.
Estou surpreso que ninguém tenha mencionado a biblioteca intl , aquela que possui um bom suporte para unicode , grafemas , operações com strings , localização e muito mais, veja abaixo.
Vou citar algumas informações sobre o suporte a Unicode no PHP pelos slides de Elizabeth Smith no PHPBenelux'14
INTL
Boa:
Ruim:
mb_string
ICONV
stream_filter_append($fp, 'convert.iconv.ISO-2022-JP/EUC-JP')
BASES DE DADOS
Algumas outras pegadinhas
Eu atualizarei esta resposta caso as coisas mudem os recursos adicionados e assim por diante.
fonte
--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd
opções.A única coisa que eu acrescentaria a essas respostas surpreendentes é enfatizar o salvamento de seus arquivos na codificação utf8; notei que os navegadores aceitam essa propriedade ao definir utf8 como codificação do código. Qualquer editor de texto decente mostrará isso, por exemplo, o Notepad ++ possui uma opção de menu para conversão de arquivos, mostra a codificação atual e permite que você altere. Para todos os meus arquivos php eu uso utf8 sem BOM.
Algum tempo atrás, alguém me pediu para adicionar suporte utf8 a um aplicativo php / mysql projetado por outra pessoa; notei que todos os arquivos foram codificados em ANSI; portanto, tive que usar o ICONV para converter todos os arquivos, alterar as tabelas do banco de dados para usar o utf8 charset e utf8_general_ci collate, adicione 'SET NAMES utf8' à camada de abstração do banco de dados após a conexão (se estiver usando 5.3.6 ou anterior, caso contrário, será necessário usar charset = utf8 na cadeia de conexão) e altere as funções da cadeia de caracteres para usar o multibyte php funções de string equivalentes.
fonte
Descobri recentemente que o uso
strtolower()
pode causar problemas em que os dados são truncados após um caractere especial.A solução foi usar
fonte
Acabei de passar pelo mesmo problema e encontrei uma boa solução nos manuais do PHP.
Alterei toda a codificação de meu arquivo para UTF8 e depois a codificação padrão na minha conexão. Isso resolveu todos os problemas.
Exibir fonte
fonte
set_charset('utf8mb4')
não funcionou, mas>set_charset("utf8")
funcionou e isso não foi mostrado nas outras respostas.set_charset("utf8")
pode funcionar, mas vai se comportar de forma diferente (ver as observações sobre a diferença entreutf8
eutf8mb4
e a história versão mysql). Useutf8
se você precisar e SOMENTE se você souber o que está fazendo !No PHP, você precisará usar as funções multibyte ou ativar mbstring.func_overload . Dessa forma, coisas como strlen funcionarão se você tiver caracteres com mais de um byte.
Você também precisará identificar o conjunto de caracteres de suas respostas. Você pode usar AddDefaultCharset, como acima, ou escrever código PHP que retorna o cabeçalho. (Ou você pode adicionar uma tag META aos seus documentos HTML.)
fonte
O suporte a Unicode no PHP ainda é uma grande bagunça. Embora seja capaz de converter uma string ISO8859 (usada internamente) em utf8, ela não tem a capacidade de trabalhar com strings unicode nativamente, o que significa que todas as funções de processamento de strings irão modificar e danificar suas strings. Portanto, você deve usar uma biblioteca separada para obter um suporte adequado ao utf8 ou reescrever todas as funções de manipulação de string.
A parte mais fácil é apenas especificar o conjunto de caracteres nos cabeçalhos HTTP e no banco de dados e tal, mas nada disso importa se o seu código PHP não gerar UTF8 válido. Essa é a parte mais difícil, e o PHP praticamente não ajuda lá. (Eu acho que o PHP6 deve corrigir o pior disso, mas ainda há um tempo)
fonte
Se você deseja que o servidor MySQL decida o conjunto de caracteres, e não o PHP como cliente (comportamento antigo; de preferência, na minha opinião), tente adicionar
skip-character-set-client-handshake
ao seumy.cnf
, sob[mysqld]
e reiniciemysql
.Isso pode causar problemas caso você esteja usando algo diferente de UTF8.
fonte
A resposta superior é excelente. Aqui está o que eu precisei em uma instalação regular do debian / php / mysql:
isso foi tudo !
fonte
se você quer uma solução mysql, tive problemas semelhantes com 2 dos meus projetos, após uma migração do servidor. Depois de pesquisar e tentar muitas soluções, me deparei com este / nada antes deste funcionar):
Depois de adicionar esta linha ao meu arquivo de configuração, tudo funciona bem!
Encontrei esta solução https://www.w3schools.com/PHP/func_mysqli_set_charset.asp quando estava procurando resolver uma inserção da consulta html
boa sorte!
fonte
Apenas uma nota:
Você está enfrentando o problema de seus caracteres não-latinos está mostrando como
?????????
, você fez uma pergunta, e ele ficou fechado com uma referência a esta questão canônica, você tentou de tudo e não importa o que você faz você ainda receber??????????
a partirMySQL
.Isso ocorre principalmente porque você está testando seus dados antigos, que foram inseridos no banco de dados usando o conjunto de caracteres errado e foram convertidos e armazenados para realmente os caracteres do ponto de interrogação
?
. O que significa que você perdeu o texto original para sempre e, independentemente do que tentar, receberá???????
.A aplicação do que você aprendeu das respostas desta pergunta em novos dados pode resolver seu problema.
fonte
Eu tive esse problema ao exibir tabelas. Eu apenas coloquei isso em cada variável de saída de eco:
fonte