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.
Tekst kan overal vandaan komen, niet alleen via een toetsenbord, het kan via OCR komen, of via één of andere handschriftherkennigstool van het OS, als je een PC met een pen/tablet hebt bijvoorbeeld.
Heb je die andere karakters 'A' gezien onder http://websec.github.io/unicode-security-guide/visual-spoofing ?
Daar staan al zeven karakters die volledig de letter A vormen. Als mensen dat ergens vandaan plakken, dan is dat toch een letter A? (helaas ondersteunt PHPHulp.nl nog geen Unicode, anders had ik het hier kunnen plakken)
Probeer maar eens aan 'non-technischen lookenpeepers' (mensen die niets van computers snappen, laat staan encoding) uit te leggen waarom dat geen A is, ik wens je alvast veel succes :-)
Overigens, weet iemand nog een elegantere oplossing die efficiënter is voor mijn vraag?
An tje op 20/06/2016 13:57:15

Overigens, weet iemand nog een elegantere oplossing die efficiënter is voor mijn vraag?

Invoer die niet klopt / niet aan de vorm voldoet gewoon weigeren.
Geinig hoor Thomas.. ik zal het de volgende keer met jouw input proberen..

Ik heb nog even een paar mensen gevraagd en die vinden al die letters A toch een A, behalve misschien de derde van rechts, de rest voldoet wel aan 'de' vorm... Maargoed, er is een gerede kans dat ik voorlopig geen betere oplossing op phphulp.nl ga tegenkomen, dus dank voor jullie tijd en inzet. De vraag van de vragensteller is ter discussie gesteld. Gelukkig kan ik zeggen dat mijn scriptje minder autistisch is dan die van jullie. :-)

Een geinige opmerking die ik tegenkwam met het zoeken naar een oplossing is die uit de documentatie van array_filter():
Caution
If the array is changed from the callback function (e.g. element added, deleted or unset) the behavior of this function is undefined.

Misschien kunnen dit soort functies - die niet voldoen aan hun vorm, alsook strlen() (telt geen karakters maar bytes) gewoon geschrapt uit PHP. Dan wordt de bende nog eens overzichtelijk.
Dit was geen grappig bedoeld antwoord. Jij probeert recht te buigen wat krom is.

Daarbij: je hebt nota bene zelf een tutorial geschreven over Unicode en PHP. PHP werkt met bytes en niet met (mb) karakters, tenzij je van de hiervoor bestemde functies gebruik maakt. Deal with it. Je kunt wel willen dat de zon om de aarde draait, maar daarmee is het nog geen voldongen feit.

Je kunt twee dingen doen als bepaalde zaken in PHP je tegenstaan: genoegen nemen met de onvolkomenheden van de taal en hier rekening mee houden of iets anders gaan doen. Ik denk dat Python jou wel zou liggen.

Een portie gezond wantrouwen als programmeur (of hoe je jezelf ook zou betitelen) is een ding, maar een paranoïde tunnelvisie is een ander.

En dit soort repliek:
Gelukkig kan ik zeggen dat mijn scriptje minder autistisch is dan die van jullie. :-)

Pot <--> ketel.
Dus je bent echt ongezellig.. zielig zeg.

En je lijkt onbekend met de menselijke natuur. Dan maar een stukje theorie. Er zijn mensen die tijdens hun middelbareschoolperiode hebben geleerd dat de Griekse cultuur de bakermat is van de westerse.
http://kunst-en-cultuur.infonu.nl/geschiedenis/159805-griekenland-de-bakermat-van-de-westerse-beschaving.html

Dan is het niet zo heel verwonderlijk dat er, naast je eigen tunnelvisie op ASCII code 65 zijnde hoofdletter 'A', ook nog andere letters 'A' bestaan in Unicode. Mede getuige codepoint 0391. Zie https://codepoints.net/U+0391 . Dat karakter heeft als officiële naam 'Greek Capital Letter Alpha'. Het is een dom feit dat dit karakter dezelfde letter 'A' is als de ASCII-variant, zowel in semantiek als in het lettertype. Echt, normale stervelingen zien geen pixel verschil, en doorgewinterde programmeurs ook niet als ze er niet op verdacht zijn. En daarvan beveel jij aan, aan iedereen die dit leest dat scripts de Unicode variant niet moet herkennen en de ASCII-variant wel omdat jij als programmeur anders de byte sequence niet snapt?

