69 votes

Correction d'un encodage UTF-8 défectueux

Je suis en train de corriger un mauvais encodage UTF-8. J'utilise actuellement PHP 5 et MySQL.

Dans ma base de données, j'ai quelques exemples de mauvais encodages qui s'impriment comme : î

  • La collation de la base de données est utf8_general_ci
  • PHP utilise un en-tête UTF-8 correct.
  • Notepad++ est configuré pour utiliser UTF-8 sans BOM.
  • la gestion de la base de données est traitée dans phpMyAdmin
  • tous les cas de caractères accentués ne sont pas cassés

J'ai besoin d'une sorte de fonction qui m'aidera à faire correspondre les instances de î, í, ü et d'autres caractères similaires à leurs caractères UTF-8 accentués appropriés.

0 votes

Vous pourriez peut-être énumérer les personnages qu'ils sont censés représenter ? Et peut-être un vidage hexagonal ?

7 votes

Un coup d'œil rapide semble suggérer que vos chaînes ont pu être "doublement" encodées en utf-8. C'est-à-dire qu'elles ont été encodées en utf-8, ces octets ont été pris comme des caractères unicode, et le résultat a été encodé en utf-8. En revenant en arrière : "î"=" \xC3\x83\xC2\xAE " <-(utf-8)- " \xC3\xAE " <-(utf-8)- " \xEE " = "î". Ou peut-être pas -- pas beaucoup de données à diagnostiquer ici.

0 votes

Il est possible que ce soit un double encodage. Existe-t-il un moyen sûr de vérifier cela par programme, et si oui, quel est le meilleur moyen de décoder le double encodage en toute sécurité ?

97voto

jsdalton Points 1895

Si vous avez des caractères UTF8 doublement encodés (divers guillemets intelligents, tirets, apostrophe ', guillemets ", etc.), dans mysql vous pouvez vider les données, puis les relire pour corriger l'encodage cassé.

Comme ça :

mysqldump -h DB_HOST -u DB_USER -p DB_PASSWORD --opt --quote-names \
    --skip-set-charset --default-character-set=latin1 DB_NAME > DB_NAME-dump.sql

mysql -h DB_HOST -u DB_USER -p DB_PASSWORD \
    --default-character-set=utf8 DB_NAME < DB_NAME-dump.sql

C'était une correction à 100% pour mon double encodage UTF-8.

Source : http://blog.hno3.org/2010/04/22/fixing-double-encoded-utf-8-data-in-mysql/

2 votes

Il semble avoir converti avec succès une base de données Typo3 pour moi. Merci d'avoir publié ce message ; c'est beaucoup plus propre que toute autre méthode de conversion :)

0 votes

J'aimerais pouvoir te donner plus de votes positifs, tu les mérites vraiment.

0 votes

Yep, ça a aussi marché pour moi ! Merci de l'avoir partagé ici et merci au propriétaire du blog :)

90voto

Si vous utf8_encode() sur une chaîne de caractères qui est déjà UTF-8, elle semble déformée lorsqu'elle est encodée plusieurs fois.

J'ai créé une fonction toUTF8() qui convertit les chaînes de caractères en UTF-8.

Vous n'avez pas besoin de spécifier l'encodage de vos chaînes de caractères. Il peut être Latin1 (iso 8859-1), Windows-1252 ou UTF8, ou un mélange des trois.

Je l'ai utilisé moi-même sur un flux avec des encodages mixtes dans la même chaîne.

Utilisation :

$utf8_string = Encoding::toUTF8($mixed_string);

$latin1_string = Encoding::toLatin1($mixed_string);

Mon autre fonction fixUTF8() corrige les chaînes UTF8 déformées si elles ont été encodées en UTF8 plusieurs fois.

Utilisation :

$utf8_string = Encoding::fixUTF8($garbled_utf8_string);

Exemples :

echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");

produira un résultat :

Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football

Télécharger :

https://github.com/neitanod/forceutf8

1 votes

Ça semble faire l'affaire. Je ne l'utilise pas pour les sorties normales, mais j'aime utiliser votre classe pour aider à la migration des données.

8 votes

Merci. C'est magique, n'est-ce pas ? Je pense que ce petit bout de code est l'une des choses les plus satisfaisantes que j'ai produites, en termes de problèmes résolus avec lui :-)

0 votes

Je recommande de l'utiliser pour les migrations, comme l'a dit Kristopher, mais pas dans un environnement de production. Il y a des cas où vous voudriez que la "chaîne brouillée" reste brouillée, comme dans cette réponse.

66voto

Eli Points 621

J'ai dû essayer de "réparer" un certain nombre de situations de rupture d'UTF8 dans le passé, et malheureusement ce n'est jamais facile, et souvent plutôt impossible.

À moins que vous ne puissiez déterminer exactement comment elle a été cassée, et qu'elle l'a toujours été de la même manière, il sera difficile de "réparer" les dommages.

Si vous voulez essayer de réparer les dégâts, votre meilleure chance serait de commencer à écrire un exemple de code, où vous essayez de nombreuses variations sur les appels à mb_convert_encoding() pour voir si vous pouvez trouver une combinaison de "de" et "à" qui fixe vos données. En fin de compte, il est souvent préférable de ne pas s'inquiéter de la correction des anciennes données en raison des niveaux de douleur impliqués, mais plutôt de corriger les choses pour l'avenir.

