En tant que développeur PHP ou MySQL Une fois que vous avez dépassé les limites des jeux de caractères confortables uniquement en anglais, vous vous retrouvez rapidement empêtré dans le monde merveilleusement étrange de UTF-8.
Un aperçu de l'apprêt UTF-8En un travail Avant celui-ci, nous avons commencé à rencontrer des problèmes de codage de données lors de la présentation de biographies d'artistes du monde entier. Il est vite devenu évident qu'il y avait des problèmes avec les données stockées car parfois les données étaient codées correctement et parfois non.
Cela a conduit les programmeurs à implémenter un mélange de correctifs, parfois avec JavaScript, parfois avec des balises meta charset HTML, parfois avec PHP, etc. Bientôt, nous nous sommes retrouvés avec une liste de 600 000 biographies d'artistes, avec les informations codées en double ou triple codage, avec des données stockées de différentes manières, selon qui avait programmé la fonction ou appliqué le patch. Un nid de rat technique classique.
En fait, naviguer dans les problèmes UTF-8 liés à l'encodage des données peut être une expérience frustrante. Cet article fournit un «livre de recettes» concis pour résoudre ces problèmes lorsque vous travaillez avec PHP et MySQL en particulier, basé sur l'expérience pratique et les leçons apprises (et grâce, en partie, aux informations découvertes ici Oui ici en route).
Plus précisément, nous allons couvrir les éléments suivants dans cet article:
La première chose à faire est de modifier votre fichier 'php.ini' pour utiliser UTF-8 comme jeu de caractères par défaut:
default_charset = 'utf-8';
( Remarque: Vous pouvez plus tard utiliser phpinfo () pour vérifier qu'il a été correctement défini ).
Ok maintenant PHP et UTF-8 devraient bien fonctionner ensemble. Vérité?
Eh bien, pas exactement. En fait, ils ne sont même pas près de le faire.
Bien que ce changement garantisse que PHP génère toujours UTF-8 en tant que codage de caractères (dans les en-têtes de type - contenu de la réponse du navigateur), vous devez encore apporter un certain nombre de modifications à votre code PHP, pour vous assurer que les processus et génère correctement les caractères UTF-8 .
En relation: Meilleures pratiques et astuces PHP par les développeurs ApeeScapePour vous assurer que votre code PHP se gère bien dans le bac à sable de codage de données UTF-8, voici ce que vous devez faire:
Définissez UTF-8 comme jeu de caractères pour toutes les sorties d'en-tête par votre code PHP.
Dans chaque en-tête de sortie PHP, spécifiez UTF-8 comme encodage:
en-tête ('Content-Type: text / html; charset = utf-8');
Spécifiez UTF-8 comme type de codage pour XML
function utf8_for_xml($string) { return preg_replace('/[^x{0009}x{000a}x{000d}x{0020}-x{D7FF}x{E000}-x{FFFD}]+/u', ' ', $string); }
Supprimer les caractères non pris en charge de XML
Étant donné que tous les caractères UTF-8 ne sont pas acceptés dans un document XML, vous devez supprimer tout type de caractère de tout XML que vous générez. Une fonction utile pour ce faire (que j'ai trouvée ici) est la suivante:
$safeString = utf8_for_xml($yourUnsafeString);
Voici comment vous pouvez utiliser cette fonction dans votre code:
htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8')
Spécifiez UTF-8 comme jeu de caractères pour tout le contenu HTML
Pour le contenu HTML, spécifiez UTF-8 comme encodage:
default_charset
Dans les formulaires HTML, spécifiez UTF-8 comme encodage:
htmlspecialchars
Spécifiez UTF-8 comme encodage pour tous les appels à htmlspecialchars
Par exemple:
htmlentities
Remarque: Depuis PHP 5.6.0, la valeur mysql_set_charset
est utilisé par défaut. Depuis PHP 5.4.0, UTF-8 est venu par défaut, mais avant PHP 5.4.0, ISO-8859-1 était utilisé par défaut. Par conséquent, c'est une bonne idée de toujours spécifier UTF-8 explicitement, pour être sûr, même si cet argument est techniquement facultatif.
Notez également que, pour UTF-8, $link = mysql_connect('localhost', 'user', 'password'); mysql_set_charset('utf8', $link);
Oui mysql_set_charset
ils peuvent être utilisés de manière interchangeable.
Spécifiez UTF-8 comme jeu de caractères par défaut à utiliser lors de l'échange de données avec la base de données MySQL, en utilisant mysqli::set_charset
:
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'test'); /* check connection */ if (mysqli_connect_errno()) { printf('Connect failed: %s
', mysqli_connect_error()); exit(); } /* change character set to utf8 */ if (!$mysqli->set_charset('utf8')) { printf('Error loading character set utf8: %s
', $mysqli->error); } else { printf('Current character set: %s
', $mysqli->character_set_name()); } $mysqli->close();
Notez qu'à partir de PHP 5.5.0, iconv
est obsolète et iconv_strlen
doit être utilisé à la place:
mbstring
Il existe plusieurs fonctions PHP qui peuvent planter, ou du moins ne pas se comporter comme prévu si la représentation des caractères nécessite plus de 1 octet (comme UTF-8). Un exemple est la fonction strlen, qui retournera le nombre d'octets au lieu du nombre de caractères.
Il existe deux options disponibles pour gérer cela:
Les fonctions [mysql] default-character-set=UTF-8 [mysqld] character-set-client-handshake = false #force encoding to uft8 character-set-server=UTF-8 collation-server=UTF-8_general_ci [mysqld_safe] default-character-set=UTF-8
qui sont disponibles par défaut avec PHP, fournissent des versions multi-octets compatibles de plusieurs de ces fonctions (par exemple, my.ini
, etc.). N'oubliez pas, cependant, que les chaînes que vous fournissez à ces fonctions doivent à leur tour être codées correctement.
Il y a aussi l'extension mysql> show variables like 'char%';
à PHP (des informations sur l'activation et la configuration sont disponibles ici ). Cette extension fournit un ensemble complet de fonctions qui répondent adéquatement à l'encodage multi-octets.
Du côté MySQL / UTF-8, les modifications du fichier my.ini sont requises comme suit:
Définissez les paramètres de configuration suivants après chaque balise correspondante: [client] default-character-set = UTF-8
| character_set_client | UTF-8 | character_set_connection | UTF-8 | character_set_database | UTF-8 | character_set_filesystem | binary | character_set_results | UTF-8 | character_set_server | UTF-8 | character_set_system | UTF-8 | character_sets_dir | /usr/share/mysql/charsets/
Après avoir apporté les modifications ci-dessus à votre fichier set names UTF-8;
, redémarrez le démon MySQL.
Pour vérifier que tout a été correctement configuré pour utiliser le codage UTF-8, exécutez la requête suivante:
comment programmer un robot
sphinx.conf
Le résultat devrait être quelque chose comme ceci:
charset_type = utf-8
Si à la place vous voyez latin1 répertorié pour l'un de ces éléments, vérifiez votre configuration et assurez-vous que vous avez redémarré avec succès le démon MySQL.
MySQL UTF-8 est en fait une implémentation partielle du jeu de caractères UTF-8. Plus précisément, le codage des données MySQL UTF-8 utilise un maximum de 3 octets, tandis que 4 octets sont nécessaires pour coder l'ensemble du jeu de caractères UTF-8. C'est bien pour tous les caractères de la langue, mais si vous devez prendre en charge les symboles astraux (dont les points de code vont de U + 010000 à U + 10FFFF), ils nécessitent un codage à quatre octets qui ne peut pas être pris en charge dans MySQL UTF-8. Dans MySQL 5.5 0.3, cela a été discuté avec l'ajout de la prise en charge des jeux de caractères utf8mb4 , qui utilise un maximum de quatre octets par caractère et prend donc en charge le jeu complet de caractères UTF-8. Donc, si vous utilisez MySQL 5.5.3 ou version ultérieure, utilisez utf8mb4 au lieu de UTF-8 comme jeu de caractères base de données / table / ligne. Plus d'informations disponibles ici.
Si le client qui se connecte n'a aucun moyen de spécifier le codage pour sa communication avec MySQL, une fois la connexion établie, vous devrez peut-être exécuter la commande / requête suivante:
sql_query_pre = SET CHARACTER_SET_RESULTS=UTF-8
Lors de la détermination de la taille des champs varchar lors de la modélisation de votre base de données, n'oubliez pas que les caractères UTF-8 peuvent nécessiter jusqu'à 4 octets par caractère.
Dans le fichier de configuration Sphinx (c'est-à-dire sql_query_pre = SET NAMES UTF-8
):
Définissez votre définition d'index pour avoir:
charset_table
Ajoutez ce qui suit à votre définition de police:
ALTER SCHEMA `your-db-name` DEFAULT CHARACTER SET UTF-8;
mysql> show variables like 'char%';
Redémarrez le moteur et refaites tous les index.
Si vous souhaitez configurer le Sphynx pour que les lettres comme C c ć Ĉ ĉ Ċ ċ Č č soient traitées de la même manière à des fins de recherche, vous devrez configurer a mysqldump -u USERNAME -pDB_PASSWORD --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert DATABASENAME --tables TABLENAME > DUMP_FILE_TABLE.sql
(également connu sous le nom de pliage de caractères) qui est essentiellement un mappage entre les caractères. Plus d'informations sont disponibles ici .
Si vous avez une base de données existante déjà encodée en latin1, je vous montre ici comment convertir latin1 en UTF-8:
Assurez-vous que vous avez effectué toutes les modifications des paramètres de configuration dans votre fichier my.ini, comme décrit ci-dessus.
Exécutez la commande suivante:
mysqldump -u root --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert artists-database --tables tbl_artist > tbl_artist.sql
Via la ligne de commande, vérifiez que tout est configuré correctement pour UTF-8
perl -i -pe 's/DEFAULT CHARSET=latin1/DEFAULT CHARSET=UTF-8/' DUMP_FILE_TABLE.sql
Créez un fichier de vidage en encodage latin1 pour la table que vous souhaitez convertir:
mysql> source 'DUMP_FILE_TABLE.sql';
Exemple:
mysql> select count(*) from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD);
Effectuez une recherche globale et remplacez le jeu de caractères dans le fichier de vidage de latin1 à UTF-8:
Par exemple, en utilisant Perl:
create table temptable ( select * from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD));
Remarque pour les utilisateurs Windows: Cette chaîne de remplacement de jeu de caractères (latin1 à UTF-8) peut également être effectuée en utilisant rechercher et remplacer dans WordPad (ou un autre éditeur de texte, comme vim). Assurez-vous d'enregistrer le fichier tel quel (pas en tant que fichier texte Unicode!).
À partir de ce moment, nous allons commencer à manipuler les données de la base de données, il serait donc probablement sage de faire une sauvegarde de la base de données, si vous ne l'avez pas déjà fait. Ensuite, restaurez le vidage dans la base de données:
alter table temptable modify temptable.ArtistName varchar(128) character set latin1;
Trouvez tous les enregistrements qui n'ont pas été convertis correctement et corrigez-les. Étant donné que les caractères non ASCII sont de par leur conception multi-octets, nous pouvons les trouver en comparant la longueur d'octet à la longueur de caractère (c'est-à-dire pour identifier les lignes qui peuvent contenir des caractères UTF-8 doubles).
Vérifiez s'il y a des enregistrements avec des caractères multi-octets (si cette requête renvoie zéro, alors il ne devrait y avoir aucun enregistrement avec des caractères multi-octets dans la table et vous pouvez passer à l'étape 8).
ArtistName
Copiez les lignes avec des caractères multi-octets dans une table temporaire:
alter table temptable modify temptable.ArtistName blob; alter table temptable modify temptable.ArtistName varchar(128) character set UTF-8;
Convertit les caractères UTF-8 à double codage en caractères UTF-8 appropriés.
C'est en fait un peu délicat. Une chaîne à double codage est une chaîne qui a été correctement codée en UTF-8. Cependant, MySQL nous a alors fait une mauvaise faveur en le convertissant (de ce qu'il pensait être latin1) à nouveau en UTF-8, lorsque nous avons défini la colonne sur le codage UTF-8. Résoudre ce problème nécessite donc un processus en deux étapes par lequel nous «trichons» MySQL afin de l'empêcher de nous faire cette «faveur».
Tout d'abord, nous redéfinissons le type d'encodage de la colonne sur latin1, éliminant ainsi le double encodage:
Exemple:
delete from MY_TABLE where LENGTH(MY_FIELD) = CHAR_LENGTH(MY_FIELD);
Remarque: Assurez-vous d'utiliser le type de champ correct pour votre table. Dans l'exemple ci-dessus, pour notre table, le type de champ correct pour replace into MY_TABLE (select * from temptable);
était varchar (128), mais le champ de la table pouvait être du texte ou tout autre type. Assurez-vous de le spécifier correctement.
Le problème est que maintenant, si nous remettons le codage de colonne sur UTF-8, MySQL exécutera à nouveau le codage de données latin1 en UTF-8, et nous reviendrons là où nous avons commencé. Pour éviter cela, le type de colonne est changé en blob, puis défini sur UTF-8. Cela exploite le fait que MySQL n'essaiera pas d'encoder un objet blob. Et ainsi, nous pouvons «tricher» la conversion du jeu de caractères MySQL, pour éviter le problème de double encodage.
Exemple:
|_+_|
(Encore une fois, comme indiqué ci-dessus, veillez à utiliser le type de champ approprié pour votre table.)
Supprimez les lignes contenant uniquement des caractères à un octet appartenant à la table temporaire:
Réinsérez les lignes fixes dans la table d'origine (avant de faire cela, vous devez exécuter des sélections sur la table temporaire pour vérifier qu'elle a été correctement corrigée, par précaution).
|_+_|
Une autre chose à retenir et à vérifier est que les fichiers de code source, les fichiers de ressources, etc., sont correctement enregistrés avec le codage de données UTF-8. Sinon, tous les caractères 'spéciaux' de ces fichiers risquent de ne pas être traités correctement.
Dans Netbeans, par exemple, vous pouvez faire un clic droit sur votre projet, sélectionner les propriétés puis sous 'Sources' vous trouverez l'option d'encodage des données (généralement par défaut c'est UTF-8, mais il vaut mieux vérifier).
Ou dans le Bloc-notes Windows, utilisez l'option 'Enregistrer sous ...' du menu Fichiers et sélectionnez l'option d'encodage UTF-8 en bas de la boîte de dialogue. (Notez que l'option 'Unicode' proposée par le Bloc-notes est en fait UTF-16, et ce n'est pas ce que vous voulez.)
Bien que cela puisse être quelque peu fastidieux, prendre le temps de revoir ces étapes pour résoudre systématiquement vos problèmes d'encodage de données MySQL et PHP UTF-8 peut vous faire gagner beaucoup de temps. À long terme, ce type d'approche méthodique est bien supérieur à la tendance courante à réparer le système.
J'espère que ce guide souligne l'importance de considérer la définition de l'ensemble de données lors de la configuration initiale d'un environnement de projet et de travailler dans un environnement de projet logiciel qui prend en compte le codage de caractères dans sa manipulation de texte et de chaînes.
En relation: Avant de déboguer PHP qui ne fonctionne pas, consultez la liste des 10 erreurs les plus courantes commises par les développeurs PHP (avant de déboguer PHP qui ne fonctionne pas, consultez cette liste des 10 erreurs les plus courantes commises par les développeurs PHP)