Diakritische tekens, PHP en MySQL

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Paul Ulje

Paul Ulje

15/02/2018 15:02:12
Quote Anchor link
Ik heb hierop gezocht in dit forum en alleen iets over het verbod op accent-tekens in @dressen gevonden. Wellicht kunnen jullie me op weg helpen.

Mijn hosting provider heeft gemorreld aan de MySQL installatie.
Dat merkte ik omdat op al mijn sites de diakritische tekens verhaspeld werden tot onleesbare teken-reeksen.
Iets dat schering en inslag is op het internet maar vooral bij de papieren mailbedrijven.
Zodat bijvoorbeeld de @post van een winkel wél goed aankomt maar de papieren versie niet.

Voorbeelden van de afgelopen twee dagen in mijn @bus zie je hier:
http://www.ulje.nl/diakritisch.pdf
Zoals je ziet lijdt ook dit forum, of liever de reclame van Monsterboard, aan het probleem.

Ik heb het kunnen corrigeren door de UTF8 instelling te negeren en in mijn openDB() procedure het oude latin in te stellen.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
  
function openDB($table = DB_NAME) {
    $db = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, $table);
    $db->set_charset('latin1');
    $db->query("SET collation_connection = latin1_swedish_ci");
    return $db;
}


Maar de echte vraag is natuurlijk:
Hoe komt het dat het zo vaak mis gaat en wat is nu de echte oplossing (die mijn hostingprovider ook niet kon vinden...)
Gewijzigd op 15/02/2018 15:24:10 door Paul Ulje
 
PHP hulp

PHP hulp

25/04/2024 02:10:24
 
Thomas van den Heuvel

Thomas van den Heuvel

15/02/2018 15:48:55
Quote Anchor link
Het probleem is waarschijnlijk dat je data dubbel utf8-ge-encodeerd in je database zit doordat je deze in je database hebt gezet zonder aanduiding van een character encoding. Deze is standaard meestal latin1. De tabellen die je gebruikte hebben naar alle waarschijnlijkheid een andere character encoding, mogelijk utf8.

MySQL is zelf redelijk slim. Als deze ziet dat de character encoding waarmee je een verbinding maakt latin1 is en de tabel waarin je informatie wilt wegschrijven utf8 is dan zal deze een vertalingsstap latin1->utf8 van de data automatisch uitvoeren. Omgekeerd, op het moment dat je data uitleest middels een latin1 data-connectie en de tabellen bevatten utf8-data (of liever gezegd, hebben een utf8-tabel- of kolom-aanduiding), dan zal MySQL proberen om -voor zover dat mogelijk is sinds latin1 een veel beperkter karakter repertoir heeft- zaken terug te vertalen.

Maar mogelijk was de data die je aanleverde al utf8. Wat gebeurt er dan als je deze data via een latin1-verbinding wegschrijft? Deze wordt nogmaals utf8-ge-encodeerd. Lees je deze data weer uit, dan wordt die om eerdergenoemde reden weer terugvertaald naar "latin1", waarbij dus effectief de dubbele encoding ongedaan wordt gemaakt. Als je dan vervolgens op de juiste manier een verbinding maakt met je database dan vindt deze dubbele encoding bij wegschrijven en decodering bij ophalen niet meer plaats. Met als gevolg dat het op dat moment evident wordt dat de reeds weggeschreven data corrupt c.q. dubbel ge-encodeerd is.

Long story short, naar alle waarschijnlijkheid is de data in je database gewoon corrupt. Of corrupt is misschien een zwaar woord, de data is verkeerd ge-encodeerd. Dit zou je na kunnen gaan door dezelfde data eens weg te schrijven naar de database, maar dan op de goede manier en dan de HEX()es van deze data met elkaar te vergelijken. Dit alles staat beschreven in een artikeltje van mij (tweede deel), met tevens een mogelijk reparatie. Maar eerst zul je héél goed moeten analyseren wat er precies aan de hand is.

Maar om ook even een misverstand uit de wereld te helpen: De methode set_charset() moet je zien als een contract tussen jou en je database waarin jij in feite zegt "dit is de character encoding waarin ik data wil weergeven en dit is tevens de character encoding waarin ik informatie aanlever". MySQL doet de rest en voert zonodig vertalingen uit maar het is natuurlijk beter dat alle character encoderingen gelijk geschakeld zijn, oftewel:
- de manier waarop je fysieke documenten (met mogelijk statische HTML met exotische karakters) opslaat, gebruik een editor die UTF-8 encodering ondersteund
- de header() of meta-tag in je documenten (of een andere manier van aanduiding welke character encoding je gebruikt wanneer je bijvoorbeeld PDF-documenten bakt)
- de connectie met je database, in te stellen via set_charset()
- de tabel- en kolomdefinities
- en last but not least, de DATA in de tabellen zelf

Voor dit laatste dien je zelf zorg te dragen, MySQL kan alleen maar data aannemen (letterlijk en figuurlijk) in de vorm die jij zegt waarin deze aangeleverd wordt, voor MySQL zijn het enkel nullen en enen, de character encoding bepaalt vervolgens hoe deze nullen en enen gerepresenteerd worden.

En ja, deze site laat ook te wensen over als het om character encoderingen gaat :p.
Gewijzigd op 15/02/2018 17:59:47 door Thomas van den Heuvel
 
Paul Ulje

Paul Ulje

15/02/2018 21:02:46
Quote Anchor link
Dank je Thomas, je had er zin in :-)

