Als een script een $_REQUEST-waarde krijgt, wil ik die valideren en eventueel sanitizen.
Maar nu is de $_REQUEST-waarde zelf een array met wat sub-arrays, met UTF-8 indices en waarden...

De oplossing waar het script nu mee werkt is array_map() met een preg_match() om te checken of een index of waarde geldig UTF-8 is, om als dat niet het geval is de waarde aan te passen met mb_convert_encoding (en een melding te geven in het log).

Maar er moet toch een simpeler oplossing zijn voor zo'n algemene vraag, misschien kan het met filter_input_array() ?

[size=xsmall]Toevoeging op 17/06/2016 21:37:19:[/size]

Ik zit te kijken naar iets als:

class cZomaarEenVoorbeeldKlasse {
  ...
  protected function naarUnicode($sTekenreeks) {
    return mb_convert_encoding((string) $sTekenreeks, 'UTF-8', 'UTF-8');
  }
  public function controleerInvoer($sVariabele) {
    if (isset($_REQUEST[$sVariabele])) {
      $_REQUEST[$sVariabele] = filter_input(INPUT_REQUEST, $sVariabele,
        FILTER_CALLBACK, array('options' => array($this, 'naarUnicode')));
    }
  }
  ...
}

Lijkt te werken, maar volgens mij checkt het niet de indices?
array_walk_recursive() doet dat ook niet, dus dan blijf ik bij array_map() hangen.. echt mooi vind ik het niet.
Van die lange ij ken ik modernere varianten: typografische ligaturen zoals ff, fi of fl en combinaties daarvan, zoals ffi en ffl. Geeft fantastisch mooi drukwerk in dtp-software die ermee uit de voeten kan, zoals Adobe InDesign en QuarkXPress.

Maar dan... Heb je een PDF met ligaturen, maar herkent een screen reader voor blinden en slechtzienden de fi- en fl-klanken niet meer. Of je kopieert wat tekst uit een PDF, maar daarna slaat de spellingcontrole van een tekstverwerker op hol.

Dat is een vergelijkbaar probleem: zodra de output van x de input van y wordt, moeten beide dezelfde taal spreken om elkaar te begrijpen. Is die taal dan Unicode? Of zou je eerder zeggen dat die taal Nederlands is?

Zelfs de @ is oorspronkelijk een ligatuur. In de context van modern Nederlands is het dan een e-mailding dat we apenstaartje noemen. In de context van middeleeuws monniken-Latijn is het echter een samentrekking van ad: de a is de aap en de gekrulde d zijn staart.

Die context kun je waarschijnlijk wel afleiden uit een langere string. Of uit andere data in dezelfde context, dus inderdaad: big data crunchen. De vraag is meer: moet je dat wel willen als je de context ook op een andere manier kunt formaliseren?
We hebben te maken met een technische uitdaging om rekenmachines ('computers') taalkundig te maken, en in dat langdurige proces loop ik tegen een fenomeen aan. En waar ik tegen ageer. Namelijk dat wanneer een computer niet begrijpt wat een mens bedoelt, dat het wel aan de mens moet liggen. Die had maar moeten zorgen voor correcte invoer. En deze gedachte dat het altijd aan de gebruiker moet liggen tot norm verheffen. Terwijl het ook anders had gekund.

Het is bijna een soort ambtenarij, het opzettelijk niet willen begrijpen en dat nog normaal vinden ook. In het extremere voorbeeld van de 'A'-s (om over de apostrof in MS-Word maar te zwijgen): het kan toch net zo makkelijk zijn dat een gebruiker geen keuze heeft of weet in welke 'A' er nou precies staat, ook al wordt wellicht voor de ASCII-variant als de Unicode-varianten in het lettertype verwezen naar hetzelfde symbool in het lettertype, ofwel er zou visueel geen pixel verschil zijn. De doorsnee eindgebruiker heeft geen flauw benul wat er mis zou kunnen zijn, laat staan dat er ook maar een mogelijkheid zou bestaan dat die eindgebruiker iets aan het probleem kan doen om het op te lossen. Vervolgens zegt jouw hypothetische script doodleuk: 'postcode klopt niet'. Terwijl iedereen kan zien dat die postcode wél klopt. Probeer zo'n houding maar eens vol te houden op een verjaardag, dat wordt erg gezellig...

