Diakritische tekens worden opeens vraagtekens
Ik heb een website met grote database.
- Apache
- Clientversie van database: libmysql - 5.5.68-MariaDB
- PHP-uitbreiding: mysqli Documentatie
- PHP-versie: 5.4.16
Deze draait prima, maar binnenkort moet de website verhuizen naar een nieuwere server.
Ik heb een exacte kopie van de database op de nieuwe server gezet. Daar zijn de eigenschappen:
- Apache
- Cliëntversie van database: libmysql - mysqlnd 8.0.30
- PHP-uitbreiding: mysqli Documentatie curl Documentatie mbstring Documentatie
- PHP-versie: 8.0.30
Iets wat op de oude server prima werkt, gaat op de nieuwe fout.
In sommige tabellen komen letters met accenten voor, zoals in het woord "één". Deze speciale tekens staan in de database ook werkelijk als é opgeslagen (en niet met de html-code é).
Op de huidige (oude) website worden de speciale tekens keurig afgebeeld.
Op de nieuwe website veranderen deze tekens in een zwart vierkantje met een wit vraagteken erin.
DATABASE (oud en nieuw):
- Collatie van de serververbinding: utf8mb4_unicode_ci
- Collatie van de database: latin1_swedish_ci
- alle tekstvelden in een tabel: Collatie latin1_swedish_ci
In de html-header van de website (oud en nieuw):
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
Een veel gehoorde tip (ook op dit forum) is: je moet alles instellen op UTF-8 en dan komt dit probleem niet voor.
Maar voordat ik me in dat soort veranderingen stort, zou ik willen weten waarom ik op de oude website met dezelfde instellingen de juiste tekens zie en op de nieuwe website niet.
Is er ergens een instelling voor de nieuwe server/database, die ervoor kan zorgen dat de é uit de database ook weer een é op de website wordt? Dat zou mij enorm helpen.
Gaat het om content uit een database? Of om hardcoded content met een é in een echo bijvoorbeeld?
Tekst die in de database is opgeslagen en die op de website moet verschijnen.
Gebruik je ook een characterset bij de connectie met je database?
En dit in de webpagina :
Je kan er de hele unicode tekenreeks in kwijt.
https://en.wikipedia.org/wiki/List_of_Unicode_characters
En ja, ook daar wil ik ook komende tijd naar kijken voor PHPhulp. Wat volgens mij niet veel moeite lijkt te zijn.
Gewijzigd op 27/03/2024 22:10:33 door - Ariën -
- Ariën - op 27/03/2024 22:07:36:
Waarom zou je eigenlijk nog op de oude iso-8859-1-characterset en de collatie latin1_swedish_ci willen blijven leunen?
Er staat heel veel content in de database. Dat bouw je niet zomaar even om.
De oude php5 en oude server konden er fantastisch mee uit de voeten. Dan moet het toch een setting zijn die bij php8 en de nieuwe server hetzelfde effect geven?
Als ik zoek op internet naar 'iso to utf-8 converter' kom ik wel wat scripts tegen. Ik heb op mijn laptop ook een dergelijk script liggen die ik ooit met succes gebruikt heb.
Als ik tijd vind zal ik het morgen of eerdaags even in de Scripts-sectie plaatsen.
Maar in dit topic vind je vast goede tips:
https://www.phphulp.nl/php/forum/topic/overstap-van-iso88591-naar-utf8/102227/
Ga je er mee spelen: MAAK BACKUPS!
Bij sterke voorkeur in een testomgeving.
Ik zie wel verschillen in je database versie, en het gebruik van de oude PHP 5. Misschien dat daar ergens net iets anders werkt in combinatie van door jouw gebruikte functies? Maar stap gewoon meteen over naar UTF-8.
Gewijzigd op 28/03/2024 00:17:06 door - Ariën -
- Ariën - op 27/03/2024 22:07:36:
Waarom zou je eigenlijk nog op de oude iso-8859-1-characterset en de collatie latin1_swedish_ci willen blijven leunen?
Goede vraag. Voordelen:
- alle 'string'-functies werken dan, omdat die stiekem op byte-level werken
- je kunt 'gewoon' met de byte index van een array werken om karakters aan te wijzen
- het is sneller
- je hebt geen extensies nodig
- je hoeft je niet bewust te zijn van hoe Unicode en UTF-8 werkt, je kunt je niet vergissen
MV Tol op 27/03/2024 19:32:18:
Is er ergens een instelling voor de nieuwe server/database, die ervoor kan zorgen dat de é uit de database ook weer een é op de website wordt?
Nee, die is er niet.
Het traject PHP tot en met de browser bestaat uit vele instellingen.
Omdat UTF-8 de standaard is in PHP sinds versie 5.x (kennelijk was het nog niet versie 5.4) is de tutorial over Unicode slechts gedeeltelijk van toepassing.
Let wel: de standaard van HTML5 is Unicode (UTF-8) en die van JavaScript ook (UTF-16). Maar dat neemt niet weg dat browsers ook gewoon SBCS ondersteunen.
Ik kan op dit moment een weloverwogen gok doen wat er mis gaat. Wanneer de browser een blokje met een vraagteken weergeeft, dan is dat het Replacement karakter. Wanneer de browser de pagina zou renderen met de juiste encoding, zou dat karakter niet verschijnen. Ofwel, de browser denkt dat je website in Unicode staat. Dat kan komen wanneer je HTTP-header van de webserver zegt dat je pagina Unicode is.
Mocht je tegen meer problemen aanlopen, check dan je php.ini in de sectie van mbstring (die op je nieuwe server staat). Het gaat om deze instellingen:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
[mbstring]
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none;
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none;
Zie voor de details:
- https://www.php.net/manual/en/mbstring.http.php
- https://www.php.net/manual/en/mbstring.configuration.php
Code (php)
1
2
3
4
2
3
4
<?php
$string = mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string));
var_dump(htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8'));[/code]
$string = mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string));
var_dump(htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8'));[/code]
Dat bracht mij op deze pagina:
https://www.php.net/manual/en/function.mb-detect-encoding.php
Voor deze test heb ik in de database deze onzinnige tekst met veel accenttekens opgeslagen:
reële reçu's à la café.
Ik haal de tekst op met php:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
$query = "SELECT `tekst` FROM `tabelnaam` WHERE `id` = 3756";
$res = mysqli_query($db_conn, $query);
while ($tabel = mysqli_fetch_array($res))
{
$tekst = $tabel['tekst'];
}
$res = mysqli_query($db_conn, $query);
while ($tabel = mysqli_fetch_array($res))
{
$tekst = $tabel['tekst'];
}
Als ik hierop deze test loslaat:
Code (php)
1
2
2
var_dump(mb_detect_encoding($tekst, ['ASCII', 'UTF-8', 'ISO-8859-1'], false));
var_dump(mb_detect_encoding($tekst, ['ASCII', 'UTF-8', 'ISO-8859-1'], true));
var_dump(mb_detect_encoding($tekst, ['ASCII', 'UTF-8', 'ISO-8859-1'], true));
is het resultaat:
ISO-8859-1
ISO-8859-1
Er is dus wel ISO-chocola van te maken.
Het blijkt inderdaad mogelijk om de als UTF-8 geïnterpreteerde tekst te presenteren als ISO-8859-1.
Het volgende php-script beeldt de opgehaalde tekst op twee manieren af: de verminkte (met vraagtekens) en de gecorrigeerde versie:
Code (php)
1
2
3
4
2
3
4
print $tekst;
print "<br/>";
print mb_convert_encoding($tekst, 'UTF-8', 'ISO-8859-1');
Dit geeft als output:
re?le re?u's ? la caf?
reële reçu's à la café
Om de iso-teksten te corrigeren, is de volgende functie iso() de oplossing:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
function iso($data)
{
$data = mb_convert_encoding($data, 'UTF-8', 'ISO-8859-1');
return $data;
}
Hiermee kan ik verder, denk ik. Ik zocht immers naar een hulpmiddel om de correct gespelde tekst uit de database ook correct op het scherm te krijgen.
Allemaal bedankt voor jullie suggesties.
Voor hetzelfde is dat niet op al je teksten van toepassing,
of voer je straks op je nieuwe server teksten als iets anders dan iso-8859-1 toe.
Ik bouw nog een controle in, in de functie iso(), gebaseerd op de proef met var_dump, die ik gebruikte om vast te stellen dat de tekst ISO-8859-1 was.