Ik zal het nog een keer moeten lezen, even moeten laten bezinken en wat gaan uitproberen.
Op mijn leeftijd laat de opnamesnelheid wat te wensen over....
Het principe lijkt me wel duidelijk.

Een paar dingetjes had ik al geprobeerd.
Toen ik het 'probleem' ontdekte heb ik natuurlijk direct MySQL bekeken op de host en vergeleken met mijn locale server. Allebei via phpMyAdmin.

- beiden, zelfde versie, mijn locale met de default configuratie van XAMP.
- beiden melden als UTF8 gecodeerd.
- in beiden ogen de accenttekens in de data correct.
- van beiden backup geeft in txt, extended ascii, de correcte data. Alle accenten daar waar ze horen.
- invoer, ook vanaf de backup, gaf en geeft in beiden het goede resultaat via phpMyAdmin en backup in extended ascii.
- uitvoer geeft locaal nog steeds het juiste resultaat.
- geknoeid met de character codering van db, table en velden, maar er wilde maar geen fout resultaat uitkomen (over slimme MySQL gesproken!)
- alleen de host geeft dus sinds de 'beveilingsupdate' verhaspelde uitvoer. (é erin, staat er ook in, Á© eruit)

Mijn lekenconclusie luidde, en je zinspeelt er al op:
- de oorspronkelijke codering was (wellicht bij toeval) correct voor in- en uitvoer.
- de 'gewijzigde' coderingsinstelling op de host voor (alleen de?) uitvoer is onjuist, in elk geval voor de scripts die ik draai.

Uitgaande van het laatste 'forceer' ik nu in elk geval de uitvoer (ook de invoer?) (en wellicht dubbel) van de host.
En mijn gegevens zijn in goede staat bewaart gebleken.
Alles komt alvast van de host weer zoals het was en nog steeds is op de locale server.
Maar gezien je verhaal lijkt zekerheid daarover nog twijfelachtig.

Dumpen in hex en dan eens goed puzzelen. Ga ik zeker doen.

Nogmaals dank!

Paul UljÁ© :-)
 
Thomas van den Heuvel

Thomas van den Heuvel

16/02/2018 00:38:33
Quote Anchor link
> nog wat leesvoer

Zoals in het artikel waar ik naar verwees in mijn vorige bericht staat beschreven kun je tevens zowel aan de MySQL-kant (via HEX()) en aan de PHP-kant van het verhaal (met bin2hex()) kijken of er tussendoor vertalingen zijn uitgevoerd bij het ophalen van de data. Maar daar is vrijwel zeker sprake van als je een verbinding maakt met latin1 en de tabel- of kolomdefinities utf8 (of een variant hiervan) zijn.

In principe maakt het eigenlijk helemaal niet uit wat voor waarde je in set_charset() gebruikt, zolang de documenten waarin je database-data weergeeft maar deze gekozen character encoding reflecteren en ervoor zorgt dat alle data die je vervolgens op deze manier aanbiedt aan je database ook echt overeenstemt met deze gekozen character encoding. Dus zolang er wordt voldaan aan de voorwaarden van het eerdergenoemde contract mag de character encoding waarin je dingen weergeeft best afwijken van de character encoding waarin je dingen opslaat. Dit is natuurlijk niet echt een optimale situatie, maar het kan.
 
Paul Ulje

Paul Ulje

17/02/2018 13:52:57
Quote Anchor link
"> nog wat leesvoer"
Fijn, ik begon me al te vervelen :-)

Weet jij hoe het komt dat briefmailings bijna standaard mis gaan.

Ik stel me zo voor:
- de opdrachtgever slaat een selectie van zijn klanten op in een tabel (of backup txt bestand?)
- die tabel stuurt hij naar het mailbedrijf
- dat mailbedrijf drukt die gegevens (onjuist) af op de envelop.

ALS dat zo gaat, EN de codering deugt vaak niet, DAN missen veel mailbedrijven de juiste coderingsgegevens.

Hoe zou jij dat als mailbedrijf aanpakken?

grt. Paul
 
Thomas van den Heuvel

Thomas van den Heuvel

17/02/2018 15:49:25
Quote Anchor link
Stel wederom een contract op :).

Oftewel, maak afspraken over de vorm waarin data wordt aangeleverd.

En hoe dit kan ontstaan: dit kan echt van alles zijn, maar het komt waarschijnlijk neer op een gebrek aan duidelijkheid over hoe er gecommuniceerd wordt, wat ruimte openlaat voor onjuiste interpretatie.

Immers, There Ain't No Such Thing As Plain Text. ALLE vormen van tekst hebben een character encoding. Het probleem is vaak dat deze realisatie nog niet overal of nog niet helemaal (of helemaal niet :/) is bezonken. Bij een mailbedrijf lijkt mij dat redelijk funest.
 
Paul Ulje

Paul Ulje

10/04/2018 01:54:38
Quote Anchor link
"Bij een mailbedrijf lijkt mij dat redelijk funest."

Ja, dat is wat ik dagdagelijks merk in de post :-)
En ik vraag me af waarom het voor een mailbedrijf niet mogelijk is om automagisch te achterhalen wat de juiste codering van de aangeleverde tabel is.
Daar valt dus wat te verbeteren voor een PHP magister.... :-)

Sorry voor deze late reactie, dank voor je hulp!

grt. Paul Ulj€¼ƒ
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.