...

...

Nou, veel plezier met debuggen van je script, wanneer je met data van gebruikers gaat werken!
https://codepoints.net/U+0391#confusables :-)
An tje op 20/06/2016 21:53:17

Dan is het niet zo heel verwonderlijk dat er, naast je eigen tunnelvisie op ASCII code 65 zijnde hoofdletter 'A', ook nog andere letters 'A' bestaan in Unicode. Mede getuige codepoint 0391. Zie https://codepoints.net/U+0391 . Dat karakter heeft als officiële naam 'Greek Capital Letter Alpha'. Het is een dom feit dat dit karakter dezelfde letter 'A' is als de ASCII-variant, zowel in semantiek als in het lettertype. Echt, normale stervelingen zien geen pixel verschil, en doorgewinterde programmeurs ook niet als ze er niet op verdacht zijn.

Er is nu eenmaal geen PHP-functie die automagisch input in het Griekse alfabet kan onderscheiden van input in het Latijnse alfabet. Zou die er wel zijn, dan zou je waarschijnlijk moeten opgeven dat je in de input Grieks verwacht, anders moet er maar worden geraden welk van de tientallen vormvarianten van een A er nou eigenlijk staat.

Ik ken een veel eenvoudigere verwarring van dezelfde orde: die van de hoofdletter O met het cijfer 0. Mijn kinderen maken die fout vaak bij het overtypen van een geprint WiFi-wachtwoord in een vakantiehuisje of hotel. Negen van de tien keer is dat gewoon een hexadecimaal getal, maar omdat zij dat niet doorzien, typen ze nogal eens een O in plaats van een 0.

Ergo, je moet de vormvereisten van de input in beeld hebben om de input goed te kunnen sanatizen. Dit is een hexadecimaal getal, dus die O zal wel een 0 zijn. Dit is Grieks, dus die A (U+0041) moet eigenlijk een A (U+0391) zijn.
nobody cares

Je moet jezelf niet als maatstaf voor anderen zien.

.. typen ze nogal eens een O in plaats van een 0.

Klopt, daarom is er in veel lettertypen een visueel verschil aangebracht tussen de O en de 0, die laatste heeft vaak een stipje in het midden of een subtiele schuine streep.
Maar het komt vaker voor ook in ASCII, de spatie is visueel moeilijk te onderscheiden van de niet-afdrukbare karakters of het laatste karakter van Extended-ASCII (0xFF).

Het hangt van de context af, en daarom is het lovend dat Unicode context-afhankelijke 'A'-s heeft geïntroduceerd. Als je een systeem maakt dat een interface heeft naar mensen, wat vrij gebruikelijk is in de PHP-hoek, dan is het juist ook voor het Nederlands handiger om Unicode te gebruiken dan ASCII. Onder andere:

