ColdFusion in Context: Automatic Server-Side Validation

One of the capabilities of ColdFusion is automatic server-side validation. It's not as flexible as ColdFusion's automatic client-side validation (which is implemented by cfform and cfinput tags that automatically generate javascript), but it is available and may generate some ideas. Bear in mind that the two capabilities are not directly related and don't follow the same rules. You can use the server-side validation with plain form and input tags (or with form variables set by other means).

Procedure

To use automatic server-side validation, add hidden fields to a form that contains the fields you want ColdFusion to validate. For each form field you want ColdFusion to validate automatically, create a hidden field that has the same name as the name of the variable to be validated - except that you'll tack one of these suffixes onto the name of the hidden field: _required, _date, _eurodate, _time, _float, _integer, or _range. You would create more than one of these hidden variables if you wanted to impose multiple conditions on the variable to be validated. For example, the existence of the fields "IncidentDt_required" and "IncidentDt_date" makes the entry of "IncidentDt" mandatory and also causes ColdFusion to ensure that the entry can be interpreted as a date. For reasons detailed later, you probably won't use _integer and _range.

Required Variables. When ColdFusion sees a form variable whose name ends in _required, ColdFusion looks for the corresponding form variable name that has no suffix. If it does not find the variable or the variable's value is empty, it defaults to adding this text to an error page: "A value must be entered for the {name of field in bold text} field." You can override the default message by saying value="{my custom message}" as an attribute of the hidden field.

Date Variables (American and European). When ColdFusion sees a form variable whose name ends in _date or _eurodate, ColdFusion looks for the corresponding form variable name that has no suffix. If it finds it, it interprets its content as a date if possible and changes it to an ODBC date. It can understand dates in standard formats such as "4 July 2002". If the user enters 18/3/2002, ColdFusion knows that 18 can't be a month and interprets the date correctly. If it can't interpret the entry as a date, it defaults to adding this text to an error page: "The value entered for the {name of field in bold text} field ('{value}') is not correctly formatted." You can override the default message by saying value="{my custom message}" as an attribute of the hidden field.

If the user enters a date such as 3/11/2002, either of the first two number groups (3 and 11) could be a month depending on whether the date was entered using the U.S. date convention or the European convention. In such ambiguous situations, the action ColdFusion takes depends on the suffix. If the variable ends in _date, it assumes the first number group is a month: 11 March 20002. If the variable ends in _eurodate, it assumes the second number group is the month: 3 November 2002.

Time Variables. If a form variable name ends in _time, ColdFusion looks for the corresponding form variable name that has no suffix. If it finds it, it interprets its content as a time if possible and changes it to an ODBC time. It is very flexible, even accepting periods in place of colons and single digits where you would expect a double digit group (such as minutes) to be needed. If it can't interpret the entry as a time, it defaults to adding this text to an error page: "The value entered for the {name of field in bold text} field ('{value}') is not correctly formattted." You can override the default message by saying value="{my custom message}" as an attribute of the hidden field.

Floating Point Variables. If a form variable name ends in _float, ColdFusion looks for the corresponding form variable name that has no suffix. If it finds it, it tries to interpret it as a floating-point number. If it can't interpret the entry as a number, it defaults to adding this text to an error page: "Data entered in the {name of field in bold text} field must be a number (you entered '{value}')." You can override the default message by saying value="{my custom message}" as an attribute of the hidden field.

Integer Variables. If a form variable name ends in _integer, ColdFusion looks for the corresponding form variable name that has no suffix. If it finds it, it tries to convert it to an integer, truncating anything to the right of the decimal point. If it can't interpret it as an integer by truncating everything to the right of the decimal point, its default is to add this text to an error page: "Data entered in the {name of field in bold text} field must be a number (you entered '{value}')." You can override the default message by saying value="{my custom message}" as an attribute of the hidden field.

Note that the user is not told the value will be truncated. If you asked the user's age, then truncating it is probably OK. If you asked how many years experience the user has with a given tool, the user might consider the difference between 1 year and 1.5 years important, and dropping the fraction may frustrate the user when the data bubbles back out of the database someday.

Range Variables. To specify the range a form variable must stay within, create a corresponding hidden field ending in _range. Specify the end points of the range by placing them inside the hidden field's value attribute in this manner: value="min={minimum} max={maximum}". If a form variable name ends in _range, ColdFusion looks for the corresponding form variable name that has no suffix. If it finds it, it tries to convert it to an integer, truncating anything to the right of the decimal point. (There's that truncation without warning again.) If it can't interpret it as a number and truncate it to form an integer, it defaults to adding this text to an error page: "Data entered in the {name of field in bold text} field must be a number (you entered '{value}')".

