web-dev-qa-db-fra.com

Correction d'un encodage UTF-8 cassé

Je suis en train de réparer 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: î

  • Le classement de la base de données est utf8_general_ci
  • PHP utilise un en-tête UTF-8 approprié
  • Notepad ++ est configuré pour utiliser UTF-8 sans BOM
  • la gestion de la base de données est géré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 à mapper les instances de î, ÃÂ, ü et d'autres similaires à leurs caractères UTF-8 accentués appropriés.

58
Jayrox

J'ai dû essayer de `` réparer '' un certain nombre de situations cassées 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 il a été brisé, et il 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 meilleur pari serait de commencer à écrire un exemple de code, où vous tentez de nombreuses variantes d'appels à mb_convert_encoding () pour voir si vous pouvez trouver une combinaison de 'de' et 'à' cela corrige vos données. En fin de compte, il est souvent préférable de ne pas même se soucier de réparer les anciennes données en raison des niveaux de douleur impliqués, mais plutôt de simplement réparer les choses à l'avenir.

Cependant, avant de faire cela, vous devez vous assurer que vous corrigez tout ce qui est à l'origine de ce problème. Vous avez déjà mentionné que le classement et les éditeurs de votre table DB sont correctement définis. Mais il y a plus d'endroits où vous devez vérifier pour vous assurer que tout est correctement UTF-8:

  • Assurez-vous que vous servez votre code HTML en UTF-8:
    • en-tête ("Content-Type: text/html; charset = utf-8");
  • Changez votre PHP jeu de caractères par défaut en utf-8:
    • ini_set ("default_charset", 'utf-8');
  • Si votre base de données ne parle PAS TOUJOURS en utf-8, alors vous devrez peut-être le dire sur une base par connexion pour vous assurer qu'elle est en mode utf-8, dans MySQL vous le faites en émettant:
    • charset utf8
  • Vous devrez peut-être 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 PHP fonctions qui sont correctement conformes à UTF-8. Cela signifie toujours utiliser mb _ * style 'multibyte aware') Cela signifie également lorsque vous appelez des fonctions telles que htmlspecialchars (), que vous incluez le paramètre charset 'utf-8' approprié à la fin pour vous assurer qu'il ne les code pas incorrectement.

Si vous manquez une étape de votre processus, l'encodage peut être modifié et des problèmes surviennent. Une fois que vous êtes dans le "groove" de la pratique de l'utf-8, tout cela devient une seconde nature. Et bien sûr, PHP6 est censé être une plainte entièrement unicode du getgo, ce qui facilitera beaucoup cela (espérons-le)

62
Eli

Si vous avez des caractères UTF8 double-encodés (diverses guillemets intelligents, tirets, apostrophe ", guillemet", 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

Il s'agissait d'un correctif à 100% pour mon UTF-8 à double codage.

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

92
jsdalton

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

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

Vous n'avez pas besoin de spécifier le codage de vos chaînes. Il peut s'agir de 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.

Usage:

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

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

Mon autre fonction fixUTF8() corrige les chaînes UTF8 tronquées si elles étaient encodées en UTF8 plusieurs fois.

Usage:

$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");

affichera:

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

78
Sebastián Grignoli

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

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

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

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

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

Je sais que ce n'est pas très élégant, mais après avoir mentionné que les chaînes peuvent être codées en double, j'ai fait cette fonction:

function fix_double encoding($string)
{
    $utf8_chars = explode(' ', 'À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö');
    $utf8_double_encoded = array();
    foreach($utf8_chars as $utf8_char)
    {
            $utf8_double_encoded[] = utf8_encode(utf8_encode($utf8_char));
    }
    $string = str_replace($utf8_double_encoded, $utf8_chars, $string);
    return $string;
}

Cela semble fonctionner parfaitement pour supprimer le double encodage que je rencontre. Il me manque probablement certains des personnages qui pourraient être un problème pour d'autres. Cependant, pour mes besoins, cela fonctionne parfaitement.

2
Jayrox

Le moyen est de convertir en binaire puis de corriger l'encodage

2
Dan

Une autre chose à vérifier, qui s'est avérée être ma solution (trouvée ici ), est de savoir comment les données sont renvoyées depuis votre serveur. Dans mon application, j'utilise PDO pour me connecter de PHP à MySQL. J'avais besoin d'ajouter un indicateur à la connexion qui disait récupérer les données au format UTF-8

La réponse a été

$dbHandle = new PDO("mysql:Host=$dbHost;dbname=$dbName;charset=utf8", $dbUser, $dbPass, 
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
1
Luke Madhanga

j'ai eu le même problème il y a longtemps, et il l'a résolu en utilisant

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
0
Jose De Gouveia

Il semble que votre utf-8 soit interprété comme iso8859-1 ou Win-1250 à un moment donné.

Lorsque vous dites "Dans ma base de données, j'ai quelques exemples de mauvais encodages" - comment avez-vous vérifié cela? Via votre application, phpmyadmin ou le client en ligne de commande? tous les encodages utf-8 apparaissent-ils comme ceci ou seulement certains? Est-il possible que les encodages soient incorrects et qu'il ait été incorrectement converti de iso8859-1 en utf-8 alors qu'il était déjà utf-8?

0
teambob

J'ai trouvé une solution après des jours de recherche. Mon commentaire va être enterré mais de toute façon ...

  1. J'obtiens les données corrompues avec php.

  2. Je n'utilise pas de noms de set UTF8

  3. J'utilise utf8_decode () sur mes données

  4. Je mets à jour ma base de données avec mes nouvelles données décodées, toujours pas en utilisant les noms de set UTF8

et voilà :)

0
David 天宇 Wong

Ce script avait une belle approche. Le convertir dans la langue de votre choix ne devrait pas être trop difficile:

http://plasmasturm.org/log/416/

#!/usr/bin/Perl
use strict;
use warnings;

use Encode qw( decode FB_QUIET );

binmode STDIN, ':bytes';
binmode STDOUT, ':encoding(UTF-8)';

my $out;

while ( <> ) {
  $out = '';
  while ( length ) {
    # consume input string up to the first UTF-8 decode error
    $out .= decode( "utf-8", $_, FB_QUIET );
    # consume one character; all octets are valid Latin-1
    $out .= decode( "iso-8859-1", substr( $_, 0, 1 ), FB_QUIET ) if length;
  }
  print $out;
}
0
Erik Aronesty