Met de komst van ASCII is de letter ? (lange ij, wederom niet ondersteund door het Nederlandse phphulp.nl, zie https://en.wikipedia.org/wiki/IJ_(digraph) ) uit ons alfabet geschrapt. Op websites, in officiële documenten, en dus ook in namen van mensen. Puur omdat we nu in een tijd leven waarin we zijn 'bevrijd' door de Amerikanen. Niets nieuws onder de zon, in de tijd dat ons land werd beheerst door Duitsers hadden we veel Duitse woorden, in de tijd van de 80-jarige oorlog hadden we veel Spaans, in de bezetting van Napoleon veel Frans.

En dan is er eindelijk Unicode dat ons bevrijd uit de 8-bit 20e eeuw, waarin we fijn onze eigen letter weer kunnen gebruiken krijg ik hier te horen dat een letter alleen geldig is als de byte sequence overeenkomt. Toegegeven, dit nog steeds vaak praktijk op internationale plaatsen als vlieghavens en het internet. Heeft een ambtenaar jou Nederlandse 'ij' vervangen voor een Griekse y of een i met een j en krijgen we dan 'computer says no' ? Dan houden mensen als Thomas op met nadenken en verschuilt men zich achter een debiele disclaimer als 'troep in, troep uit', en het meer pragmatische 'er is geen voorgedefinieerde PHP functie'. Met contextafhankelijk menselijk leed tot gevolg.

Ik begrijp best dat jullie zeggen dat het jullie overweging is, voor jullie eigen context(en), en dat kan een terechte afweging zijn, maar. Het wil niet zeggen dat het dan per sé ook voor mijn geval moet gelden. Als ik een serieus script bak, met nog relatief simpele datakwaliteitsalgoritmen, zonder te verzanden in data governance, dan probeer ik inderdaad 'recht te buigen wat krom is'. Al is het wel zo dat het kromme in de programmatuur zit, en in de 'encoding hell'. Ik wil uitgaan van gebruikers, ook als dat betekent dat je daarvoor extra moeite moet doen. En daarvoor hoeven mensen hier niet verwezen te worden naar een andere programmeertaal, want dat slaat echt als een tang op een varken. Ik wil het even gezegd hebben.
An tje op 21/06/2016 11:08:35

Het hangt van de context af, en daarom is het lovend dat Unicode context-afhankelijke 'A'-s heeft geïntroduceerd.

Eens, maar dat is juist een wezenlijk onderdeel van het probleem. Wat schoon (sana) is en wat zinvol (sane) is, wordt bepaald door de context. Iets dat een context-afhankelijke betekenis heeft, laat zich niet goed behappen door een context-onafhankelijke of context-ongevoelige totaaloplossing. Een A is meestal een Latijnse A, tenzij het een Griekse A moet zijn omdat de context Grieks is.

Ik zou de oplossing niet zozeer in een schone $_REQUEST alleen zoeken, maar hogerop in de boom: in HTTP content negotiation, want daarmee kun je beter uit de voeten met talen, alfabetten en karaktersets.

In de beperking toont zich de meester. Best leuk dat Unicode bijvoorbeeld ook Koptisch ondersteunt, maar dat is een dode taal, die in de 17e eeuw is uitgestorven. Moet je Koptisch ondersteunen omdat Unicode het ondersteunt? Of wil je Koptisch ondersteunen omdat je applicatie dat vereist? Dat zijn twee verschillende vereisten. En een keuze.
Gelukkig zijn we het er over eens dat de $_REQUEST schoon moet zijn, ook qua encoding. En zeker een goed punt van de HTTP content-negotiation.

Met de vraag of je Koptisch moet ondersteunen: er zijn ook Kopten in Nederland... Als de keuze is: 'nee, want dat lukt technisch niet' of 'het budget is te krap om genoeg FTE in te huren om het te bouwen' dan kan dat natuurlijk, al klinkt het mij wel vreemd in de oren in deze tijd van big data, waarin er dan dus ook geen koppeling gemaakt kan worden tussen een ij en een <Nederlandse ij> en een y. Maargoed, keuzes dus.

Van de volgende kant bekeken: Unicode heeft een keuze gemaakt om context-informatie op te slaan in het soort karakter. Ben ik verplicht om dat wel, of juist niet te gebruiken? Je zou immers een postcode kunnen samenstellen van dezelfde letters uit de context van een ander alfabet, met nummers in balletjes (ook Unicode karakters). Een mens kan die postcode gewoon lezen, interpreteren en meteen de context goed raden. Mensen kunnen dat veel beter dan zelfs het meest uitgebreide apparaat Watson van IBM dat aan Jeopardy meedeed: https://www.youtube.com/watch?v=YgYSv2KSyWg . De computer lijkt heel slim, maar in termen van AI is die vrij dom, het ding kan 'alleen maar' snel scoren en ranken. Na het initiële 'wow'-moment wordt Jeopardy snel saai.

Je zou een server met een client kunnen laten onderhandelen over het soort content, dat je weet hoe de server verschillende 'A'-s, 'ij'-s, etc. zal interpreteren. Dat zal zeker helpen. Maar waarom zou je contextbepaling door mensen, je eindgebruikers, op voorhand willen uitsluiten, als het in je macht ligt om het toe te staan? Is er überhaupt een reden om geen Unicode te gebruiken?

Reageren