Door
Ozzie PHP
op 05-03-2014 18:04
gewijzigd op 05-03-2014 18:05
3.672 views
Hallo,
Mag een set method valideren?
Stel we hebben een product en we willen aan dat product een productnummer toevoegen.
<?php
$product = new Product();
$product->setProdNr('ABC1234');
?>
De vraag is of deze setProdNr method (of iedere set method in het algemeen) mag valideren of de input klopt.
In het voorbeeld gaat het nu om een productnummer, maar in de praktijk heeft een product nog meer eigenschappen die gavalideerd moeten worden. Denk bijvoorbeeld aan de productnaam. Is het een string, en bestaat die string uit minimaal 3 tekens? Nou ja, zo zijn er dus een heleboel dingen die gevalideerd moeten worden.
Mijn simpele vraag is, mag een setter eigenlijk wel iets valideren?
Stel dat het product gevalideerd is, en hiervoor hebben 10 controles plaatsgevonden. Vervolgens slaan we de gegevens op in de database. De volgende keer halen we het product op uit de database en via de mapper worden alle gegevens keurig weer geset. MAAR... opnieuw vinden er nu 10 controles plaats, want die controles zijn onderdeel van de set methods!
Mijn stelling is dan ook: een set method mag geen input valideren en alle input moet gevalideerd worden door een validator object. Dit validator object maakt vervolgens een product aan.
Dan krijg je dus zoiets:
<?php
$pv = new ProductValidator();
$pv->setProdNr('ABC1234');
$product = $pv->createProduct();
// opslaan in database
$pm = new ProductMapper();
$pm->save($product);
// ophalen uit database
$pm->load('ABC1234'); // hier vindt dus geen validatie meer plaats
>> Een class moet altijd maar 1 ding doen. En niets meer (SOLID principle, heb je waarschijnlijk al meer voorbij zien komen).
Dit is dus waar het me vooral om gaat.
Moet je een User class zien als een class die er zelf voor zorgt dat z'n inhoud klopt, of moet je de User class vooral zien als een "container" die de user data vasthoudt, en dat je voor de controle een UserValidator class gebruikt.
@Dos:
Ik heb alleen beschikking over MySQL.
Als ik jou dus goed begrijp zeg jij eigenlijk dat de data in je database kan worden gewijzigd, en dat je er daarom niet vanzelfsprekend vanuit moet gaan dat die data veilig is. Begrijp ik je goed?
Als je jezelf beschermt tegen SQL injectie, en SQL injectie dus niet mogelijk is, kan er dan nog steeds door iemand gerommeld worden met de data in de database? Is dat een reëel veiligheidsprobleem?
"Als ik jou dus goed begrijp zeg jij eigenlijk dat de data in je database kan worden gewijzigd, en dat je er daarom niet vanzelfsprekend vanuit moet gaan dat die data veilig is. Begrijp ik je goed?"
Yup. Ik kan prima met mijn favoriete database tool de applicatie validatie omzeilen als er geen CHECK CONSTRAINTs zijn. (verbonden als iemand met UPDATE en/of INSERT rechten)
"Als je jezelf beschermt tegen SQL injectie, en SQL injectie dus niet mogelijk is, kan er dan nog steeds door iemand gerommeld worden met de data in de database? Is dat een reëel veiligheidsprobleem?"
Als je je bedenkt dat websites van grote bedrijven die veel meer geld aan beveiliging kunnen besteden soms vatbaar zijn voor SQL injectie wil je dan echt alleen op je anti SQL injectie voorzorgsmaatregelen vertrouwen :p
Het liefst heb je meerdere lagen van beveilig maatregelen. En persoonlijk vind ik dat validatie zo dicht mogelijk bij de opslag plaats moet vinden, javascript validatie doe je op server niveau nog eens over, op database niveau nog eens is extra veilig. Wel kan het een maintenance nachtmerrie worden, dus weeg alles goed af.
Moet je een User class zien als een class die er zelf voor zorgt dat z'n inhoud klopt, of moet je de User class vooral zien als een "container" die de user data vasthoudt, en dat je voor de controle een UserValidator class gebruikt.
Het is natuurlijk aan jou wat je wilt. Je kan het allemaal op verschillende manieren doen. Ik zou zeggen je User class is iets dat er zelf voor moet zorgen dat hij klopt. Ik zou daar ook niet nog eens een ValidatorClass bij maken.
Ik heb daar nooit bij stilgestaan dat informatie uit de database ook onveilig kan zijn. Wat dat betreft valt er dus iets voor te zeggen om altijd te controleren.
Heb ik weer even een wat extremer voorbeeldje voor je.
Stel een gebruiker vult z'n adres in. Jij valideert vervolgens via een externe website of de postcode bestaat en of het adres correspondeert met de postcode. Ja? Dan sla je de gegevens op in de database. Vervolgens wil jij op het scherm een lijst met gebruikers tonen, inclusief hun adressen. Wordt dan weer per adres die controle uitgevoerd?
Ik snap dat dit een extreem voorbeeld is, maar het gaat me om de gedachtengang en hoe jij hier tegenaan kijkt.
@D Vivendi:
Oké, en als jij dus de user data uit de database haalt, dan voer jij opnieuw de benodigde controles uit? Of koppel je de gegevens uit de database zonder controle aan de class properties?
Vervolgens wil jij op het scherm een lijst met gebruikers tonen, inclusief hun adressen. Wordt dan weer per adres die controle uitgevoerd?
Nee, die website zou requests vanaf jouw server waarschijnlijk binnen de kortste keren blokkeren.
De postcode kun je prima op zichzelf valideren. Het huisnummer ook, maar de straat en woonplaats zou ik gewoon als tekst zien. En tekst is makkelijk gevalideerd.
Als ik data uit de database haal dan is dat bij mij al een object. Ik gebruik gewoon simpelweg een ORM. Ik doe zelf helemaal niets met objecten mappen en al die rompslomp.
Maar die keus is aan jou of je het terug wilt mappen naar zo'n User object. Doe je dat, dan voer je idd gewoon die controles uit, want die zitten dan eenmaal in je setters, daar ontkom je ook niet meer aan. Maar dat is geen probleem toch?
Maar je kan ook gewoon voor het uitlezen direct je "rows" uitlezen zoals je die bv. terug krijgt van een mysqli_fetch_assoc() oid.
Het is maar net wat je zelf wilt of je gebruikers (als je die hebt) verwachten.
>> De postcode kun je prima op zichzelf valideren. Het huisnummer ook, maar de straat en woonplaats zou ik gewoon als tekst zien. En tekst is makkelijk gevalideerd.
Ik snap wat je bedoelt. En het voorbeeld is ook een beetje extreem, maar door in extremen te praten kom je vaak tot betere inzichten. Wat ik bedoel is dit. We hadden dus besloten dat een object geldige data moet hebben. Bij een adres zou je dus kunnen controleren of een postcode matcht met de straat en huisnummer, zodat iemand niet een postcode van Amsterdam kan opgeven en een straat in Groningen.
Oké, dus iemand vult z'n gegevens in. Wij controleren of het klopt en slaan ze op in de database. Vervolgens gaan we het adres weer een keer ophalen uit de database, en jij zegt dan... gegevens uit de database kunnen niet kloppen, dus we moeten nogmaals controleren. Correct, of niet?
@D Vivendi:
>> Als ik data uit de database haal dan is dat bij mij al een object.
Wat voor object is dat dan? Gebruik je de stdClass? Of bedoel je iets anders?
Aangezien het een extreem voorbeeld is zou je ook correcte data kunnen kopen en niet op een externe service vertrouwen: http://shop.postcode.nl/nationale-postcodedatabase-professional
Wel zorgen dat de tabellen read only zijn natuurlijk. Dan zou je kunnen besluiten dat je alleen op postcode formaat en datatype gaat valideren.
>> Wat voor object is dat dan? Gebruik je de stdClass? Of bedoel je iets anders?
In mijn geval is het een lege class die 'dynamisch' opgevult wordt met properties door m'n ORM. Dat object kan ik ook gewoon weer terug geven en wordt het automatisch opgeslagen. Die objecten valideren zichzelf ook niet. Dat kan ik ook niet met mijn ORM. Zoiets zou je volgens mij weer wel kunnen doen met iets als Doctrine.
Ik bouw gewoon simepele websites. Dus ik wil me dan ook helemaal niet bezig houden met het mappen van objecten, validator classes erbij schrijven, Repositories en noem maar op. Ik win met dit soort dingen helemaal niets. Het wordt er echt niet duidelijker of veiliger op.
Wanneer ik een facebook of twitter moet maken, dan zou ik bijvoorbeeld wel van m'n ORM afstappen, en zelf mijn queries gaan schrijven. Maar ik zie dat niet snel gebeuren.
Maar goed, ik wijk een beetje af. Wat voor object je terug krijgt hangt af van je ORM. Zou daar ook eens naar kijken als je nog niets weet over ORM systemen.