Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created June 10, 2022 11:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bennadel/2a2eb3e1131d19600573e045942d2a7c to your computer and use it in GitHub Desktop.
Save bennadel/2a2eb3e1131d19600573e045942d2a7c to your computer and use it in GitHub Desktop.
A Relational Database Table To Prevent Double Form-Submissions In ColdFusion
CREATE TABLE `double_submission_token` (
`token` varchar(50) NOT NULL,
`expiresAt` datetime NOT NULL,
PRIMARY KEY (`token`),
KEY `IX_byExpiration` (`expiresAt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<cfscript>
// Set up default form values.
// --
// NOTE: We're generating a unique token for this form instance. This value will only
// be generated once per form since the post-back will also include the submission
// token thereby avoiding the subsequent CFParam default call to createUuid().
param name="form.submitted" type="boolean" default=false;
param name="form.submissionToken" type="string" default=createUuid();
param name="form.message" type="string" default="";
if ( form.submitted ) {
try {
// By wrapping the processing in a CFTransaction tag, it creates an atomic
// boundary around both "INSERT INTO" queries. This means that if something
// goes wrong with the message insert (the second query), the token insert
// (the first query) will naturally rollback allowing for the form to be
// re-submitted without issue. And, of course, since the submission token has
// a unique index on it (primary key), any accidental double-submission will
// cause a "duplicate entry" error on the first insert, thereby preventing the
// second query from ever executing.
transaction {
```
<cfquery>
INSERT INTO
double_submission_token
SET
token = <cfqueryparam value="#form.submissionToken#" sqltype="varchar" />,
expiresAt = ( UTC_TIMESTAMP() + INTERVAL 1 HOUR )
</cfquery>
<cfquery>
INSERT INTO
ben_message
SET
message = <cfqueryparam value="#form.message#" sqltype="longvarchar" />
</cfquery>
```
} // END: Transaction.
location( url = "./success.cfm", addToken = false );
} catch ( any error ) {
if ( error.message contains "Duplicate entry" ) {
echo( "Oops, it looks like your message is already being processed." );
abort;
}
echo( "Sorry, an unexpected error occurred." );
abort;
}
}
</cfscript>
<!--- Reset the output buffer and render the page. --->
<cfcontent type="text/html; charset=utf-8" />
<cfoutput>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Send a message</title>
</head>
<body>
<h1>
Send a Message
</h1>
<form method="post" action="#cgi.script_name#">
<!--- Posting our double-submission form token back to server. --->
<input type="hidden" name="submitted" value="true" />
<input type="hidden" name="submissionToken" value="#encodeForHtmlAttribute( form.submissionToken )#" />
<textarea name="message">#encodeForHtml( form.message )#</textarea><br />
<button type="submit">
Send message
</button>
</form>
</body>
</html>
</cfoutput>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment