Vandaag nog maar eens tegen het eeuwige charset probleem aangelopen. Sinds enige tijd staat de site van de Culture Club op een server in ons beheer, in opdracht van een klant van ons. De site werd ontwikkeld door Milk & Cookies, een bende prettig gestoorde designers. Bij de migratie van de database naar de nieuwe machine (vanaf een machine die niet in ons beheer had, en waar we geen toegang tot hadden) moesten we een dump krijgen van de designers. We kregen de file in onze mailbox, en deze moest in de MySQL database gezet worden.
Om alles nog wat complexer te maken werkt de site op de Macromedia (ondertussen Adobe) Coldfusion MX 7 server, aangezien het een coldfusion site is. CMX7 is een Java-gebasseerde application server, die een eenvoudige scripting toelaat, zonder al te veel problemen (of mogelijkheden) te hebben met connecties en zo. De site administrator dient dit in te stellen in het administration panel.
Na enige tijd kregen we melding dat er vreemde karakters in enkele entries zaten, en dat deze niet goed weergegeven werden op de site. Er waren ondertussen nieuwe entries toegevoegd, en ook deze waren niet goed. Echter, in phpMyAdmin op de server, die niet door de CMX7 server werd afgehandeld, maar rechtstreeks door Apache/PHP, bleek het enkel de oude entries te zijn die verkeerd weergegeven waren, en niet de nieuwe. Deze waren goed. Er waren 3 stappen in het spel:
- De gedumpte file die we origineel hadden
- De database server zelf. Deze stond in latin1.
- Coldfusion MX7
Enig zoekwerk leverde me volgende zekerheid: Als CMX7 niets anders verteld wordt, werkt die in UTF8. Dat stemde ook overeen met het feit dat mijn Firefox elke pagina in UTF-8 weergaf, ondanks de “charset=iso-8859-1″ melding bovenaan de pagina. Een UTF-8 pagina geeft als eerste byte een speciaal karakter mee, zodat deze herkend kan worden.
Eerst en vooral heb ik de database omgezet naar UTF-8. Eerst en vooral een dump van de database nemen, en dan met enkele welgeplaatste “ALTER TABLE xxx DEFAULT CHARACTER SET = utf8″ commando’s de definities omgezet naar UTF8. Daarmee was mijn data echter nog niet in UTF8, ik wist zelfs niet wat het wel was.
De juiste codepagines vinden was niet zo een groot probleem. Via een pagina die ik vond op het internet, kon ik vinden welke sequence aan een bepaalde charset gekoppeld was. (Om te volgen, scroll helemaal naar onderen, bij het Euro symbool) Via een mysqldump (met default-charset=latin1, want mijn data was nog latin1), kreeg ik onderstaande voor de oude data:
Ik wist dat het een euro symbool moest zijn, en helemaal onderaan de pagina zien we dat de “E2 82 AC” sequence dus UTF-8 data is, en het eurosymbool voorstelt. Let er echter op dat we dit gedumpt hadden in latin1. Dat was dus gewone UTF8-data.
De nieuwe data gaf dit:
Een karakter met waarde “80″. Dit moest ook terug een Euro-symbool zijn. We zien dat ASCII 80 in verschillende codepages het eurosymbool is. De tweede deed een belletje rinkelen (codepage 1252 dus), want dit is de standaard Windows codepage.
De oude data kon dus via volgende commando’s hersteld worden (gewoon als latin1 dumpen, en als utf8 terug inladen, aangezien de data wel goed was):
mysqldump --set-default-charset=latin1 database tabelnaam > file
mysql --set-default-charset=utf8 database < file
Vreemd genoeg kreeg ik het nog altijd niet goed op de webpagina. Maar dat is voor later.
De nieuwe data heb ik via iconv omgezet:
iconv -f CP1252 -t UTF-8 tabeldump > tabeldump.utf8
Een snelle blik gaf me zekerheid dat het “80″ controlekarakter omgevormd was tot “E2 82 AC” waar er een Euro moest staan. Zover waren we al. Met wat scripting dan de boel gedumpt, de oude van de nieuwe data gescheiden, de nieuwe omgezet, en beide terug ingeladen.
Dubbel gecontroleerd dat alles van de database standaard op utf8 stond:
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
UTF-8-er kan niet denk ik. Dan was er nog het probleem dat de data natuurlijk niet goed weergegeven werd. Elk controlekarakter werd nogmaals in UTF-8 ge-encodeerd (dus, utf-8 op reeds utf-8 data). Ik vermoedde dat de database connectie in CMX7 niet heel zuiver was, en heb een testopstelling gemaakt. Een nieuwe database met dezelfde data, maar deze keer met de JDBC connector van MySQL ipv de standaard driver in Coldfusion. Deze pagina geeft weer hoe je deze kan installeren en testen in coldfusion. Snel een coldfusion testpagina gemaakt, en het leek te werken. Dan een pagina van de site van de Culture club waar het fout liep omgebouwd zodat deze de nieuwe datasource gebruikte, en alles bleef werken.
Uiteindelijk de datasource aangepast naar de nieuwe datasource, en alles lijkt nu perfect te werken.
Charsets zijn echt wel een “p**n in the ass”.