Dus nu hebben we het concrete voorbeeld van de postcode, dat voor het invoeren van een Nederlandse postcode de Amerikaanse (US-ASCII) 'A' voor een postcode moet gelden. Zou een gebruiker komen met een A uit een andere context (Grieks, wiskundig, etc.) dan werkt jouw programma niet, en bovendien, legt de schuld bij de gebruiker: "foute postcode, dat is FOUT!" (immers de gebruiker heeft de postcode ingevoerd). De gebruiker heeft niet in de gaten dat de programmeur(s) geen rekening houden met verschillende codepoints.

De oorzaak van dit probleem is natuurlijk dat de computer onderscheid probeert te maken tussen contexten waar dat niet nodig is.
Dan zeg ik op mijn beurt dat als het in je macht ligt om daar wat aan te doen, je het niet hoeft te laten. Ik wil het zeker niet tot norm verheffen, omdat de inspanning die het kost waarschijnlijk onevenredig is met het maken van een bijbehorend webformulier waarin gebruikers letters met de muis (sorry, via touch..) kunnen aanwijzen. Dan omzeil je het probleem en ben je klaar. Dan kun je rustig andere contexten weigeren omdat je eerder hebt aangegeven dat je dat niet gaat snappen.

Echter in andere kader van big data, datakwaliteit, waar bestanden gekoppeld worden en gegevens genormaliseerd, op vlieghavens, op internet waar veel via tekst gaat, of juist waar je vrije invoer wilt laten om gebruikers meer op hun gemak te stellen, kan een andere keuze gemaakt worden.
Dergelijke keuze is niet fout, en iedereen zou zich kunnen voorstellen dat iemand daar voor kiest.

Om terug te gaan naar de oorsprong van dit onderwerp:
- technisch gezien heb je gelijk, de ene codepoint is de andere niet
- je hebt alleen maar technisch gelijk, de rest van het gelijk heb ik ;)
- het is niet altijd van toepassing om de $_REQUEST te sanitizen via transcoding
- dat wel doen kost extra tijd van de programmeur en de CVE
- enige verlichting bieden wellicht iconv en het (wederom Engelse) Soundex-algorime in MySQL

Zo, hehe, klaar!

Na deze gedachtenwisseling om de vraag, zou ik ook graag nog lezen over hoe je een input array als $_REQUEST kunt controleren op encoding, inclusief indices. Anders ben ik geneigd aan te nemen dat niemand hier een betere oplossing voor het probleem kan bedenken?



[size=xsmall]Toevoeging op 21/06/2016 17:00:06:[/size]

Ik ben in eens weer een stuk verder met dank aan de user comments op http://php.net/manual/en/function.iconv.php !

Bij HTTP input is:
o Unicode gebruiken alleen maar goed
o encoding checken en ongeldige bytes strippen alleen maar zinvol, bijvoorbeeld
ini_set('mbstring.substitute_character', "none");
$tekst = mb_convert_encoding($tekst, 'UTF-8', 'UTF-8');

o transliteratie een doodnormaal proces, en een optie want ondersteund in PHP:
setlocale(LC_CTYPE, 'nl_NL');
$tekst = iconv('UTF-8', 'ASCII//TRANSLIT', $tekst);

Ward heeft gelijk, je moet met setlocale() aangeven wat de doeltaal is.
o Intl is een onbetwiste optie, wrapper voor de ICU-library van Unicode zelf:
- filteren:
$tekst = UConverter::transcode($tekst, 'UTF-8', 'UTF-8');

- transliteratie:
http://php.net/manual/en/class.transliterator.php
http://icu-project.org/apiref/icu4c/classicu_1_1Transliterator.html
o Er is in PHP geen prefab functie om nested arrays met indices aan te passen, dat moet je zelf typen



[size=xsmall]Toevoeging op 21/06/2016 17:10:56:[/size]

o Naast strippen van ongeldige byte sequences van UTF-8 is het ook nog mogelijk om UTF-8 verder te normaliseren: http://php.net/manual/en/class.normalizer.php

[size=xsmall]Toevoeging op 21/06/2016 17:12:04:[/size]

http://unicode.org/faq/normalization.html

[size=xsmall]Toevoeging op 22/06/2016 08:55:24:[/size]

http://stackoverflow.com/questions/17458876/php-spoofchecker-class

[size=xsmall]Toevoeging op 22/06/2016 08:58:49:[/size]

Ik geloof dat dat het nu wel duidelijk is dat de opmerking "er is geen functie in PHP" niet klopt. Gelukkig maar.

Reageren