Bestandsnamen zoeken in databank
Elke $entry wil ik controleren in een databank. Dat werkt behalve als er speciale karakters in de bestandsnaam voorkomen: AdigûzelElbinur21.03.2001.jpg, TruöngNgoc Mai13.09.2009.jpg, ...
Er zit dus iets niet juist met de encoding van de bestanden vs. de databank. De databank staat volledig in utf8_general_ci. Ik ga zoeken in een view die twee tabellen via union samenvoegt.
Als ik met mb_detect_encoding kijk, dan zie ik dat de bestandsnamen ook in utf8 staan.
Het script draait op een Centos 7 server met PHP versie 7.3.9.
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
while (false !== ($entry = readdir($handle))) {
if($entry !=='.' && $entry !=='..' && $entry !== '__MACOSX'){
echo "<div class=\"bold\">$entry</div>";
$sqlentry = mysqli_real_escape_string($link, $entry);
$query = "select pointer from vwLeerlingenFotosNaarSmartschool where zoekstring = '$sqlentry'";
}
}
if($entry !=='.' && $entry !=='..' && $entry !== '__MACOSX'){
echo "<div class=\"bold\">$entry</div>";
$sqlentry = mysqli_real_escape_string($link, $entry);
$query = "select pointer from vwLeerlingenFotosNaarSmartschool where zoekstring = '$sqlentry'";
}
}
Ik heb ook getest door alle namen vanuit de databank eerst in een array te stoppen.
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
$query = "select distinct pointer from vwLeerlingenFotosNaarSmartschool";
$result = mysqli_query($link, $query);
$arr_pointer = array();
while($row = mysqli_fetch_assoc($result)){
$pointer = $row['pointer'];
$arr_pointer[$pointer] = $row['zoekstring'];
}
$result = mysqli_query($link, $query);
$arr_pointer = array();
while($row = mysqli_fetch_assoc($result)){
$pointer = $row['pointer'];
$arr_pointer[$pointer] = $row['zoekstring'];
}
Ik gebruik daarna in_array of array_search om te zoeken maar ook daar werkt dat niet bij de speciale gevallen.
Hoe kan ik er voor zorgen dat de strings in de array (of de databank) toch matchen met de strings die ik uit het bestandssysteem ophaal?
Gewijzigd op 01/10/2019 11:53:12 door Geert Huylebroeck
Zou je de code tussen code-tags kunnen plaatsen?
Geert Huylebroeck op 01/10/2019 11:25:13:
De databank staat volledig in utf8_general_ci.
Maar dat is een collation, niet een character encoding.
Geert Huylebroeck op 01/10/2019 11:25:13:
Als ik met mb_detect_encoding kijk, dan zie ik dat de bestandsnamen ook in utf8 staan.
Dat is allemaal leuk en aardig, maar hoe maak je een connectie met je database? Gebruik je ook set_charset()?
En je zou natuurlijk eens kunnen kijken hoe dat er op byte-niveau allemaal uitziet. In MySQL kun je dit met HEX('waarde') doen, en in PHP met strtoupper(bin2hex($waarde)). Afwijkingen tussen die twee verklaren waarschijnlijk waarom je geen matches vindt. En geven ook aan dat er mogelijk onnodige (extra) vertalingen plaatsvinden wanneer je e.e.a. naar de database wegschrijft omdat set_charset() ontbreekt en er een andere/verkeerde character encoding wordt verondersteld.
De verbinding staat ook in UTF8: .
Ik ga morgen eens proberen om die HEX waarden te vergelijken.
Maar wat als die twee effectief geen match hebben? Kan ik dan nog iets doen om toch tot een match te komen?
Maar als je niet precies weet wat er misgaat dan is het in wezen onmogelijk om iets op te lossen. Je weet dan immers niet wat er aan de hand is.
EDIT: je zou ook kunnen opteren voor een compleet andere aanpak. Als de foto-informatie opgeslagen wordt in de database dan is er in principe geen noodzaak voor de foto's om een bepaalde naam te dragen. Je zou dan in wezen het bestand kunnen hernoemen naar het auto-increment id van het record (bv 12.jpg). Ik neem aan dat deze foto's nu ook niet enkel "beveiligd" zijn door het feit dat ze een voor anderen onbekende naam hebben en voor de rest volledig toegankelijk zijn?
Gewijzigd op 01/10/2019 17:19:38 door Thomas van den Heuvel
Het opslagen van de foto’s in de databank is helaas geen optie. Het is zo dat ik de foto’s van de schoolfotograaf ontvang met een bepaalde bestandsnaam. Die moet ik voor een bepaalde applicatie omzetten naar de unieke sleutelwaarde van de leerling.
De foto’s worden via een zip-bestand geüploaded en van zodra ze verwerkt zijn (upload via API) meteen verwijderd.
EjdaâSarah19.09.2005.jpg
92544 - sarah.ejdaa
File: 456A646161CC82536172616831392E30392E323030352E6A7067
DB: 456A6461C3A2536172616831392E30392E323030352E6A7067
MöllerElisabeth04.10.2002.jpg
23164 - elisabeth.moller
File: 4D6FCC886C6C6572456C6973616265746830342E31302E323030322E6A7067
DB: 4DC3B66C6C6572456C6973616265746830342E31302E323030322E6A7067
Het lijkt er dus op dat die speciale karakters dus een andere encodering hebben. De vraag is nu, hoe lost ik dit op?
Code (php)
1
2
3
4
2
3
4
$file = '456A6461'.'61CC82'.'536172616831392E30392E323030352E6A7067';
//0x61 = a + utf8:CC82=COMBINING CIRCUMFLEX ACCENT
$db = '456A6461'.'C3A2'.'536172616831392E30392E323030352E6A7067';
// \xc3\xa2 LATIN SMALL LETTER A WITH CIRCUMFLEX
//0x61 = a + utf8:CC82=COMBINING CIRCUMFLEX ACCENT
$db = '456A6461'.'C3A2'.'536172616831392E30392E323030352E6A7067';
// \xc3\xa2 LATIN SMALL LETTER A WITH CIRCUMFLEX
In de filenaam wordt dus een "a" gecombineerd met een "^" = "â".
In je database wordt gewoon direct een "â" gebruikt.
Effectief hetzelfde, maar binair niet.
Je zou dus iets kunnen maken wat al die combining karakters omzet naar enkele karakters (of in ieder geval een "vertaaltabel" maken die dit gewoon binair doet: '61CC82' => 'C3A2', enz). Of een functie zoeken die dit voor je kan doen (ik heb even kort met iconv() en mb_convert_encoding() zitten spelen, maar kon zo snel geen "magische config" vinden).
Gewijzigd op 02/10/2019 23:12:01 door Rob Doemaarwat
En ik zie dat @Rob mij al voor was :/
Zoals @Rob al aangeeft zijn "6FCC88" en "C3B6" (de letter "o" met een umlaut) twee manieren om hetzelfde te zeggen, in de eerste variant is dit symbool (glyph) samengesteld uit twee zogenaamde "code points": een code point voor de letter o (0x6f) en een code point voor een trema (0xcc 0x88). De tweede variant is de zogenaamde "genormaliseerde" vorm.
Het woord "normaliseren" bleek hier cruciaal, PHP heeft hier een ingebouwde class voor, mits je PHP-versie nieuw genoeg is. Dit is onderdeel van de int(ernationa)l(ization) extensie.
Een simpele test om te kijken of dit bij jou out-of-the-box werkt:
Code (php)
Je zou dan "fixed!" te zien moeten krijgen. En anders moet je deze extensie installeren en e.e.a. opnieuw starten.
EDIT: had trouwens tijdens deze speurtocht een coole toolsite gevonden: onlineutf8tools.com.
Gewijzigd op 03/10/2019 01:48:13 door Thomas van den Heuvel
mvg
Geert