If the entry can be converted to an integer through truncation but is not the desired range, ColdFusion's default is to add this text to an error page: "The value entered for the {name of field in bold text} field must be between {min} and {max} (your entry was {value})."

You cannot override either of the default messages for "range". The inability to avoid displaying the raw field name makes the use of the range capability undesirable unless your raw form field names are very friendly (for example, "Events").

Build a Demo Form

Ready to try these capabilities out? Place this code in autoval.cfm. It demonstrates each of the validation methods. Nickname shows _required by itself. The two date validation attributes are shown next. The "Honorific" is displayed as part of a custom message for American date to prove that the error page understands ColdFusion. Default messages are used for the time field - no value is provided to be displayed on failure - in order to show what default messages look like. The form ends by demonstrating floating-point, integer, and range.

<form action="gate.cfm" method="post">
<cfset Honorific="Valued Customer">
Enter the following to see automatic server-side validation
 and formatting...<br>
Enter your nickname: <input type="text" name="Nickname"><br>
<input type="hidden" name="Nickname_required"
value="Enter a nickname so we'll know what to call you">
Enter a date.  If ambiguous, it will be interpreted as American:
 <input type="text" name="YourAmDt"><br>
<input type="hidden" name="YourAmDt_required"
value="<cfoutput>#Honorific#</cfoutput>, enter an American-style date">
<input type="hidden" name="YourAmDt_date"
value="American dates should have numeric {month}/{day in month}/{year}">
Enter a date.  If ambiguous, it will be interpreted as European: 
<input type="text" name="YourEDt"><br>
<input type="hidden" name="YourEDt_eurodate"
value="European dates must have numeric {day in month}/{month}/{year}">
<input type="hidden" name="YourEDt_required"
value="A date to be interpreted as European is needed.">
Enter a time properly or see default gripes: 
<input type="text" name="YourTime"><br>
<input type="hidden" name="YourTime_required"
value="A time must be entered">
<input type="hidden" name="YourTime_time"
value="A time should be formatted as a time value with digits, etc.">
Enter a number to be used "as is": <input type="text" 
name="YourFloat"><br>
<input type="hidden" name="YourFloat_required"
value='Enter a number to be used "as is"'>
<input type="hidden" name="YourFloat_float"
value="The number to be used 'as is' is wrongly formatted">
Enter an number to be truncated to the nearest integer: 
<input type="text" name="YourInt"><br>
<input type="hidden" name="YourInt_required"
value="A number to be truncated is required">
<input type="hidden" name="YourInt_integer"
value="The entry to be truncated is not a number">
Enter a number to be truncated from 3 to 5 inclusive: 
<input type="text" name="YourSpecial">
<input type="hidden" name="YourSpecial_required"
value="A number from 3 through 5 is needed; it will be truncated.">
<input type="hidden" name="YourSpecial_range" value="min=3 max=5">
<input type="submit" name="doit" value="Go">
</form>

View the Back-End Results

Create an action page; call it gate.cfm. Its purpose in this demonstration is to show that some of the validation processes change variables in addition to validating them. Besides, it's nice to see a real page after getting blocked repeatedly by the error dialogue.

MADE IT!
<p>
<cfoutput>
Nickname is: #form.Nickname#<br>
American date is: #form.YourAmDt#<br>
European date is: #form.YourEDt#<br>
Number "as is": #form.YourFloat#<br>
Number truncated: #form.YourInt#<br>
Number truncated from 3 to 5 inclusive: #form.YourSpecial#<br>
Time: #form.YourTime#
</cfoutput>

Run the Demo

Browse autoval.cfm, filling in the fields in various ways, until you get tired of error messages. The error page, with its professional appearance and bullets, really looks pretty good, better than a javascript alert. Further, it displays everything that's wrong, not just the first problem encountered in the form.

Once everything is filled in right, you may be surprised to see what would go into a database if it were inserted now. Adjust date inputs to see how the same date (such as 5/7/1999) will be interpreted two different ways depending on the context. The curly brackets around dates and times indicate that you're looking at the string equivalent of an ODBC date or time.

Considerations for Use

Suppose you haven't been validating your database inputs on the server side until now. You've counted on javascript to block bad input at the client. If this has been the case and you're belatedly finding that your site has users whose talking browsers don't read javascript alerts, it's time to step up to the challenge. You can let those users get raw database errors, or you can consider this technique as a stopgap measure while you work on a custom solution.

One word of warning. This facility is useful to keep the user from getting raw database errors or from putting bad data into the database. However, don't count on this method of validation for important aspects of something like a shopping cart. (You are using more than javascript on your shopping cart forms, aren't you?) If one reason for validating inputs on the server is that an unscrupulous user may hack the form, remember that the user can hack or remove these validation fields as well. =Marty=