Eu tenho um aplicativo que lida com clientes de todo o mundo e, naturalmente, quero que tudo que entra nos meus bancos de dados seja codificado em UTF-8.
O principal problema para mim é que não sei qual será a codificação da fonte de qualquer sequência - pode ser de uma caixa de texto (usar <form accept-charset="utf-8">
é útil apenas se o usuário realmente enviar o formulário) ou pode ser de um arquivo de texto carregado, então eu realmente não tenho controle sobre a entrada.
O que eu preciso é de uma função ou classe que garanta que o material que entra no meu banco de dados seja, na medida do possível, codificado em UTF-8. Eu tentei, iconv(mb_detect_encoding($text), "UTF-8", $text);
mas isso tem problemas (se a entrada for 'noiva', ela retorna 'noiva'). Eu tentei muitas coisas = /
Para uploads de arquivos, gosto da ideia de pedir ao usuário final que especifique a codificação que eles usam e mostro-lhes visualizações de como será a saída, mas isso não ajuda contra hackers desagradáveis (na verdade, poderia dar vida a eles). um pouco mais fácil).
Eu li as outras perguntas do SO sobre o assunto, mas todas parecem ter diferenças sutis como "Preciso analisar feeds RSS" ou "Raspe dados de sites" (ou, na verdade, "Você não pode").
Mas deve haver algo que pelo menos tenha uma boa tentativa !
fonte
UTF-8//IGNORE
como o 2º paramiconv
?Respostas:
O que você está pedindo é extremamente difícil. Se possível, conseguir que o usuário especifique a codificação é o melhor. Prevenir um ataque não deve ser muito mais fácil ou mais difícil dessa maneira.
No entanto, você pode tentar fazer isso:
Configurá-lo para estrito pode ajudar a obter um resultado melhor.
fonte
mb_detect_encoding
código fonte em sua distribuição php (em algum lugar aqui: ext / mbstring / libmbfl / mbfl / mbfl_ident.c). Esta função não funciona corretamente. Para algumas codificações, ele ainda tem "return true", lol. Outros estão nas funções Ctrl + c Ctrl + v. Isso ocorre porque você não pode detectar a codificação sem algum tipo de dicionário ou abordagem estatística (como a minha).mb_detect_encoding
Pelo que entendi, percorre a lista de codificações fornecidas e aceita a primeira que não possui sequências de bytes inválidas na string ... Para codificações que não possuem sequências de bytes inválidas, como ISO-8859-1, é sempre verdade . Nenhuma heurística "inteligente" e os resultados variam muito com a lista (e a ordem) das codificações que você passa.mb_detect_order()
mesmo que é o valor padrão para este parâmetro, porque ele queria para definir a detecção de codificação rigorosa para true (o 3º param) :)Na Rússia, pátria, temos quatro codificações populares, então sua pergunta é muito procurada aqui.
Somente pelos códigos de caracteres dos símbolos você não pode detectar a codificação, porque as páginas de código se cruzam. Algumas páginas de código em diferentes idiomas têm até uma interseção completa. Então, precisamos de outra abordagem .
A única maneira de trabalhar com codificações desconhecidas é trabalhar com probabilidades. Portanto, não queremos responder à pergunta "o que é codificação deste texto?", Estamos tentando entender "o que é a codificação mais provável desse texto? ".
Um cara aqui no popular blog de tecnologia russo inventou essa abordagem:
Crie o intervalo de probabilidade dos códigos de caracteres em todas as codificações que você deseja suportar. Você pode construí-lo usando alguns textos grandes no seu idioma (por exemplo, ficção, use Shakespeare para inglês e Tolstoi para russo, lol). Você ficará smth assim:
Próximo. Você pega o texto em codificação desconhecida e, para cada codificação no seu "dicionário de probabilidades", procura a frequência de cada símbolo no texto codificado em desconhecida. Soma probabilidades de símbolos. A codificação com uma classificação maior provavelmente é a vencedora. Melhores resultados para textos maiores.
Se você estiver interessado , posso ajudá-lo com prazer nessa tarefa. Podemos aumentar bastante a precisão criando uma lista de probabilidades de dois códigos.
Btw. mb_detect_encoding certanly não funciona. Sim mesmo. Por favor, dê uma olhada no código fonte mb_detect_encoding em "ext / mbstring / libmbfl / mbfl / mbfl_ident.c".
fonte
Você provavelmente já tentou isso, mas por que não usar apenas a função mb_convert_encoding? Ele tentará detectar automaticamente o conjunto de caracteres do texto fornecido ou você pode passar uma lista para ele.
Além disso, tentei executar:
e os resultados são os mesmos para ambos. Como você vê que seu texto está truncado para 'noivo'? está no banco de dados ou em um navegador?
fonte
iconv
. Eu tentei fazer um mb_ * quase puro. O que você acha?Não há como identificar o conjunto de caracteres de uma sequência que é completamente precisa. Existem maneiras de tentar adivinhar o conjunto de caracteres. Uma dessas maneiras, e provavelmente / atualmente a melhor em PHP, é mb_detect_encoding (). Isso examinará sua string e procurará ocorrências de itens exclusivos de determinados conjuntos de caracteres. Dependendo da sua sequência, pode não haver tais ocorrências distinguíveis.
Pegue o conjunto de caracteres ISO-8859-1 x ISO-8859-15 ( http://en.wikipedia.org/wiki/ISO/IEC_8859-15#Changes_from_ISO-8859-1 )
Existem apenas alguns caracteres diferentes e, para piorar, eles são representados pelos mesmos bytes. Não há como detectar, receber uma sequência sem saber a codificação, se o byte 0xA4 deve significar ¤ ou € na sua sequência, portanto não há como saber se é o conjunto de caracteres exato.
(Nota: você pode adicionar um fator humano, ou uma técnica de varredura ainda mais avançada (por exemplo, o que Oroboros102 sugere), para tentar descobrir com base no contexto circundante, se o personagem deve ser ¤ ou €, embora isso pareça uma ponte muito longe)
Existem diferenças mais distintas entre, por exemplo, UTF-8 e ISO-8859-1, por isso ainda vale a pena tentar descobrir quando não tiver certeza, embora você possa e nunca deva confiar que isso esteja correto.
Leitura interessante: http://kore-nordmann.de/blog/php_charset_encoding_FAQ.html#how-do-i-determine-the-charset-encoding-of-a-string
Existem outras maneiras de garantir o conjunto de caracteres correto. Em relação aos formulários, tente aplicar o máximo possível o UTF-8 (confira o boneco de neve para garantir que seu envio seja UTF-8 em todos os navegadores: http://intertwingly.net/blog/2010/07/29/Rails-and -Bonecos de neve ) Ao fazer isso, pelo menos você pode ter certeza de que todo texto enviado através de seus formulários é utf_8. Em relação aos arquivos enviados, tente executar o comando unix 'file -i' nele, por exemplo, exec () (se possível no seu servidor) para ajudar na detecção (usando a lista técnica do documento). Em relação à raspagem de dados, você pode ler os cabeçalhos HTTP, que geralmente especificam o conjunto de caracteres. Ao analisar arquivos XML, verifique se os metadados XML contêm uma definição de conjunto de caracteres.
Em vez de tentar adivinhar automaticamente o conjunto de caracteres, você deve primeiro tentar garantir um determinado conjunto de caracteres sempre que possível, ou tentar obter uma definição da fonte de origem (se aplicável) antes de recorrer à detecção.
fonte
Existem algumas boas respostas e tentativas de responder sua pergunta aqui. Não sou um mestre de codificação, mas entendo seu desejo de ter uma pilha UTF-8 pura até o banco de dados. Eu tenho usado a
utf8mb4
codificação do MySQL para tabelas, campos e conexões.Minha situação se resumia a "Eu só quero que meus desinfetantes, validadores, lógica de negócios e instruções preparadas lidem com o UTF-8 quando os dados vierem de formulários HTML ou links de registro de email". Então, da minha maneira simples, comecei com esta ideia:
$encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];
throw new RuntimeException
UTF-8
, continue.Senão, se é
ISO-8859-1
ouASCII
uma. Tentativa de conversão para UTF-8 (espera, não concluída)
b. Detectar a codificação do valor convertido
c. Se a codificação relatada e o valor convertido forem ambos
UTF-8
, continue.d. Outro,
throw new RuntimeException
Da minha aula abstrata
Sanitizer
Alguém poderia argumentar que eu deveria separar as preocupações de codificação da minha
Sanitizer
classe abstrata e simplesmente injetar umEncoder
objeto em uma instância filha concreta deSanitizer
. No entanto, o principal problema com a minha abordagem é que, sem mais conhecimento, simplesmente rejeito os tipos de codificação que não quero (e confio nas funções do PHP mb_ *). Sem um estudo mais aprofundado, não sei se isso machuca algumas populações ou não (ou se estou perdendo informações importantes). Então, eu preciso aprender mais. Encontrei este artigo.O que todo programador precisa absolutamente e positivamente sobre codificações e conjuntos de caracteres para trabalhar com texto
Além disso, o que acontece quando dados criptografados são adicionados aos meus links de registro de e-mail (usando
OpenSSL
oumcrypt
)? Isso poderia interferir na decodificação? E o Windows-1252? E as implicações de segurança? O uso deutf8_decode()
eutf8_encode()
emSanitizer::isUTF8
é duvidoso.As pessoas apontaram falhas nas funções do PHP mb_ *. Nunca levei tempo para investigar
iconv
, mas se funcionar melhor que as funções mb_ *, informe-me.fonte
Eu não acho que seja um problema. Um aplicativo conhece a fonte da entrada. Se for de um formulário, use a codificação UTF-8 no seu caso. Isso funciona. Basta verificar se os dados fornecidos estão codificados corretamente (validação). Lembre-se de que nem todos os bancos de dados oferecem suporte ao UTF-8 em toda a sua extensão.
Se for um arquivo, você não o salvará codificado em UTF-8 no banco de dados, mas em formato binário. Quando você produzir o arquivo novamente, use a saída binária também, então isso é totalmente transparente.
Sua idéia é boa de que um usuário possa dizer a codificação, seja ele mesmo assim após o download do arquivo, pois é binário.
Portanto, devo admitir que não vejo um problema específico que você levanta com sua pergunta. Mas talvez você possa adicionar mais alguns detalhes sobre qual é o seu problema.
fonte
Você pode configurar um conjunto de métricas para tentar adivinhar qual codificação está sendo usada. Novamente, não é perfeito, mas pode pegar algumas das falhas de mb_detect_encoding ().
fonte
mb_detect_encoding()
erros, você acha que minha resposta tem uma chance de bola de neve no verão no Saara?Se você estiver disposto a "levar isso para o console", eu recomendo
enca
. Diferente do bastante simplistamb_detect_encoding
, ele usa "uma mistura de análise, análise estatística, adivinhação e magia negra para determinar suas codificações" (lol - veja a página de manual ). No entanto, você geralmente precisa passar o idioma do arquivo de entrada se quiser detectar essas codificações específicas do país. (No entanto,mb_detect_encoding
possui essencialmente o mesmo requisito, pois a codificação teria que aparecer "no lugar certo" na lista de codificações passadas para que seja detectável.)enca
também veio aqui: Como encontrar a codificação de um arquivo no Unix via script (s)fonte
Parece que sua pergunta foi bastante respondida, mas eu tenho uma abordagem que pode simplificar seu caso:
Eu tive um problema semelhante ao tentar retornar dados de string do mysql, até mesmo configurando o banco de dados e o php para retornar as strings formatadas em utf-8. A única maneira de obter o erro era realmente devolvê-los do banco de dados.
Finalmente, navegando pela web, encontrei uma maneira muito fácil de lidar com isso:
Dando que você pode salvar todos esses tipos de dados de string no mysql em diferentes formatos e agrupamentos, o que você só precisa fazer é, diretamente no seu arquivo de conexão php, definir o agrupamento para utf-8, assim:
O que significa que primeiro você salva os dados em qualquer formato ou agrupamento e os converte apenas no retorno ao seu arquivo php.
Espero que tenha sido útil!
fonte
Se o texto for recuperado de um banco de dados mysql, você pode tentar adicioná-lo após a conexão BD.
mysqli_set_charset ($ con, "utf8");
https://www.php.net/manual/en/mysqli.set-charset.php
fonte
Opções padrão de cURL:
Eu tentei algo assim. Isso me ajudou. Se encontrado nas informações de meta charset, estou convertendo, caso contrário, não faço nada.
fonte