PHP: Convertir une chaîne en UTF-8 sans connaître l'original jeu de caractères, ou au moins essayer
J'ai une application qui traite avec des clients de partout dans le monde, et, naturellement, je veux tout ce qui se passe dans mes bases de données pour être codé en UTF-8.
Le principal problème pour moi est que je ne sais pas ce que le codage de la source de n'importe quelle chaîne va être - c'est peut-être à partir d'une zone de texte (à l'aide de <form accept-charset="utf-8">
n'est utile que si l'utilisateur est soumis le formulaire), ou il pourrait être téléchargés à partir d'un fichier texte, donc je n'ai pas vraiment de contrôle sur l'entrée.
Ce dont j'ai besoin est une fonction ou une classe qui fait en sorte que les choses qui se passent dans ma base de données est, dans la mesure du possible, codé en UTF-8. J'ai essayé iconv(mb_detect_encoding($text), "UTF-8", $text);
mais qui a des problèmes (si l'entrée est 'fiancée' il renvoie 'fiancé'). J'en ai essayé beaucoup de choses =/
Pour les uploads de fichier, j'aime l'idée de demander à l'utilisateur de préciser l'encodage qu'ils utilisent, et de leur montrer les aperçus de ce que la sortie va ressembler, mais ce n'aide pas contre les méchants pirates (en fait, on pourrait leur rendre la vie un peu plus facile).
J'ai lu les autres questions sur le sujet, mais ils semblent tous avoir des différences subtiles comme "j'ai besoin d'analyser les flux RSS" ou "je gratter les données de sites web" (ou, en fait, "on ne peut pas").
Mais il doit y avoir quelque chose qui au moins a une bonne essayer!
- En gros, c'est pas possible, par définition, pour obtenir tout à fait correcte, en réalité, le taux de réussite de deviner un inconnu l'encodage n'est pas terrible. Il est possible d'utiliser la méthode heuristique, mais il sera correct à moins de 100% du temps, en fonction du matériau de loin inférieur à 100%. Vous devez être conscient de cela. Peut-être que quelqu'un ici peut au moins suggérer une bibliothèque avec de bonnes heuristiques, cependant.
- Bien sûr, je sais il n'y a pas de solution parfaite, d'où le désir de quelque chose qui aura au moins un de bien aller.
- cela peut vous aider: stackoverflow.com/q/505562/642173
- Avez-vous essayé d'utiliser
UTF-8//IGNORE
que le 2ème param dansiconv
? - Ouais, c'est ce que j'ai fait. Il n'est pas parfait, évidemment, que puis "fiancée" devient "fiancé", mais c'est certainement mieux. Comment se fait-TRANSLIT ne fonctionne pas?
- N'est-il pas plus facile de DEMANDER les clients de la langue source (aka localisation)? Vous permet d'économiser des maux de tête dans le long terme.
- Bien sûr, une partie du problème est que les non-anglais des mots des cultures dans le texte anglais assez fréquemment (par exemple 'fiancée'), et le même problème se produit avec d'autres langues aussi - je me souviens quand j'étais à l'école, il y avait un mouvement en France pour purger des phrases comme "le week-end'.
- double possible de Détecter l'encodage et de faire tout en UTF-8
- J'ai fait une contribution visant à celles qui tentent de résoudre ce principalement avec
mb_*
fonctions. Il est une sorte de sauvage, mais bon, pourquoi pas? 🙂 Si il y avait un moyen de se débarrasser deutf8_decode
etutf8_encode
, il pourrait être mieux. Peut-êtreiconv
??? - J'ai trouvé ce stackoverflow.com/a/3521396/1429677 une excellente réponse à cette question, ici, est la lib github.com/neitanod/forceutf8
- mon commentaire à compter de 2019, de valider et d'accepter l'entrée d'une codé en utf-8 page dans utf8mb4 db comme il est avec des déclarations préparées à l'avance et de prendre vos précautions lors de l'impression à l'écran. ce sera en sécurité et toujours lisible sans avoir besoin de ce qui est demandé.
Vous devez vous connecter pour publier un commentaire.
Ce que vous me demandez est extrêmement difficile. Si possible, arriver à l'utilisateur de spécifier l'encodage est le meilleur. La prévention d'une attaque ne devrait pas être beaucoup plus facile ou plus difficile de cette façon.
Cependant, vous pourriez essayer de faire ceci:
Le paramètre stricte pourrait vous aider à obtenir un meilleur résultat.
mb_detect_encoding
code source dans votre php distro (quelque part ici: ext/mbstring/libmbfl/mbfl/mbfl_ident.c). Cette fonction ne fonctionne pas correctement à tous. Pour certains encodages il a même "return true", lol. D'autres sont dans le Ctrl+c Ctrl+v fonctions. C'est parce que vous ne pouvez pas détecter l'encodage sans une sorte de dictionnaire ou d'une approche statistique (comme le mien).mb_detect_encoding
va par le biais de la liste de codages, et accepte la première qui n'a pas non valide les séquences d'octets de la chaîne ... Pour les codages qui n'ont pas invalide les séquences d'octets comme ISO-8859-1, c'est toujours vrai. Aucun "intelligents" les heuristiques, et les résultats varient grandement en fonction de la liste (et de l'ordre) de codages vous passer.mb_detect_order()
même si c'est la valeur par défaut de ce paramètre, car il souhaitait stricte de codage de détection de vrai (le 3ème param) 🙂mb_detect_encoding('áéóú', 'UTF-8', true)
retournefalse
et donc neiconv()
. Je ne vois pas l'avantage par rapport à tout simplement détecter si c'est l'UTF-8: stackoverflow.com/a/4407996/318765$encoding = mb_detect_encoding($text, 'ASCII, UTF-8, ISO-8859-1', true); $text = $encoding ? iconv($encoding, 'UTF-8//TRANSLIT', $text) : '';
à la place. Mais enfin, cela ne résoudra pas le problème, comme par exemple une entrée de l'UTF-16 entraînera une chaîne vide, comme UTF-16 ne peut pas être détecté.Dans la mère-patrie, la Russie, nous avons 4 encodages populaires, de sorte que votre question est en grande demande ici.
Seulement par char codes de symboles vous ne pouvez pas détecter l'encodage, car les pages de code se croisent. Certaines pages de code dans différentes langues ont même intersection complète. Donc, nous avons besoin d'une autre approche.
Le seul moyen de travailler avec des inconnus encodages est de travailler avec des probabilités. Donc, nous ne voulons pas répondre à la question "qu'est-ce que l'encodage de ce texte?", nous essayons de comprendre "ce qui est le plus susceptible d'encodage de ce texte?".
Un gars ici en russe populaire tech blog inventé cette approche:
Construire la probabilité gamme de char codes dans chaque encodage que vous voulez soutenir. Vous pouvez le construire à l'aide de quelques grands textes dans votre langue (par exemple, un peu de fiction, l'utilisation de Shakespeare pour l'anglais et de Tolstoï pour le russe, lol ). Vous obtiendrez qch comme ceci:
Suivant. Vous prenez un texte inconnu de codage et pour chaque encodage dans votre "probabilité dictionnaire" de votre recherche pour la fréquence de chaque symbole dans l'inconnu du texte codé. La somme des probabilités des symboles. Encodage avec le plus grand cote est probable que le vainqueur. De meilleurs résultats pour les plus grands textes.
Si vous êtes intéressé, je peux volontiers vous aider dans cette tâche. Nous pouvons grandement améliorer la précision par la construction de deux charcodes probabilty liste.
Btw. mb_detect_encoding certanly ne fonctionne pas. Oui, à tous. S'il vous plaît, jetez un oeil de mb_detect_encoding code source dans "ext/mbstring/libmbfl/mbfl/mbfl_ident.c".
Vous avez probablement essayé, mais pourquoi ne pas simplement utiliser le mb_convert_encoding fonction? Il va tenter d'auto-détecter le jeu de caractères du texte ou vous pouvez passer d'une liste.
Aussi, j'ai essayé d'exécuter:
et les résultats sont les mêmes pour les deux. Comment voyez-vous que votre texte est tronqué à 'fiancé'? est-il dans la base de données ou dans un navigateur?
iconv
. J'ai essayé de faire presque pur mb_* en route. Ce que vous pensez-vous?Il n'y a aucun moyen d'identifier le jeu de caractères d'une chaîne qui est tout à fait exact.
Il y a des façons d'essayer de deviner le jeu de caractères. L'un de ces moyens, et probablement/actuellement le meilleur en PHP, est mb_detect_encoding(). Cela va scanner votre chaîne et de rechercher les occurrences de choses uniques à certains jeux de caractères. En fonction de votre chaîne, il y a peut-être pas à distinguer les occurrences.
Prendre l'ISO-8859-1 jeu de caractères vs ISO-8859-15 ( http://en.wikipedia.org/wiki/ISO/IEC_8859-15#Changes_from_ISO-8859-1 )
Il n'y a qu'une poignée de personnages différents, et pour empirer les choses, ils sont représentés par le même octets. Il n'y a aucun moyen de le détecter, étant donné une chaîne de caractères, sans le savoir, l'encodage, si octet 0xA4 est censé signifier ¤ € ou dans votre chaîne, donc il n'y a aucun moyen de savoir c'est exact charset.
(Remarque: vous pouvez ajouter un facteur humain, ou encore plus avancé de la technique de balayage (par exemple, ce qui Oroboros102 l'indique), pour essayer de comprendre basée sur le contexte environnant, si le caractère doit être ¤ € ou, si cela semble comme un pont trop loin)
Il y a plus à distinguer les différences entre par exemple UTF-8 et ISO-8859-1, c'est donc toujours la peine d'essayer de comprendre quand vous n'êtes pas sûr, si vous pouvez et ne devez jamais compter sur elle est correcte.
Lecture intéressante: http://kore-nordmann.de/blog/php_charset_encoding_FAQ.html#how-do-i-determine-the-charset-encoding-of-a-string
Il y a d'autres façons d'assurer le bon charset bien. Concernant les formes, essayez de faire respecter l'UTF-8 comme beaucoup que possible (consultez le bonhomme de neige à assurez-vous que votre présentation doit être en UTF-8 dans chaque navigateur: http://intertwingly.net/blog/2010/07/29/Rails-and-Snowmen )
Cela étant fait, au moins vous pouvez être sûr que chaque texte soumis par le biais de vos formulaires est utf_8. Concernant les fichiers téléchargés, essayez d'exécuter la unix "fichier -i' commande, par exemple par exec() (si possible sur votre serveur) à l'aide de la détection (en utilisant le document de la NOMENCLATURE.)
Concernant le raclage de données, vous pouvez lire les en-têtes HTTP, qui, généralement, spécifier le jeu de caractères. Lors de l'analyse des fichiers XML, voir si le XML meta-données contiennent un jeu de caractères définition.
Plutôt que d'essayer de deviner automatiquement le jeu de caractères, vous devez d'abord essayer de s'assurer une certaine charset vous-même, si possible, ou en essayant d'attraper une définition de la source que vous êtes obtenir à partir (le cas échéant) avant de recourir à la détection.
Il y a vraiment de bonnes réponses, et tente de répondre à votre question ici. Je ne suis pas un encodage maître, mais je comprends votre désir d'avoir un pur UTF-8 de la pile sur le chemin de votre base de données. J'ai été en utilisant MySQL
utf8mb4
codant pour des tables, des champs et des connexions.Ma situation se résumait à "je veux juste mon désinfectants, des validateurs, la logique métier, et des déclarations préparées à faire face avec UTF-8 lorsque des données à partir de formulaires HTML ou d'e-mail d'enregistrement de liens." Donc, en ma façon simple, j'ai commencé avec cette idée:
$encodings = ['UTF-8', 'ISO-8859-1', 'ASCII'];
throw new RuntimeException
UTF-8
poursuivre.D'autre, si c'est
ISO-8859-1
ouASCII
un. Tentative de conversion en UTF-8 (temps d'attente, pas fini)
b. Détecter le codage de la valeur convertie
c. Si l'rapporté de l'encodage et de la valeur convertie sont à la fois
UTF-8
poursuivre.d. Autre chose,
throw new RuntimeException
De ma classe abstraite
Sanitizer
On pourrait faire un argument que je devrais séparés l'encodage des préoccupations de mon résumé
Sanitizer
classe et simplement injecter unEncoder
objet dans un béton enfant instance deSanitizer
. Cependant, le principal problème avec mon approche est que, sans plus de connaissances, j'ai simplement rejeter types d'encodage que je ne veux pas (et je me base sur PHP mb_* fonctions). Sans étude approfondie, je ne peut pas savoir si ça fait mal à certaines populations ou pas (ou, si je suis perdant sur "informations importantes"). Donc, j'ai besoin d'en savoir plus. J'ai trouvé cet article.Ce que chaque programmeur absolument besoin de savoir sur les codages et les jeux de caractères pour travailler avec du texte
En outre, ce qui se passe lorsque des données chiffrées est ajouté à mon email liens d'inscription (à l'aide de
OpenSSL
oumcrypt
)? Cela pourrait interférer avec le décodage? Qu'en Windows-1252? Que sur les implications en matière de sécurité? L'utilisation deutf8_decode()
etutf8_encode()
dansSanitizer::isUTF8
sont douteux.Les gens l'ont souligné les lacunes dans le PHP mb_* les fonctions. Je n'ai jamais pris le temps d'étudier
iconv
, mais si cela fonctionne mieux que mb_*fonctions, laissez-moi savoir.Je ne pense pas que c'est un problème. Une application connaît la source de l'entrée. Si c'est à partir d'un formulaire, utiliser l'encodage UTF-8 dans votre cas. Qui fonctionne. Suffit de vérifier les données fournies est codé correctement (validation). Gardez à l'esprit que toutes les bases de données de support de l'UTF-8 dans sa gamme complète.
Si c'est un fichier que vous n'aurez pas l'enregistrer en UTF-8 dans la base de données, mais sous forme binaire. Lors de la sortie de nouveau le fichier, utiliser la sortie binaire ainsi, alors ceci est totalement transparent.
Votre idée est sympa qu'un utilisateur peut déterminer le codage, qu'il/elle peut dire de toute façon après avoir téléchargé le fichier, que c'est du binaire.
Donc je dois avouer que je ne vois pas un problème spécifique, vous relancez avec votre question. Mais peut-être que vous pouvez ajouter un peu plus de détails ce qu'est ton problème.
Vous pourriez mettre en place un ensemble de mesures pour essayer de deviner quel encodage est utilisé. Encore une fois, il n'est pas parfait, mais pourrait rattraper un peu du manque de mb_detect_encoding().
mb_detect_encoding()
manque, pensez-vous que ma réponse a une boule de neige de la chance en été dans le Sahara?Si vous êtes prêt à "prendre la console", je vous recommande
enca
. Contrairement à la plutôt simplistemb_detect_encoding
, il utilise un mélange d'analyse syntaxique, analyse statistique, de deviner et de la magie noire afin de déterminer leur encodage" (lol - voir page de man). Cependant, vous avez généralement à passer la langue de fichier d'entrée si vous voulez détecter de tels spécifiques au pays des codages. (Cependant,mb_detect_encoding
essentiellement a la même exigence, comme l'encodage devrait apparaître "au bon endroit" dans la liste de codages pour qu'il soit détectable à tous.)enca
aussi est venu ici: Comment trouver l'encodage d'un fichier sous Unix via le script(s)Il semble que votre question est tout à fait répondu, mais j'ai une approche qui peut vous simplifier cas:
J'ai eu un problème similaire en essayant de retourner la chaîne de données de mysql, même la configuration de la base de données et php pour renvoyer des chaînes formatées à l'utf-8. La seule façon que j'ai obtenu l'erreur était en fait le retour de la base de données.
Enfin, navigation sur le web j'ai trouvé un moyen facile de traiter avec elle:
Donner que vous pouvez enregistrer tous les types de données de chaîne dans votre mysql dans différents formats et les classements, ce que vous avez seulement besoin de faire est, à votre de connexion php fichiers, définir le classement de l'utf-8, comme ceci:
Qui signifie que d'abord vous enregistrer les données dans n'importe quel format ou de classement et de vous convertir seulement au retour de votre fichier php.
Espère que ça a été utile!
cURL options par défaut:
J'ai essayé quelque chose comme ça. Il m'a aidé. Si trouvé sur meta charset info, je suis à la conversion, sinon ne rien faire.