Any time a user submits a form on a web site, you need to validate that data. Validation can be done in two places: on the client's browser, or on the web server.
Client-side validation is mostly just a convenience for the web user. Rather than wait for a form to be submitted and a new page loaded, the user gets immediate feedback and has a chance to correct any errors before the page is submitted.
Even though you may have already validated the data client-side, you still need to do the same validation on the server-side. You have no control over the user's web browser: your clever script might work on their machine, or they might have Javascript turned off entirely. Worse, there is nothing to stop them from simply writing their own web page that submits whatever they want to your server.
The problem I ran into was, how do I know that the validation is being performed identically on both the client and server?
To solve this, I wrote a set of simple validation functions in both Javascript (to run client-side) and VBScript (which is the server-side language we use for most of our projects), then wrote a test program to verify that both sets of functions behaved identically.
First I defined a few simple helper functions:
getdigits. This returns a string with everything but the
digits removed.
Javascript
function getdigits (s) { return s.replace (/[^\d]/g, ""); }
VBScript
function getdigits (s) dim re set re = new regexp re.pattern = "[^\d]" re.global = true getdigits = re.replace (s, "") set re = nothing end function
luhn. This is the luhn
checksum algorithm, used to validate such things as credit card numbers and
bank routing numbers.
Javascript
function luhn (cc) { var sum = 0; var i; for (i = cc.length - 2; i >= 0; i -= 2) { sum += Array (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) [parseInt (cc.charAt (i), 10)]; } for (i = cc.length - 1; i >= 0; i -= 2) { sum += parseInt (cc.charAt (i), 10); } return (sum % 10) == 0; }
VBScript
function luhn (cc) dim sum, i sum = 0 for i = len (cc) - 1 to 1 step -2 sum = sum + array (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) (cint (mid (cc, i, 1))) next for i = len (cc) to 1 step -2 sum = sum + cint (mid (cc, i, 1)) next luhn = (sum mod 10 = 0) end function
Support for regular expressions under VBScript is terrible, so I made a
validateRE helper function.
VBScript
function validateRE (s, regex) dim re set re = new regexp re.pattern = regex re.ignorecase = true validatere = re.test (s) set re = nothing End Function
Most of the actual work is done with regular expressions.
var isNonblank_re = /\S/; var isWhole_re = /^\s*\d+\s*$/; var isInteger_re = /^\s*(\+|-)?\d+\s*$/; var isDecimal_re = /^\s*(\+|-)?((\d+(\.\d+)?)|(\.\d+))\s*$/; var isCurrency_re = /^\s*(\+|-)?((\d+(\.\d\d)?)|(\.\d\d))\s*$/; var isEmail_re = /^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/;
isNonblank. This just checks that the input string isn't
blank.
isWhole checks that an input string is a whole number
(digits only).
isInteger checks that an input string is an integer, with
an optional +/- sign character.
isDecimal checks that an input string is a decimal number,
with an optional +/- sign character.
isCurrency works just like isDecimal, except
that only zero or two digits are allowed after the decimal point
isEmail checks that an input string looks like a valid
email address. I've seen many, many different examples of email address
validation, including huge unreadable thousand-character regular
expressions. Some do as little as just checking for the @ symbol,
others try to verify the top-level domain (.com, .org), etc. Frankly, I
don't see the point. No matter how strict your validation is, some
joker can invent an email address that bypasses it. The best you can do
is check for obvious typos.
Having defined the helper functions and the regular expressions, most of the actual validation functions are trivial one-liners:
Javascript
function isNonblank (s) { return String (s).search (isNonblank_re) != -1 }
VBScript
function isNonblank (s) isNonblank = validateRE (s, isNonblank_re) end function
A few are a bit more complicated...
isValidCC validates a credit card number. Well, it makes
sure something looks like a valid credit card number anyhow. It
doesn't force the user to use any particular format and just ignores
anything that isn't a digit. (I've seen credit card forms where you had
to enter the entire number in a specific format, or without any spaces.
Those programmers were idiots.
isValidCC is table-driven, making it easy to add or remove
cards depending on what the vendor accepts on his site.
function isValidABA (routingNumber) verifies that a string
looks like a valid American Banking Association routing number.
Note that all of these functions ignore leading and trailing spaces. Why? Because someone entering data into a form won't necessarily see those spaces, and won't understand why his perfectly reasonable data is being rejected. You just need to be sure to trim off the spaces after the validation is done.
Okay, now I have all these little functions. How do I know they work identically in both languages?
I wrote a program in VBScript that tests each function with sample data, and shows the output of the VBScript and Javascript versions side-by-side for comparison. I won't describe how it works here, but you can have a look at the output.
Javascript validation functions.
VBScript validation functions. (rename to .asp)
Test program. (rename to .asp)
You'll need an IIS server to run the VBScript files of course.