web-dev-qa-db-fra.com

Problème avec les caractères UTF-8; ce que je vois n'est pas ce que j'ai stocké

J'ai essayé d'utiliser UTF-8 et j'ai eu des ennuis.

J'ai essayé beaucoup de choses. voici les résultats que j'ai obtenus:

  • ???? au lieu de caractères asiatiques. Même pour le texte européen, j'ai Se?or pour Señor.
  • Un charabia étrange (Mojibake?) Tel que Señor ou 新浪新闻 pour 新浪新闻.
  • Diamants noirs, tels que Se�or.
  • Enfin, je me suis retrouvé dans une situation où les données étaient perdues, ou du moins tronquées: Se pour Señor.
  • Même quand j'ai eu le texte à regarder bien, il n'a pas trier correctement.

Qu'est-ce que je fais mal? Comment puis-je réparer le code? Puis-je récupérer le data, si oui, comment?

59
Rick James

Ce problème affecte les participants de ce site et de nombreux autres.

Vous avez énuméré les cinq principaux cas de CHARACTER SET problèmes.

Meilleure pratique

À l'avenir, il est préférable d'utiliser CHARACTER SET utf8mb4 et COLLATION utf8mb4_unicode_520_ci. (Il existe une version plus récente du classement Unicode dans le pipeline.)

utf8mb4 est un sur-ensemble de utf8 dans la mesure où il gère les codes utf8 sur 4 octets, nécessaires à Emoji et à certains chinois.

En dehors de MySQL, "UTF-8" fait référence à tous les codages de taille, donc identiques à ceux de MySQL utf8mb4, ne pas utf8.

J'essaierai d'utiliser ces orthographes et majuscules pour distinguer intérieurement et extérieurement de MySQL dans la suite.

Aperçu de ce que vous devriez faire

  • Demandez à votre éditeur, etc., de définir UTF-8.
  • Les formulaires HTML doivent commencer comme <form accept-charset="UTF-8">.
  • Faites coder vos octets au format UTF-8.
  • Définissez UTF-8 en tant que codage utilisé dans le client.
  • Avoir la colonne/table déclarée CHARACTER SET utf8mb4 (Vérifier avec SHOW CREATE TABLE.)
  • <meta charset=UTF-8> au début de HTML

TF-8 jusqu'au bout

Plus de détails pour les langages informatiques (et ses sections suivantes)

Testez les données

L'affichage des données avec un outil ou avec SELECT ne peut pas être approuvé. Trop de ces clients, en particulier les navigateurs, tentent de compenser les encodages incorrects et vous montrent le texte correct même si la base de données est endommagée. Alors, choisissez un tableau et une colonne qui a un texte non anglais et faites

SELECT col, HEX(col) FROM tbl WHERE ...

Le HEX pour UTF-8 correctement stocké sera

  • Pour un espace vide (dans n'importe quelle langue): 20
  • Pour l'anglais: 4x, 5x, 6x, ou 7x
  • Pour la plupart des pays d’Europe occidentale, les lettres accentuées devraient être Cxyy
  • Cyrillique, hébreu et farsi/arabe: Dxyy
  • La plupart de l'Asie: Exyyzz
  • Emoji et quelques Chinois: F0yyzzww
  • Plus de détails

Causes spécifiques et solutions des problèmes rencontrés

Tronqué texte (Se pour Señor):

  • Les octets à stocker ne sont pas codés en tant que utf8mb4. Répare ça.
  • Vérifiez également que la connexion en cours de lecture est UTF-8.

Black Diamonds avec des points d'interrogation (Se�or pour Señor); l'un de ces cas existe:

Cas 1 (les octets d'origine étaient pas UTF-8):

  • Les octets à stocker ne sont pas codés en tant que utf8. Répare ça.
  • La connexion (ou SET NAMES) pour le INSERT et le SELECT n'était pas utf8/utf8mb4. Répare ça.
  • Vérifiez également que la colonne de la base de données est CHARACTER SET utf8 (ou utf8mb4).

Cas 2 (octets d'origine étaient UTF-8):

  • La connexion (ou SET NAMES) pour le SELECT n'était pas utf8/utf8mb4. Répare ça.
  • Vérifiez également que la colonne de la base de données est CHARACTER SET utf8 (ou utf8mb4).

Les diamants noirs apparaissent uniquement lorsque le navigateur est défini sur <meta charset=UTF-8>.

Points d'interrogation (normaux, pas de diamants noirs) (Se?or pour Señor):

  • Les octets à stocker ne sont pas codés en tant que utf8/utf8mb4. Répare ça.
  • La colonne dans la base de données n'est pas CHARACTER SET utf8 (ou utf8mb4). Répare ça. (Utilisation SHOW CREATE TABLE.)
  • Vérifiez également que la connexion en cours de lecture est UTF-8.

Mojibake (Señor pour Señor): (Cette discussion s'applique également à le double codage , qui n'est pas nécessairement visible.)

  • Les octets à stocker doivent être codés en UTF-8. Répare ça.
  • La connexion lorsque INSERTing et SELECTing text doit spécifier utf8 ou utf8mb4. Répare ça.
  • La colonne doit être déclarée CHARACTER SET utf8 (ou utf8mb4). Répare ça.
  • HTML devrait commencer par <meta charset=UTF-8>.

Si les données semblent correctes, mais ne trient pas correctement, soit vous avez sélectionné le mauvais classement, soit aucun classement ne correspond à votre besoin, ou vous avez un double codage .

Le double encodage peut être confirmé en faisant le SELECT .. HEX .. décrit ci-dessus.

é should come back C3A9, but instead shows C383C2A9
The Emoji ???? should come back F09F91BD, but comes back C3B0C5B8E28098C2BD

Autrement dit, l'hex est environ deux fois plus long qu'il devrait l'être. Cela est dû à la conversion de latin1 (ou quoi que ce soit) en utf8, puis à traiter ces octets comme s’ils étaient en latin1 et à répéter la conversion. Le tri (et la comparaison) ne fonctionnent pas correctement car il s’agit, par exemple, d’un tri comme si la chaîne était Señor.

Correction des données, si possible

Pour Troncature et Points d'interrogation , les données sont perdues.

Pour Mojibake / Double Encodage , ...

Pour Black Diamonds , ...

(Je vais devoir continuer dans une autre question/réponse.)

97
Rick James

J'ai eu des problèmes similaires avec 2 de mes projets, après une migration de serveur. Après avoir cherché et essayé beaucoup de solutions, je suis tombé sur celle-ci:

mysqli_set_charset($con,"utf8");

Après avoir ajouté cette ligne à mon fichier de configuration, tout fonctionne correctement!

J'ai trouvé cette solution pour mysqli https://www.w3schools.com/PHP/func_mysqli_set_charset.asp quand je cherchais à résoudre une requête d'insertion à partir de html

bonne chance!

4
castro_pereira

C'est drôle comment tu réponds à ta propre question :)

  1. Définissez votre code IDE langue sur UTF8

  2. Ajoutez à l'en-tête de votre page Web où vous collectez le formulaire de données.

  3. Vérifiez que votre définition de table MySQL ressemble à ceci:

    CREATE TABLE your_table (
      ...
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
  4. Si vous utilisez PDO, assurez-vous

    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES utf8'); 
    $dbL = new PDO($pdo, $user, $pass, $options);
    

Si vous avez déjà une grosse base de données avec le problème ci-dessus, vous pouvez essayer d'exporter SIDU avec le jeu de caractères correct et de l'importer avec UTF8. Bonne chance

2
SIDU