Mon problème initial est de migrer une application web mysql-php depuis une configuration sous Windows avec WAMP vers une configuration sous un serveur linux (Ubuntu) avec LAMP (Apache MySql PHP5).

La base de donnée MySql de départ contient du texte codé en ISO-8859-1... mais pas seulement ! Le site utilisant des éditeurs différents (plain text, CKEditor), il y a aussi des caractères diacritiques non encodés telle que : &eacute, &agrave ...

Liens rapides :

 

L'encodage (charset) sur un serveur web intervient à de multiples endroits :

Je nommerai par la suite cette succession par la "chaîne d'échanges"

  • Le système d'exploitation
  • Le service Apache2
  • Le service MySql, la base de donnée, ses tables, son contenu
  • Le service PHP, les fonctions utilisé par ce dernier.
  • Les pages XHTML, celle-ci pouvant être définies par le code PHP.

Sur le client, si tout est bien fait du côté serveur, votre navigateur récupère le charset dans la page XHTML. Le changement d'encodage à ce niveau n'a d'intérêt que de mieux compendre les erreurs sur la page finale.

Il est à noter que pour nous français, que ce soit en UTF-8, en ISO-8859-1 ou 15 ou encore en CP1252, dans tous les cas, les codes par exemple de àèé sont respectivement 0xE0 (224), 0xE8 (232) et 0xE9 (233), mais que là où les trois derniers codages les codent sur un octet, l'UTF-8 les code sur 2 octets tel que U+00E0 ... ce U d'Unicode ce traduit par le code c3 dans les données (un éditeur héxadécima, vim fait l'affaire, ou frhed sous Windows)

 

Charset Apache2

le fichier /etc/apache2/apache2.conf ne contient rien sur l'encodage.

le fichier /etc/apache2/conf-available/charset.conf contient lui #AddDefaultCharset UTF-8 et comme on peut le voir désormais désactivé par défaut (Ubuntu Trusty - Apache 2.4.7)

 

Charsets MySql

J'ai bien mis à un s au titre de paragraphe ci-dessus. En effet, c'est une part importante du codage dans la chaîne des échanges !

L'utilisation de phpmyadmin est à éviter pour travailler notre sujet. En effet l'affichage est passé par toute la chaîne d'échanges. Il faut donc ouvrir un terminal :

mysql -u root -p
mysql> use mabasededonnees
mysql> SHOW VARIABLES LIKE 'char%' (les majuscules ne sont pas indispensables)

qui doit vous retourner quelque chose comme :

+----------------------------+--------------------------+
| Variable_name              | Value                    |
+----------------------------+--------------------------+
| character_set_client       | utf8 |
| character_set_connection   | utf8 |
| character_set_database     | latin1 |
| character_set_filesystem   | binary |
| character_set_results      | utf8 |
| character_set_server       | latin1 |
| character_set_system       | utf8 |
+----------------------------+--------------------------+

On voit que notre base et notre service MySql utilise non pas l'UTF-8 mais le latin1 (ou ISO-8859-1)

Pour basculer le character_set_server à UTF-8, suivre les instructions ci-dessous, extraite de https://dev.mysql.com/doc/refman/5.5/en/charset-connection.html

dans le fichier /etc/mysql/my.cnf :
dans la section [mysqld], ajouter les lignes ci-dessous:

collation_server=utf8_unicode_ci
character_set_server=utf8

non nécessaire : skip-character-set-client-handshake

Redémarrer le service apache2 :  sudo service mysql restart

Si la base de donnée est déjà existante voici des requêtes pour en modifier les paramètres (extraite du site http://openweb.eu.org/articles/changer_pour_utf8) :

ALTER DATABASE mabasededonnees CHARACTER SET UTF8;
ALTER TABLE matable CHARACTER SET UTF8;
ALTER TABLE matable CONVERT TO CHARACTER SET UTF8;

 en revanche, cela ne modifie pas le contenu existant ! Peut-être suis-je passé à côté de la bonne fonction, mais le seul moyen que j'ai trouvé, c'est :

  • d'extraire la(les) table(s)
  • de les convertir en utf8 avec iconv ou notepad++ : cf. § Conversion d'une base existante sur http://www.windowslinux.net/encodage
  • de les insérer dans la nouvelle base si changement de serveur comme mon cas, ou de faire un "replace" sur la base existante

Le tableau des variables de MySql doit être maintenant :

+----------------------------+----------------------------+
| Variable_name             | Value                     |
+----------------------------+----------------------------+
| character_set_client       | utf8                       |
| character_set_connection   | utf8                       |
| character_set_database     | utf8                       |
| character_set_filesystem   | binary                     |
| character_set_results      | utf8                       |
| character_set_server       | utf8                       |
| character_set_system       | utf8                       |
| character_sets_dir         | /usr/share/mysql/charsets/ |
+----------------------------+----------------------------+
8 rows in set (0.00 sec)

 

Charset PHP5/PHP7

Sur les sites dynamiques, les pages HTML/XHTML sont créés dynamiquement par le code PHP ou autre langages. Il doit créer ces pages avec le bon charset.

Pour cela, il suffit d'utiliser la commande, au début de vos codes php :

header('Content-type: text/html; charset=utf8');

La modification de default_charset = "UTF-8" du fichier /etc/php5/apache2/php.ini ou /etc/php/7.0/apache2/php.ini n'est pas nécessaire, pas plus, semble-t-il que les iconv.input_encoding et compagnie (section [iconv] ) ni le mssql.charset ou encore le mbstring.internal_encoding ou mbstring.http_input (section [mbstring] )

Enfin, toujours dans le php.ini et comme pour les paramètres ci-dessus, le site http://www.windowslinux.net/encodage recommande de modifier la ligne:

mbstring.func_overload = 7 cela fonctionne aussi très bien dans mon cas en la laissant à 0.

pour plus d'infos et notamment la dépréciation des variables ci-dessus avec php5.6 et supérieur : https://wiki.php.net/rfc/default_encoding

En revanche, il m'a fallu modifier le code php qui ouvre la base de donnée : 

...
$host = "localhost";
$dbname = "nom_de_ma_base"; $charset = "utf8";
$dsn = "mysql:host=".$host.";dbname=".$dbname.";charset=".$charset; if(!$dhb) {
$dbh = new PDO($dsn, $username, $password);
}

 

Basculement final

Attention à ce qu'on met dans notre nouvelle base de donnée.

Pour finaliser mon basculement ou migration du serveur WAMP à mon nouveau LAMP, il faut exporter les tables du premier puis les importer sur le second.

Je me connecte au phpmyadmin du WAMP:

Lancer un export de la base : sélectionner Custom,

S’il n’y a plus que les "articles" et la liste de fichiers attachés à transférer (si on n’a déjà transféré le tout), on peut, dans la section  Table(s) : cliquer Unselect All puis sélectionner les tables nécessaires,

puis Character set of the file : laisser utf-8 (par défaut). Dans la rubrique Format-specific options: Dump table, cocher Data … cela évite de récupérer d'éventuel CREATE avec un DEFAULT CHARSET avec un autre charset

Dans la rubrique Data dump options, Function to use when dumping data : REPLACE au lieu de INSERT

Cliquer le bouton Go en bas du formulaire.

Lors du passage d'un serveur sous windows qui ignore la casse vers un serveur Linux qui la respecte, il peut-être necessaire d'adapter les noms des tables, cf. mon article sur vim

Il reste à importer dans la nouvelle base. Pour d'éventuels fichiers joints aux articles, il faut monter un partage du windows sur le linux, et lancer un rsync…

Des liens

qui m'ont été utiles mais certaines infos sont néanmoins obsolètes (notamment sur AddDefaultCharset ) :

Une page de forum sur cette problématique

http://forum.alsacreations.com/topic-3-57026-1-Convertir-BDD-mysql-de-ISO-a-UTF-8.html

Changer de jeu de caractères pour UTF8 :

http://openweb.eu.org/articles/changer_pour_utf8

les problèmes d'affichage, le charset à différents niveaux ....

http://windowslinux.net/encodage