Controle op input van database waardes

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 3 volgende »

Yoeri Achterbergen

Yoeri Achterbergen

05/09/2020 21:07:46
Quote Anchor link
Goede avond,


Graag zou ik willen weten of ik in de juiste richting zit te denken.

Vanuit mijn database maak ik opties aan voor in de select, zodat gebruikers alleen daar de keus uit hebben.
Natuurlijk wil je niet dat via de inspector de waardes alsnog kunnen worden aangepast.
Ik wil dus een controle of de waarde ook overeenkomt met de lijst uit de database.

Is het dan verstandig als het formulier geladen word eerst de waardes in een array te zetten en met een foreach loop de opties aan te maken en de controle te doen met array_key_exists?

Of raden jullie een andere techniek aan?
 
PHP hulp

PHP hulp

23/12/2024 18:13:22
 
Rob Doemaarwat

Rob Doemaarwat

05/09/2020 21:17:01
Quote Anchor link
Als je je lijst opbouwt op basis van
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
select id,name
from lijst
where {voorwaarden}

dan hoef je in je controle enkel nog te kijken of het id bestaat binnen de context
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
select 1
from lijst
where id = {id} and {voorwaarden}

Dan hoef je dus niet je hele lijst op te halen (incl "name"). Andersom: als je die lijst toch al ergens voor nodig hebt, dan is een array_key_exists() natuurlijk het snelst.
 
Thomas van den Heuvel

Thomas van den Heuvel

05/09/2020 21:22:49
Quote Anchor link
Dit lijkt mij onderdeel van de validatie van de formulierinformatie na submit en voor wegschrijven naar de database.

Hoe je dit formulier opbouwt -dit is onderdeel van de weergave van het formulier, wat een andere actie is dan het verwerken van een formulier- staat hier in principe los van.

Wel zou je een validatieregel voor zo'n invoerveld kunnen hebben, of een formulier-object met hierin formulierveld-objecten kunnen hebben, waar je zowel bij weergave alsook validatie/verwerking op eenzelfde wijze informatie uit hengelt.

Ik denk dat je de verschillende onderdelen het beste in afzondering kunt behandelen:
Enerzijds de "flow" van het formuliergebruik: je hebt een aparte "actie" voor het weergeven van een formulier, eventueel met terugkoppeling van een eerdere submit + foutmeldingen en eerdere ingevulde waarden, en een aparte "actie" voor het verwerken van het formulier. Na validatie ga je dan terug naar het formulier op het moment dat er foutmeldingen zijn of schrijf je data permanent weg naar de database en verhuis je vervolgens weer terug naar een "succes"- of overzichtspagina.

Anderzijds heb je de formulierdata die je op een bepaalde manier inzet in beide acties voor initialsatie, validatie en weergave van het formulier. Deze formulierdata kan bijvoorbeeld in een soort van datastructuur zitten (configuratie-array) of ondergebracht zijn in een of meerdere klassen, of zelfs een combinatie van beide.

Als je veelvuldig gebruik maakt van formulieren loont het zelfs de moeite om een soort van formuliersysteem te bouwen die de formulieropbouw in HTML en de validatie grotendeels automatiseert. De bouwstenen (de formulierelementen) hoef je dan slechts één keer te schrijven.

Met een formuliersysteem zou je ook composiet- of volledige custom elementen kunnen bouwen.

Beschouw bijvoorbeeld de demo van een eigen formuliersysteem voor het toevoegen en wijzigen van data.

Het "enige" wat je in wezen "schrijft" aan formulierprogrammering zijn dan de formuliervelden, en de programmering van de acties, zoals hier staat geïllustreerd. Nu staat hier "enige" tussen aanhalingstekens, want het is nog steeds redelijk wat code. Maar al die code bij elkaar (~163 regels) omvat de volledige afhandeling van een redelijk groot/complex formulier, exclusief de klassen voor het formulier en de -elementen, maar die verdien je vrij snel terug als je veel formulieren gebruikt.
Gewijzigd op 05/09/2020 21:27:07 door Thomas van den Heuvel
 
Frank Nietbelangrijk

Frank Nietbelangrijk