Cependant, avant de faire cela, vous devez vous assurer que vous corrigez tout ce qui cause ce problème en premier lieu. Vous avez déjà mentionné que la collation et les éditeurs de votre table de base de données sont correctement définis. Mais il y a d'autres endroits où vous devez vérifier que tout est correctement UTF-8 :

  • Assurez-vous que vous fournissez votre HTML en UTF-8 :
    • header("Content-Type: text/html; charset=utf-8");
  • Changez le jeu de caractères par défaut de PHP en utf-8 :
    • ini_set("default_charset", 'utf-8');
  • Si votre base de données ne parle pas TOUJOURS en utf-8, il se peut que vous deviez lui demander, pour chaque connexion, de s'assurer qu'elle est en mode utf-8, ce que vous pouvez faire avec MySQL :
    • jeu de caractères utf8
  • Vous pouvez avoir besoin de dire à votre serveur web de toujours essayer de parler en UTF8, dans Apache cette commande est :
    • AddDefaultCharset UTF-8
  • Enfin, vous devez TOUJOURS vous assurer que vous utilisez des fonctions PHP qui sont correctement conformes à l'UTF-8. Cela signifie que vous devez toujours utiliser l'option mb_* des fonctions de chaîne de caractères de type "multibyte". Cela signifie également que lorsque vous appelez des fonctions telles que htmlspecialchars() Il est important que vous incluiez le paramètre charset 'utf-8' approprié à la fin pour vous assurer qu'il ne les codera pas de manière incorrecte.

Si vous oubliez une seule étape de votre processus, l'encodage peut être déformé et des problèmes peuvent survenir. Une fois que vous avez pris l'habitude d'utiliser utf-8, tout cela devient une seconde nature. Et bien sûr, PHP6 est supposé être entièrement unicode dès le départ, ce qui facilitera beaucoup de choses (espérons-le).

1 votes

Merci beaucoup ! Comme il y a aussi beaucoup de chaînes correctement encodées dans la base de données, ce qui aggrave le problème, j'ai choisi de remplacer les chaînes corrompues par leurs caractères corrects. Cela fonctionne parfaitement. J'ai déjà mis en œuvre la plupart de vos conseils concernant PHP et la configuration du serveur, mais c'est un excellent résumé, donc je choisirais ceci comme réponse, parce que ma solution n'est pas vraiment belle.

0 votes

Une remarque importante sur ce conseil : N'ajoutez PAS 'utf-8' comme deuxième argument à la fonction htmlspecialchars(). Sans cet argument, cette fonction fait ce qu'il faut avec les chaînes UTF-8, puisqu'elle ignore tous les octets dont le bit de poids fort est activé et les laisse passer. Cela permet de les préserver et de "faire la bonne chose". Avec 'utf-8', htmlspecialchars() interprète la chaîne UTF-8 - mais ne traite pas les caractères hors BMP (ceux dont les points de code sont U+10000 et plus, encodés en quatre octets). Elle encode de manière incorrecte ceux qui correspondent aux specials mod 65536 . Ce comportement est à la fois plus lent et erroné.

0 votes

Veuillez consulter ma réponse ci-dessous. J'ai résolu tous ces problèmes dans une seule fonction pure-PHP : fixUTF8(). Vous n'avez pas besoin de modifier la configuration de votre serveur, et vous n'avez même pas besoin d'avoir les fonctions multi-octets installées. La fonction est assez intelligente pour corriger chaque caractère indépendamment, même si l'encodage est mélangé dans la même chaîne (peu importe combien de fois elle a été convertie ou si elle est déjà en UTF8).

19voto

Celleb Points 1

J'ai eu un problème avec un fichier xml qui avait un encodage cassé, il disait qu'il était utf-8 mais il avait des caractères qui n'étaient pas utf-8.
Après plusieurs essais et erreurs avec le mb_convert_encoding() J'arrive à le réparer avec

mb_convert_encoding($text, 'Windows-1252', 'UTF-8')

1 votes

Cela a fonctionné pour moi après des jours à me cogner la tête sur le problème (tout était UTF-8 de bout en bout mais pas dans le RSS !) Merci !

0 votes

Mon problème était : Les champs de la base de données sont enregistrés en tant que latin1_swedish_ci sortie par PHP en utf-8 montrant Umlaute ü comme ü et ö comme ö . Cela a permis de régler ce problème.

11voto

blueyed Points 7719

Comme Dan l'a souligné : vous devez les convertir en binaire et ensuite convertir/corriger l'encodage.

Par exemple, pour utf8 stocké en latin1, le SQL suivant le résoudra :

UPDATE table
   SET field = CONVERT( CAST(field AS BINARY) USING utf8)
 WHERE $broken_field_condition

0 votes

Intéressant ; je m'en souviendrai si je rencontre à nouveau ce problème. merci.

1 votes

C'est logique. Je suppose que c'est vraiment un double encodage, c'est juste que le champ est marqué latin1 même s'il contient réellement UTF8, donc quand vous demandez le champ en UTF8, il l'encode à nouveau.

0 votes

Mec, tu as fait ma journée, ça a marché pour moi. Maintenant j'aimerais comprendre la vraie raison pour laquelle le dump avec lequel je travaille a ces caractères erronés (peut-être qu'il a été correctement encodé en utf-8 mais que le processus de dump a imprimé la sortie en latin1).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X