<% @LANGUAGE = "VBscript" %> <% Option Explicit %> <% pageTitle = "Comparison of VBScript/Javascript Validation Functions" pageAuthor = "steve" addFooterSection "/consulting/code.asp", "return to code page" %> <%= openHeader %> <%= closeHeader %>

<%= pageTitle %>

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.

Helper functions

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

Regular expressions

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.

Validation functions

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.

Validating the validator

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.

Downloads

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.

What next?

Some day when I'm not too lazy I'll write a more in-depth article on how to actually use these functions. <%= pageFooter %>