05/09/2020 21:31:23
Quote Anchor link
Wanneer het formulier verstuurd is (vaak in de POST request method) dan is het altijd heel erg belangrijk om de data die ingestuurd is te valideren en wel SERVER-SIDE! Dus niet (alleen) met javascript maar met PHP. Valideren doe je op alle mogelijke manieren zodat de data in je database niet vervuild raakt.

Er is overigens nog een goede manier om te voorkomen dat je database inconsistent wordt namelijk door BEPERKINGEN (in het Engels constraints) toe te voegen op de vreemde sleutels.

Dit is in jouw specifieke voorbeeld ook goed mogelijk. Google eens op mysql foreign key constraints
 
Thomas van den Heuvel

Thomas van den Heuvel

05/09/2020 21:38:19
Quote Anchor link
Dat kan ook, maar dat werkt uiteraard alleen als je alles helemaal hebt uitgenormaliseerd (of je moet ENUMs gebruiken ofzo, maar dat is niet echt optimaal). De structuur van toegestane formulierwaarden kan dus zowel in de database alsook in code zijn vastgelegd. En op grond daarvan kun je toetsen of de aangeboden waarden geldig zijn. Deze zul je op zijn minst altijd aan de serverzijde moeten controleren zoals @Frank aangeeft.
Gewijzigd op 05/09/2020 23:23:53 door Thomas van den Heuvel
 
Rob Doemaarwat

Rob Doemaarwat

06/09/2020 09:41:03
Quote Anchor link
@Thomas: Maar hoe controleer je dan in je "formuliersysteem" of een waarde (key) is toegestaan? In het voorbeeld dat je geeft hebben je "select" fields altijd een vaste "options" array. Maar ik kan me voorstellen dat die lijstjes meestal uit een DB komen. Haal je dan bij de initialisatie altijd de hele lijst uit de DB op*, om vervolgens dus met een array_key_exists vast te stellen dat de key bestaat en dus is toegestaan. Of zit er nog een slimmigheidje in waarbij je dus bij de controle niet weer de hele lijst op hoeft te halen, maar puur kijkt of die ene key bestaat (binnen de overige voorwaarden)?

* daarnaast kan ik me voorstellen dat er soms (asynchrone) "actions" zijn waarbij de inhoud van deze lijst er helemaal niet toe doet, en het dus helemaal niet nodig is om de lijst op te halen.
 
Thomas van den Heuvel

Thomas van den Heuvel

06/09/2020 18:10:44
Quote Anchor link
Hm, moest even graven in code.

Voordat het formulier wordt gevalideerd in de verwerkstap worden de velden eerst geïnitialiseerd met waarden uit $_POST. Voor een select-veld houdt dit in dat wordt gecontroleerd of er een waarde is ingesteld, en zoja, of deze geldig is (met isset, ik sta geen null-waarden toe dus dat zou altijd goed moeten gaan), en zoja dan wordt de waarde toegekend. Indien er een niet-toegestane waarde is geselecteerd wordt de default-waarde gepakt. Maar voor hetzelfde geld zou het formulier(veld) een foutmelding kunnen retourneren, wat misschien beter is.

Aan de andere kant zou je ook van mening kunnen zijn dat op het moment dat iemand een formulier aan het manipuleren is, dat er andere dingen aan de hand zijn die wellicht ook op een andere plaats opgelost dienen te worden :p.

De opties kunnen zowel uit de database komen als je dat wilt, of gewoon in de definitie van het formulier-object zelf worden opgenomen.

In het validatie-gedeelte wat volgt op de initialisatie worden eventuele extra "regels" geïnspecteerd. Op het moment dat het select-veld een regel "verplicht" heeft en een ongeldige waarde was geselecteerd (waarbij dus de default waarde wordt gepakt die meestal als waarde "geen waarde" heeft) wordt op die wijze sowieso voorkomen dat de waarde wordt doorgelaten. Maar als je meer manipulatie verwacht zou je strengere controles kunnen doen. Volgens mij zat er in dit systeem ook iets dat je "default" regels kon definiëren die altijd worden gecontroleerd, daarbij maakt het dus niet uit of deze expliciet staan ingesteld of niet. Daar zou je eventueel dit soort extra controles kunnen opnemen, of in het initialisatie-gedeelte de boel al af kunnen blazen indien het lijkt alsof er sprake is van manipulatie.

