Ik heb een contactformulier waarin de afhandeling en het formulier in hetzelfde PHP bestand zitten. Ik gebruik POST variabelen.
Nu heb ik last van het bekende probleem dat na verzending het formulier opnieuw verzonden wordt als ik de pagina ververs. Voor zover ik weet is het niet mogelijk om de POST variabelen leeg te maken direct na verzending, omdat ze nog in het geheugen van de browser zitten.
Heeft iemand hier een idee wat te doen om dit probleem te voorkomen?
Gebruik het POST/redirect/GET patroon. Oftewel, zorg dat de verwerkstap een aparte stap is in je script, waarna je ofwel direct wordt doorgestuurd na succesvolle verwerking, ofwel terug wordt gestuurd naar het formulier ingeval van fouten.
Dit komt dus neer in het opsplitsen van de verschillende codedelen en de bijbehorende acties:
- tonen van het formulier (en eventuele terugkoppeling van fouten)
- verwerken van het formulier (en doorsturen na succes of terugsturen na fouten)
- boodschap na succes
EDIT: dit zou dus een moment kunnen zijn om je code eens onder de loep te nemen in termen van paginaopbouw, vooral als je een dynamische website hebt en meerdere pagina's hebt die door PHP worden gegenereerd. Idealiter standaardiseer je dit dus waarbij je al dit soort acties op verschillende pagina's op een uniforme manier kunt behandelen.
Ook zou je dat moment kunnen aangrijpen om de vaste opbouw (het "maintemplate") en pagina-specifieke content uit elkaar te trekken zodat je heel efficiënt je pagina's kunt genereren zonder dat je HTML moet knippen en plakken waarbij je dus dezelfde code dupliceert, die je dan dus vervolgens ook op meerdere plekken zou moeten onderhouden :/.
Hier is PHP bij uitstek voor geschikt, maak hier dan dus ook gebruik van.
De code van @Ariën lost dan wellicht het directe probleem op, maar hiermee hoeft nog geen sprake te zijn van een gestructureerde opbouw. Als dit een standalone script betreft is dit ook niet nodig, maar als je een heleboel (of allemaal) van dat soort pagina's hebt dan wordt het tijd om eens goed na te denken over hoe je deze serveert. Ook als je een wat elegantere foutafhandeling in wilt bouwen (als je die uberhaupt hebt) dan wordt de "paginaflow" belangrijk(er).
Een alternatieve manier zou trouwens een token zijn, die je direct na het POSTen invalideert, zodat alle mogelijke volgende POSTs (die door een refresh werden veroorzaakt) direct afketsen vanwege een ongeldig token. Het gebruik van een token voor formulieren die publiek toegankelijk zijn is sowieso een goed idee omdat dit voorkomt (of het i.i.g. moeilijker maakt) om POST-data rechtstreeks in te schieten vanaf een externe bron. Zo'n token wordt ook wel een CRSF-token genoemd. Dit voorkomt Cross Site Request Forgeries.
Bedankt voor jullie reacties. Ik ga alle opties eens proberen.
Met de header location heb ik trouwens de ervaring dat ik de melding "Warning: Cannot modify header information - headers already sent by" krijg. Maar dat is mogelijk niet te voorkomen omdat ik zowel formulier als afhandeling in hetzelfde bestand heb staan.
Wat het Post/Redirect/Get patroon betreft, heb je zo een voorbeeld van een (eenvoudig) script die op deze wijze gebouwd is? Dan kan ik eens goed kijken hoe het precies werkt.
Als je "Warning: Cannot modify header information - headers already sent by... te zien krijgt, dan heb je blijkbaar output in de vorm van HTML of een zichtbare witruimte voor je header()-functies staan, en dat mag niet. De foutmelding geeft ook aan in welk bestand dit gebeurt, en na de dubbele punt op welke lijn dit plaatsvindt. Als je jouw script zo aanpast dat alle taken eerst worden uitgevoerd in het begin, zonder output te hebben, dan kan het prima.
Er mag best HTML voor de header() functies staan, zolang deze maar niet verstuurd wordt voordat je klaar bent met het instellen van headers. Het kan namelijk best zo zijn dat alle output automatisch gebufferd (opgespaard) wordt en dan loop je nooit tegen deze foutmeldingen aan.
Output buffering kan best meerwaarde hebben, maar om het nu enkel te gebruiken om "headers already sent" meldingen onder het tapijt te vegen is natuurlijk niet echt een goed ontwerpbeginsel, en het spoort je ook niet aan om dingen in de goede volgorde te zetten.
Ik ben nog steeds van mening dat op het moment dat je een pagina/script verschillende dingen wilt laten doen, je deze acties echt zou moeten gaan compartimenteren in aparte onderdelen. Dit omdat anders het gevaar van spaghetti code constant op de loer ligt. Daarnaast heeft het scheiden van acties in verschillende stappen ook het bijkomende voordeel dat je deze acties ook in afzondering kunt debuggen. En ook is dit -wanneer je steeds meer interactie inbouwt in code die onderhand hele HTML-documenten uitspugen- ongeveer het moment dat je na moet gaan denken over een soort van algemene aanpak voor document-opbouw. Zelfs als dit een standalone script is loont het de moeite om een vaste aanpak te volgen. Je kunt namelijk telkens dezelfde code als basis gebruiken, en vervolgens kun je heel snel documenten, en op den duur ook websites, in elkaar zetten. Simpelweg omdat je elke keer hetzelfde sjabloon gebruikt.
Ik weet niet hoe je OOP-kennis is, maar mogelijk biedt dit artikel enige inspiratie.
Even voor de duidelijkheid, de "header location" alleen gebruiken in het geval van een succesvolle verzending. Nooit de terugmelding van de foutieve input via "header location" doen, omdat je dan alle (foutieve) input weer kwijt bent en het formulier opnieuw kunt invullen. Correct?
1) In bestand form.php staat mijn formulier met als actie: action="validate.php".
2) De validatie van mijn formulier vindt dus plaats in bestand validate.php.
3) Indien validatie juist is, dan stuur ik terug naar form.php via header("location:form.php?m=success").
4) In form.php wordt dan via GET het Dank U bericht gegenereerd.
Voor de bezoeker gebeurt alles dus netjes op dezelfde pagina.
Maar in het geval van fout ingevuld veld, moet ik dus een sessie gebruiken om de ingevulde velden te "onthouden"?
Is er geen andere mogelijkheid, zonder gebruik van sessies? Ik wil een sessie juist voorkomen, het formulier zo eenvoudig mogelijk laten.