Aller au contenu
VOZit

Blog · Bases de données

utf8 ou utf8mb4 : pourquoi les emojis cassent votre base MySQL

Un utilisateur saisit un emoji dans un formulaire, et le texte est coupé net à cet endroit — ou l'enregistrement échoue. Ce n'est pas un bug de votre code : c'est un piège historique de MySQL et MariaDB, dont le jeu de caractères « utf8 » n'est pas tout à fait de l'UTF-8.

Le faux utf8

L'UTF-8 encode un caractère sur 1 à 4 octets. Les lettres accentuées en prennent 2, la plupart des caractères courants 3, et les emojis — comme certains idéogrammes rares — 4.

Or le jeu de caractères historiquement nommé utf8 dans MySQL et MariaDB est limité à 3 octets. Il s'appelle désormais utf8mb3, et utf8 en est un alias. Le véritable UTF-8 complet s'appelle utf8mb4.

Selon le mode SQL du serveur, un caractère de 4 octets dans une colonne utf8mb3 provoque une erreur (« Incorrect string value ») ou est silencieusement tronqué.

Les trois niveaux à corriger

Le jeu de caractères se règle à trois endroits, et les trois doivent concorder :

  1. la connexion : dans le DSN PDO, charset=utf8mb4 ;
  2. la base et les tables : conversion avec ALTER TABLE … CONVERT TO CHARACTER SET utf8mb4 ;
  3. le serveur : jeu de caractères par défaut, pour que les nouvelles tables naissent correctes.
$pdo = new PDO('mysql:host=localhost;dbname=app;charset=utf8mb4', $u, $p);

ALTER DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE messages CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Le piège des index

Avec utf8mb4, chaque caractère peut occuper 4 octets au lieu de 3. Un index sur une colonne VARCHAR(255) représente alors jusqu'à 1 020 octets. Sur les anciens formats de ligne InnoDB, la clé d'index est limitée à 767 octets, et la conversion échoue avec « Specified key was too long ».

Deux réponses : utiliser le format de ligne DYNAMIC (par défaut sur les versions récentes, qui portent la limite à 3 072 octets), ou réduire la colonne indexée à VARCHAR(191) — d'où ce chiffre étrange que l'on croise dans de nombreux schémas.

Avant de convertir

  • Sauvegardez : la conversion réécrit toute la table.
  • Sur une grosse table, la conversion bloque les écritures pendant sa durée : planifiez-la hors des heures d'activité.
  • Vérifiez que les données actuelles sont réellement en UTF-8 : une base remplie en latin1 mais déclarée utf8 (cas fréquent sur les vieux sites) produit des caractères doublement encodés (« é » au lieu de « é ») qu'il faut corriger d'abord.
  • Choisissez un interclassement disponible sur votre serveur : utf8mb4_unicode_ci existe partout, alors que utf8mb4_0900_ai_ci est propre à MySQL 8 et absent de nombreuses versions de MariaDB.

Publié le 27/05/2025.

Parlons de votre projet

Un projet, une idée, une application à reprendre ?

Décrivez-le en quelques lignes. Nous revenons vers vous rapidement avec nos questions ou une proposition d'échange. L'étude est gratuite et sans engagement.

  • Étude gratuite, sans engagement
  • Un interlocuteur unique, du devis à la maintenance
  • Développé et hébergé en France
  • Basés près d'Angers, projets partout en France
Demander un devis gratuit