Elk formulierveld heeft ook zijn eigen klasse, dus je zou deze ook kunnen extenden voor een paranoia-plus uitvoering.

Per page-access, zij het het tonen of verwerken van een formulier, wordt alles maar 1x ingeladen.

Ik ben het eens dat functionaliteit als deze er alles / zoveel mogelijk aan moet doen om ervoor te zorgen dat als data goed wordt bevonden en wordt doorgelaten, dat deze 100% moet kloppen en dus ook moet precies moet passen in de vakjes waar je de data vervolgens in wilt stoppen. Dat is immers het hele doel van de validatie.
 

08/09/2020 09:05:00
Quote Anchor link
Wat ik sterk aanraad is om de database eigenaar te maken van de data, in plaats van PHP.
Want de database is daar speciaal voor gemaakt, en PHP niet.

Wat je op database niveau moet doen is een CONSTRAINT aanmaken van het type FOREIGN KEY (FK) op de kolom(men) waarin je de keuze opslaat van de gebruiker. De database zorgt er dan voor dat ze zullen wijzen naar de meestal PRIMARY KEY van de andere tabel waar de FK naar verwijst.

Geeft de database een fout bij een poging verkeerde invoer op te slaan? Dan weet je dat de data van de gebruiker niet klopt, en kan je dat aangeven bij de gebruiker.

Deze functionaliteit is standaard ingebouwd bij de meeste databases, behalve bij MySQL. Daar hangt het af van de storage engine, en als je InnoDB gebruikt, kan het wel.
Gewijzigd op 08/09/2020 09:08:14 door
 
Thomas van den Heuvel

Thomas van den Heuvel

08/09/2020 16:40:01
Quote Anchor link
Het waarborgen van de referentiële integriteit is natuurlijk altijd verstandig zodat op die manier gezorgd wordt dat de data IN de database consistent is en blijft. De validatie van formulierdata zorgt er voor (of maakt het op zijn minst meer aannemelijk) dat data alleen aan de database aangeboden wordt als deze ook echt "past".

Als je op voorhand al weet dat iets niet past dan is het niet nodig om hiervoor een query te laten mislukken om dat nog eens te bevestigen. Ik ben het met je eens dat de database middelen mag hebben om de data consistent te houden en verkeerde data mag weigeren, maar ook functionaliteit buiten de database kan hierbij helpen, dit is niet het exclusieve domein van de database zelf.

Een validatielaag in formulierfunctionaliteit heeft ook als extra doel om aan de gebruiker op een vriendelijke en begrijpelijke manier terug te koppelen wat deze zou moeten wijzigen aan de invoer om ervoor te zorgen dat deze alsnog weggeschreven kan worden naar de database. Dat werkt doorgaans wat beter dan "foreign key constraint X failed" oid.
 
Rob Doemaarwat

Rob Doemaarwat

08/09/2020 19:03:39
Quote Anchor link
Daarnaast: De tabel die voor deze <select> wordt gebruikt heeft misschien wel tig entries, maar de gebruiker mag er maar een paar selecteren (op basis van rechten, of van een andere keuze). Je kunt dus niet altijd alles afschuiven op de DB.
 

08/09/2020 23:00:11
Quote Anchor link
Wat zou de use case zijn die de overhead rechtvaardigt?
Het valideren van de data in PHP heeft een prijs, want dan moet je de gegevens laten controleren in de DB (wat die zelf al voor je doet middels een INSERT of UPDATE statement) om daarna alsnog binnen een transactie een INSERT of UPDATE te doen waarbij de DB het een tweede keer controleert. Daarbij is het niet nodig, omdat je als het goed is heldere foutcodes terug krijgt waardoor je alsnog de gebruiker normale terugkoppeling kunt geven.
 
Frank Nietbelangrijk

Frank Nietbelangrijk

08/09/2020 23:39:26
Quote Anchor link
>> Wat zou de use case zijn die de overhead rechtvaardigt?

- Lees Rob zijn reactie nog eens door

Bovendien zit een formulier dikwijls vol vuiligheid verstuurd door kwaadwillende bots of rotzakken. Daarom wil je een formulier op allerlei manieren "beproeven" om te voorkomen dat er data in je database komt die er helemaal niet hoort te zijn, ook als deze data "database technisch" wel klopt. Daarnaast kunnen er in je formulier velden zitten die niet of niet rechtstreeks naar de database geschreven worden maar die je wel wilt valideren zoals bijvoorbeeld een CSRF token.

