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 :
- la connexion : dans le DSN PDO,
charset=utf8mb4; - la base et les tables : conversion avec
ALTER TABLE … CONVERT TO CHARACTER SET utf8mb4; - 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_ciexiste partout, alors queutf8mb4_0900_ai_ciest propre à MySQL 8 et absent de nombreuses versions de MariaDB.
Publié le 27/05/2025.