Jouw (Ad Fundum) methode waarin je eigenlijk gaat afwachten of je database wel of niet met een foutmelding kan komen kan volgens mij wel nuttig zijn als er op één of meerdere kolommen een UNIQUE CONSTRAINT zit. (Bijvoorbeeld op de 'email' kolom in de user tabel om te voorkomen dat er meerdere accounts op één mailadres komen te staan).

De hele tabel doorlopen op alle voorkomende mailadressen lijkt me dan een kostbare operatie waardoor ik in dat geval zou kiezen voor een INSERT waaruit mogelijkerwijs een foutmelding komt die zegt dat het mailadres al in de tabel aanwezig is.
 
Thomas van den Heuvel

Thomas van den Heuvel

09/09/2020 12:47:51
Quote Anchor link
Frank Nietbelangrijk op 08/09/2020 23:39:26:
De hele tabel doorlopen op alle voorkomende mailadressen lijkt me dan een kostbare operatie waardoor ik in dat geval zou kiezen voor een INSERT waaruit mogelijkerwijs een foutmelding komt die zegt dat het mailadres al in de tabel aanwezig is.

Maar dat doe je toch in de validatie van het formulier? En in de query waarin je dat controleert zul je ook een case-insensitive controle moeten doen of wat dan ook. Net zoals je als je een nieuwe gebruiker aanmaakt iets soortgelijks wilt doen. Weet niet helemaal of je dat soort regels in de database kunt verankeren, bijvoorbeeld dat je als je een gebruiker Henk hebt dat het niet is toegestaan om een andere gebruiker HENK toe te voegen? Je zou dus kunnen stellen dat je op die manier meer semantische regels kunt toevoegen naast de reeds aanwezige syntactische regels. Dit valt volgens mij onder de "business logic" van de applicatie?

Vraag is ook, als dit uberhaupt mogelijk is, of het echt wenselijk is om dat allemaal in de database vast te leggen. Elke keer als je dan nieuwe regels verzint of wilt aanpassen houdt dit een databasewijziging in? Dat zou ik dan zelf liever in een andere laag regelen in plaats van dat helemaal vast te timmeren in de database. Op die manier worden dat soort regels ook makkelijker programmeerbaar.

Zou je dit kunnen vergelijken met een zwik rewriterules in een .htaccess-bestand die precies alle mappings vastleggen van externe URL naar intern adres versus een enkele regel die alles naar een index.php bestand delegeert? Ik zou dan wel weten welke variant ik zou kiezen.
 
Yoeri Achterbergen

Yoeri Achterbergen

11/09/2020 01:03:00
Quote Anchor link
Hoi hoi,


Bedankt voor de reacties. Waar het mij hoofdzakelijk om gaat is het volgende
In de DB staan tijden, deze worden gefetched als de pagina geladen word.
De gebruiker mag alleen die tijden gebruiken, word er gemanipuleerd dan treed er een foutmelding op.
Stap 1: laad de tijden
Stap 2: controleer of de tijd die is geselecteerd voorkomt in de DB.

Werken met ID's?
De tijd die gepost word gebruiken in where?
 
Thomas van den Heuvel

Thomas van den Heuvel

11/09/2020 01:17:46
Quote Anchor link
Je zult wat meer moeten vertellen over deze tijden. Mogen deze ook maar één keer geselecteerd worden en zijn ze daarna niet meer beschikbaar? Hoe is het "gedrag" van zo'n tijd precies? Kun je concreet vertellen over wat voor tijd het gaat?

Er kan ook tijd verstrijken tussen het laden van de formulierpagina met de tijden en het submitten ervan. Daarnaast kan het gebeuren dat 100 personen tegelijkertijd een formulier submitten, en dat de tijd meerdere keren wordt gekoppeld aan verschillende records, mogelijk met dubbele boekingen of wat dan ook tot gevolg.

Het "gedrag" van zo'n tijd bepaalt hoe de validatie hiervan verloopt, als je hier tips over wilt zul je ons dus moeten uitleggen hoe je wilt dat deze tijden zich gedragen.
 
Ozzie PHP

Ozzie PHP

11/09/2020 01:24:46
Quote Anchor link
Klaarblijkelijk mag een gebruiker dus kiezen uit een aantal tijden.

De tijden kun je dan aan de gebruiker tonen op een nette manier, bijv.

13.15 uur

of als het om een tijdvak gaat

13.15 - 13.30 uur

Aan zo'n tijd of tijdvak kun je een value koppelen, bijv. 202009111315 voor het tijdstip 13.15 uur op 11 september 2020. Of in het geval van een tijdvak 2020091113151330.

Als de gebruiker het formulier submit, voer je een query uit en controleer je aam de hand van de value of het tijd/tijdvak nog vrij is. Ja, dan opslaan. Nee, dan opnieuw het formulier tonen met de beschikbare tijden/tijdvakken.
 
Yoeri Achterbergen

Yoeri Achterbergen

11/09/2020 13:17:34
Quote Anchor link
In de database heb ik een tabel met een starttijd en een eindtijd.
Deze tijden zijn gekoppeld aan de dagen van de week.

iddaystarttimeendtime
1maandag12:0018:00
2dinsdag10:0018:00
3woensdag14:0018:00
4donderdag10:0018:00
5vrijdag10:0022:00
6zaterdag10:0022:00
7zondagNULLNULL


De gebruiker voert een datum in waardoor een AJAX request plaats vind waarmee ik check om welke dag het gaat en haal daarmee de start en eind tijd mee op.
Vervolgens word er voor elk kwartier een option element gemaakt welke ik dan met javascript in het select element zet zodat de gebruiker kan kiezen.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$day
= date('N', strtotime($_POST['when']));

$sql            = "SELECT id, starttime, endtime FROM $the_table WHERE id=$day";
$result            = mysqli_query($connection, $sql);

while($row = mysqli_fetch_assoc($result)){
    $start     =  strtotime($row['starttime']);
    $end     = strtotime($row['endtime']);
}


$return = '<option></option>';
for($i=$start; $i<$end; $i += 900){
    $return .= '<option>'.date('H:i', $i).'</option>';
}


echo $return;
?>


Ik wil voorkomen dat de option gemanipuleerd word door tijden te veranderen zoals 13:12 of buiten de starttijd en eindtijd om.
Gewijzigd op 11/09/2020 13:18:18 door Yoeri Achterbergen
 
Rob Doemaarwat

Rob Doemaarwat

11/09/2020 14:25:15
Quote Anchor link
"Had dat dan meteen gezegd" ...

1) Regenereer je lijstje met tijden en kijk of de geselecteerde tijd in dit lijstje zit.
2) Controleer in de database of de betreffende datum+tijd nog vrij is.

Alhoewel het mbt 2) wel handig lijkt als je dit ook al op voorhand doet, zodat de gebruiker alleen de tijden te zien krijgt die nog vrij zijn.

En mbt 2) moet je sowieso achteraf / voor opslaan altijd een DB lookup doen (misschien heeft een andere gebruiker net datzelfde tijdstip gereserveerd, dus lijkt me dat je hier gewoon maar direct alles in de DB kunt controleren (dus ik zou geen "trucjes" toepassen om een DB lookup te besparen).
 
Yoeri Achterbergen

Yoeri Achterbergen

11/09/2020 20:21:31
Quote Anchor link
Dus als ik met submitten nogmaals dat lijstje genereer en deze in een array zet en de array key exist gebruik zou een oplossing zijn?
 
Ozzie PHP

Ozzie PHP

11/09/2020 20:50:16
Quote Anchor link
Nee, op het moment dat je de value ontvangt die bij de tijd hoort, dan check je direct in de database of de bijbehorende tijd vrij is. Zo ja, dan reserveer je direct de tbetreffende tijd in de database.

Je voert dus 2 queries achter elkaar uit. Die stap van een array maken zou ik overslaan.
 
Rob Doemaarwat

Rob Doemaarwat

11/09/2020 21:07:12
Quote Anchor link
@Ozzie: maar de beschikbare tijden staan (nog) niet in de database; alleen de begin- en eindtijd voor die dag. Op basis van de begin- en eindtijd moet je dus eerst het lijstje met opties weer regenereren om de check te kunnen doen.
 

Pagina: 1 2 3 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.