Note from Will:
I don't do ASP, I just compiled this Article from a
bunch of different web pages.
|
In this article, we will discuss how to use Microsoft ASP technology to handle user-submitted form data and then send that data to someone via email with Microsoft's Collaboration Data Object for NT Server (CDONTS). |
Introduction
Microsoft's Active Server Page technology is a powerful server-side scripting method of web development that allows any web developer with a web server powered by NT's Internet Information Services (IIS) and a basic understanding of HTML and VBScript to create powerful dynamic web pages.
This article assumes that you have the basic HTML and VBScript understanding mentioned above. However, I will explain anything that is crucial to your understanding.
If you have ever created or thought about creating an HTML form for user input on your web site, then you must have also dealt with the issue of handling the data once it is submitted (ie. where does the data go and how does it get there). As you may already know, if you want the information submitted to be emailed to you, you can simply put your email address in the action field of the FORM tag like this:
<form action="mailto:corinth@enfused.com" method="get" enctype="text/plain">
|
TIP: If you do not
have time or the resources to program an ASP
page or Perl
script to handle your form's submitted data, you can use a
little-known HTML trick to make the submitted form data reach your
inbox in a legible fashion. By adding |
However, you probably also know that when you use the
mailto
action, your users will get an obnoxious and frightening security warning, and
we do not want to scare your users away!
To avoid the security alert, you have a couple of options. First, if you are developing in a UNIX environment, using Perl and CGI would probably be your best bet. If that is the case, you should check out Aaron Weiss' The Perl You Need to Know series of articles here at the WDVL.
On the other hand, if you are developing in an NT environment, while you may still use Perl and CGI if Perl is installed on your server, it is recommended that you use ASP because it is easier to code and a bit more intuitive, for novices and experts alike.
In the remainder of this article, I will show you how to use ASP to handle the form data and then send it to an email address using the Collaborative Data Object for NTS (CDONTS), a special Windows NT COM object designed to send mail through the SMTP service on your web server.
Creating
the Form
Adding the
ASP Code
Making the
ASP Page Smart
Working
with CDONTS
Putting It
All Together and Wrapping Up
For simplicity's sake, and to keep all this new information from getting garbled in your brain, we are going to create and use a very simple form that collects only a user's first and last name. If you do not know how to make an HTML form, you can read Alan Richmond's introduction to forms at the WDVL or you can visit Webmonkey for another easy forms tutorial.
Our form page is very simple, so here is the code (we will leave
action blank until later):
<html> <head> <title>ASP Form Sample</title> </head> <body> <form action="" method="get" name="Input_Form"> First Name: <input type="text" size="30" maxlength="50" name="First_Name"> <br> Last Name: <input type="text" size="30" maxlength="50" name="Last_Name"> <br> <input type="submit" value="Submit Form"> </form> </body> </html>
This is what our little bit of code produces:
|
TIP: To make your form fields look nice and aligned on screen, put them in a simple table with two columns to provide more precise positioning. |
If you are following along, save your file as formtest.asp. Or, name it whatever you want but make certain that the file has the .asp file extension. If you have access to an NT server, upload the file and test it to make sure your form is coded correctly. If you do not have access to an NT server, you may download Microsoft's Personal Web Server and test the ASP page on your local machine (Note: When we work with CDONTS later, that will not work on Personal Web Server, it is supported by only NT Server).
Now on to something a little more difficult (and fun)! How in the world can we make this form go to my email address at corinth@enfused.com without popping up that ugly security alert box? It is really easier than you think. Move on to the next page and I will show you how.
Now we have got a nice clean HTML form just crying to be used, but it does not have any action - nowhere to go with submitted data. Next we will add some ASP to make the page more useful.
First, we will begin by adding an
action to our form. For
this particular form, we are just going to make it the name of our file.
However, in many situations you can make it the name of another page depending
on what you are doing with the form. Since I named the file formtest.asp, then
my action tag will look like the following:
<form action="formtest.asp" method="get" name="Input_Form">
Well, that was pretty easy, but where does the ASP come in? So far this page is like just any old page that you could have done in your sleep. All right then, ask and you shall receive! We are now going to add some ASP code to capture the submitted form data and store them in variables.
To begin with, we need to add a fun little symbol to our page that tells the web server ASP code is coming ahead. For our form, we should put this symbol before any HTML code in our sample page. Take a look:
<% ' Note: A single quote denotes a comment in ASP ' (which is primarily powered by VB), just like // double ' forward slashes denote a comment in JavaScript or C++. ' You guessed it, that little <% starts the ASP part of ' the page and if you are really sharp you will also ' guess that %> ends the ASP part of the page. %> <html> <head> <title>ASP Form Sample</title> </head> <body> Our form code, etc... </body> </html>
All right, put your thinking caps on, this next part is crucial to making
your page work properly. Up until now we have not talked about the infamous
method
attribute of the form tag. For an ASP page, this part of the form is
particularly important in that it will dictate how you create the ASP form
handling code. If you use the post method, then the server
will "post" the submitted form data "behind the scenes."
That means the user will not be able to see what happens to the data they
entered, but a script properly coded will be able to access and manipulate that
data.
On the other hand, if you use the
get method, then the
server will append the submitted form data at the end of the URL in your
browser's address bar. You have seen this before (it looks like a bunch of
&formfieldname=inputeddata&formfieldname2=inputeddata
at the end of the URL - it is called the querystring); a lot of the
search engines use it so that you can bookmark your search results page
(something you cannot do when the post method is used).
So which method is best? There is not clear-cut answer to that question,
suffice it to say that it depends entirely on your needs and what your form
does. Basically, if you want to let the user bookmark the resulting page, use
the get method. Otherwise, use the
post
method.
I am going to briefly show you how to code the ASP for both methods. ASP deals with two fundamental objects (there are more, but we are only dealing with the big two in this particular article): Request and Response. Response has many uses and methods (a method is a function that an object performs), but its primary use is to write text (or HTML) to a web page. Request also has many uses and methods, but it is primarily used for obtaining information from the client. Remember, we are dealing with a server-side scripting environment, so it all makes sense. The server "responds" to a client "request." Got it? If not, I will provide some links to some ASP resources at the end of this page.
With either method, you must use the Request object to get the submitted
information. If you decided to use the post method, you will
need to use the following code:
<%
Dim fname, lname
fname = Request.Form("First_Name")
lname = Request.Form("Last_Name")
%>
In the above code, we are simply using the Forms collection (or a group of common or related items - namely the fields of the form) of the Request object to get the information that the user submitted on your web page. The syntax for objects and collections or methods is simple and consistent throughout ASP pages (with few exceptions): Object.Collection("ITEM_NAME") or for methods, Object.Method("METHOD_PARAMETERS").
If you chose the get method (which is assumed throughout
the rest of this article), you cannot use the Forms collection at all and must
use the Querystring collection, which acts exactly the same as the Forms
collection except it is simply a collection of data in the querystring. Here is
the code:
<%
Dim fname, lname
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
%>
Again, the above code uses the standard Object.Collection syntax as
I described before. You will note that in both cases, the Item Name is the same
as the name attribute of the form's input tags. That is not
an accident. Whether you use the Querystring or Form collection, you will need
to reference the name you assigned to the input tags when you created your form.
At this point, I would say we are doing pretty well, but there is one problem: every time someone accesses the page, this ASP code is going to be executed. What if we add some Response code to write a little thank you message, like this:
<%
Dim fname, lname
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
Response.Write("Thanks for submitting your name!")
%>
Even if the user never submits the form, they are going to see the thank you message and that is no good! What is worse, once we add CDONTS, the server will return a cryptic ASP error - and you want to avoid them, trust me.
On the next page, we will discuss how to avoid this annoying problem using a hidden form field and some simple conditional testing.
ASP and VBScript Links:
15 Seconds (Advanced)
ASP Toolbox
ASP Watch
Learn ASP
MS
on ASP Microsoft
VBSCript Reference PowerASP
Webmonkey ASP
Tutorials
We have got a web page, a simple form and some ASP code to store any submitted data in variables, but sadly, our page is a page of very little brain. Everytime the page is called from the browser it executes the ASP whether the user presses submit or not; and, while it will not cause problems as-is, as soon as we add code that actually does something with those variables, things will get messy. Just look at how ugly ASP error messages are:
Microsoft VBScript compilation error '800a03f9'
All right, all right, you caught me, I am exaggerating a bit. The error messages are not that bad, they usually include a line number and some frighteningly intelligent help message. *grin*
Moving on, I think the reader will agree that we should avoid those crazy
errors altogether. In order to ensure that our web page does not execute the
form handling code without submitting the form we can use a very simple
conditional test using if...then logic. We will test for a
special "hidden" form field that we add to our form like so:
<form action="formtest.asp" method="get" name="Input_Form"> <!--Existing form code--> First Name: <input type="text" size="30" maxlength="50" name="First_Name"> <br> Last Name: <input type="text" size="30" maxlength="50" name="Last_Name"> <br> <!--Insert new form field--> <input type="hidden" name="isSubmitted" value="yes"> <!--Finish off form with the rest of the exisiting code--> <input type="submit" value="Submit Form"> </form>
If you are not familiar with hidden form fields, do not worry, they are really self-explanatory. Basically they are form fields hidden from the user's view in that they do not show up on the web page but are submitted with every other field and are given the value you, as the designer, assign when the page is created. Easy, no?
For our purposes, the hidden form field is named descriptively as "isSubmitted" with an assigned value of "yes." Here we come to the hardest part of making our ASP smart - the ASP! However, you will quickly see that it is considerably less difficult then you may be expecting.
To begin, we need to revisit our existing ASP code:
<%
Dim fname, lname
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
Response.Write("Thanks for submitting your name!")
%>>Now, to add some conditional testing all we need to do is take this existing
code and put it inside a simple if...then statement like so:<%
if [some condition is true] then
Dim fname, lname
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
Response.Write("Thanks for submitting your name!")
end if
%>
All that is missing is the condition itself (indicated above as
[some
condition is true] above), which is equally easy thanks to the
QueryString Collection that we discussed before. Let's walk through this one
together so there are no questions in anyone's mind about how the condition is
set up. First, what variable are we testing for? Every conditional test has to
have a variable to test and an anticipated result that is either determined to
be true or false in each case. How about Request.Querystring("isSubmitted")
= "yes"?
TIP: If you are
relatively new to VBScript (the language driving the ASP), then you
should note that it is syntactically different from JavaScript. For
instance, if you were coding an if...then
statement in JavaScript then you would type:if (condition is true) { processing... processing... }
In
VBScript, you have to remember to include
then and
end if as illustrated above. If you leave these
things out your code will not work properly. |
In this case our test variable is the
isSubmitted form
field as it is stored in the querystring after submission. The anticipated
result is that this condition will be true and then execute whatever code
follows the then part of the
if
statement. If the condition is false (if
Request.Querystring("isSubmitted") does not equal
"yes" or is empty (which occurs only when the form is not submitted),
then the ASP form handling code will not be executed.
At this point, you should be starting to see the potential of ASP form handling. For example, you can check the validity of form fields with server-side ASP instead of using client-side JavaScript. If the user has a browser that does not support JavaScript or they have it turned off, your ASP web page will still be smart enough to validate their submitted data.
Another possible use for the skills obtained through this tutorial would be to create individual portions of a web page dynamically, as the user is actually using the page. For instance, when I was working on Carcruises.com, the owner asked if we could have a more intuitive way of finding car cruises. So, we developed a system wherein the user picks the state for which they want to locate a cruise. Then, the ASP form handling code matches the selected state to the corresponding months available in the database using an SQL query. Next, the ASP writes a new select box to the page that lists the results of the query. Not only is this method more functional, it leaves room to make web pages that are incredibly intelligent. To top it off, it was all done using the techniques we have been discussing (and a little SQL of course).
All that remains to be done at this point is to process the submitted form data; and, as I told you in the beginning, we are going to send the data via email to your email account using Windows NT Server's Collaboration Data Object (CDONTS).
However, to use CDONTS, we ought to know what it is first. The Collaboration Data Object, according to some Microsoft documentation:
"CDONTS is a Simple Mail Transfer Protocol (SMTP) specific OLE server that is specifically designed to provide Messaging functionality to Web-based applications."
In non-Microsoftese, that means CDONTS is something that acts as the middleman between your web page and the SMTP server, enabling communication that will allow you to send data from the web (like our form) to someone via email.
CDONTS is very powerful and feature-rich, but for now, we are going to keep it simple. I will provide links for some other tutorials on CDONTS at the end of this page. First things first, whenever you use a server object like CDONTS you need to invoke an instance of it (or, in simpler terms, make it available for use). To do that we are going to add a few lines to our form handling code. All the code for CDONTS is explained line-by-line following the example.
<%
if Request.Querystring("isSubmitted") = "yes" then
Dim fname, lname
Dim objCDO
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
'Here is where we insert new code to invoke CDONTS
'This line invokes the object using the name objCDO
Set objCDO = Server.CreateObject("CDONTS.NewMail")
objCDO.From = "corinth@enfused.com" 'That's me :)
objCDO.To = "youremail@domain.com"
objCDO.Cc = "someoneimportant@whitehouse.gov, buycheese@cheese.com"
objCDO.Bcc = "bgates@microsoft.NET"
objCDO.Subject = "Submitted form data from my page"
objCDO.Body = "Name: " & fname & " " & lname
objCDO.BodyFormat = 1
objCDO.MailFormat = 1
objCDO.Send
'Notice that response.write changed to ConfirmMsg =
'I will explain why in just a little while.
ConfirmMsg = "Thanks for submitting your name!"
end if
%>
Now, let's go through that line-by-line, so you know exactly what is going
on. Keep in mind that everytime you want to reference a method or property of
the object you invoked, you need to use the name you assigned (in this example,
objCDO
followed by a period, as illustrated below. (Note: It does not matter in what
order these values are assigned, so long as they all precede the
Send
command).
To begin, From is the email address, as a string, of the
user sending the email. For now, make this your email address. Normally it would
be wise to allow the user to fill this field in, and I will show you how to do
that at the end of the article. However, I recommend that you try it on your own
first to ensure you have a grasp on what we have been doing thus far.
objCDO.From = "corinth@enfused.com" 'That's me :)
| TIP: Do not send me spam | On the other hand, all legitimate emails, questions, comments or criticisms are welcome. Just keep in mind that I am a busy guy and may not be able to reply very promptly to all of them. |
|---|
To is the email address of the intended recipient. Make
this field your email address(es). Multiple Addresses may be separated by commas
(in any field as a matter of fact). Do not forget the quotes in any of these
fields, they must all be string values.
objCDO.To = "youremail@domain.com"
CC,
BCC are the email addresses of any
Carbon Copies or Blind Carbon Copies you would like to send.objCDO.Cc = "someoneimportant@whitehouse.gov, buycheese@cheese.com" objCDO.Bcc = "bgates@microsoft.NET"
Subject is any string you provide that will be displayed
as the subject of the email,
objCDO.Subject = "Submitted form data from my page"
Body is the body, or main content, of the message. You can
put anything you want in here, in the format of a string, so long as it can be
sent via email. We are just going to put our variables in here and send them.objCDO.Body = "Name: " & fname & " " & lname
| TIP: The above code illustrates an important and powerful element of ASP and CDONTS, the designer can assign variables to these CDONTS attributes rather then using hard-coded strings. That ability expands your capacity to work creatively. Try to come up with some ways to make your life easier by using string variables. Perhaps you could make the subject a form field, thereby allowing users to submit their own subject. |
The next two properties determine the type of email sent, whether it is HTML
or plain text. For our purposes, we will be sending the message as plain text.
However, should you want to send HTML simply change these values to 0 and make
the Body string HTML code.
objCDO.BodyFormat = 1 objCDO.MailFormat = 1
Finally, the last bit of code actually tells the server to send the message.
objCDO.Send
As for that little trick with
ConfirmMsg = instead of
Response.Write,
that was done in order to better format our confirmation message. When we apply
the final touches to the whole page, I will show you what we are going to do
with the ConfirmMsg variable.
That is really all there is to CDONTS, at least for our purposes. I have created a handy CDONTS reference table to help you while you are coding. All that remains is for you to move onto the next page where we will put it all together and I will show you a few extras you can add in, should you so desire.
CDONTS Links:
ASP Today: Setting Up
and Using CDONTS
15 Seconds: Sending HTML
with CDO
15 Seconds: Collaboration
Data Object and IIS 4.0
Power ASP:
Using the CDONTS component...(includes attachments).
ASP
Watch: Sending E-mail using CDONTS
Microsoft
CDONTS Documentation
We have come a long way since the beginning of this tutorial. If you have successfully made it this far then pat yourself on the back because you have learned a lot. Once you get some practice, you will be able to take this fairly simple concept, some creativity and some elbow-grease to create very intuitive and complex dynamic pages.
Below you will find the complete source code (for a working "live" version of the code, visit this test page I set up at Enfused). Following the code is explanation that should tie up any loose ends and some enhancements you may want to consider. As an additional note, I've removed the email addresses for the CC and BCC code in the example because we do not want to accidentally spam someone in case those dummy addresses I cooked up were real.
<%
if Request.Querystring("isSubmitted") = "yes" then
Dim fname, lname
Dim objCDO
fname = Request.Querystring("First_Name")
lname = Request.Querystring("Last_Name")
Set objCDO = Server.CreateObject("CDONTS.NewMail")
objCDO.From = "corinth@enfused.com"
objCDO.To = "corinth@enfused.com"
objCDO.Cc = ""
objCDO.Bcc = ""
objCDO.Subject = "Submitted form data from my page"
objCDO.Body = "Name: " & fname & " " & lname
objCDO.BodyFormat = 1
objCDO.MailFormat = 1
objCDO.Send
ConfirmMsg = "Thanks for submitting your name!"
end if
%>
<html>
<head>
<title>ASP Form Sample</title>
</head>
<body>
<% if ConfirmMsg <> "" then %>
<h2><%= ConfirmMsg %></h2>
<% end if %>
<form action="formtest.asp" method="get" name="Input_Form">
First Name:
<input type="text" size="30"
maxlength="50" name="First_Name">
<br>
Last Name:
<input type="text" size="30"
maxlength="50" name="Last_Name">
<br>
<input type="hidden" name="isSubmitted" value="yes">
<input type="submit" value="Submit Form">
</form>
</body>
</html>
The first major change you are likely to notice is the extra code dealing
with ConfirmMsg in the HTML portion of the page. As
promised, I will explain.
<% if ConfirmMsg <> "" then %> <h2><%= ConfirmMsg %></h2> <% end if %>
Using another conditional test, the page checks to see if
ConfirmMsg
is not a zero-length string (or is not empty). If
ConfirmMsg
is empty that means the ASP form handling code did not execute and
assign "Thanks for submitting your name!" to
ConfirmMsg
and will therefore not write anything to the page. However, if
ConfirmMsg
is not empty, that means the ASP code was executed and it should
display the message.
Another item of note is that one may use one line of ASP to initiate a
conditional test or loop, followed by HTML and then followed with ASP again. The
ability to "sandwich" HTML in between looping or condition testing
becomes more important as the complexity of the HTML to be written on every loop
or test increases. Also, note that the <%= ConfirmMsg %>
is a special form of ASP code. When the <% is followed by
an equals sign (=) then the ASP processor acts in an output mode, allowing the
designer to use a variable name without typing
response.write(varName).
The possibilities for enhancement here are endless. One possibility, that I
asked you to try earlier, is to allow users to enter their own email addresses
for the From attribute of CDONTS. To do it, first add a
field to your form like:
Email Address: <input type = "text" size = "30" maxlength = "50" name = "Email_Address">
Then, using your ability to assign variables (and still assuming the
get
method is being used) add a variable for the email address, like so:
EmailVar = Request.QueryString("Email_Address")
Finally, change the CDONTS code to the following:
objCDO.From = EmailVar
You can do the same with any of the CDO variables, depending on your needs. At Enfused we designed a special "Recommend to a Friend" page that uses these same exact techniques, allowing the user to send mail from our site with whatever values they want.
Another possibility includes writing the submitted form data to a database, like we did on Enfused's Suggest a Site page. With only a little extra coding and some SQL know-how, doing this can be quite easy because ASP has a special database-connectivity object, called ADO, to make your life easier. For some more info about working with ADO, check out this recent WDVL article on the subject.
In this tutorial, we learned about Microsoft's Active Server Page technology and how to use it along with the NT's Collaboration Data Object (CDONTS), to create a page that will email user-submitted form data. Forms drive interactivity and the Internet, and correctly harnessed, will allow you to make the best web sites possible. With these techniques and some practice, the sky is the limit on what you can do.
| Ever need to make sure a user enters data in specific fields on a form, but did not know how? Ever need to make sure a phone number actually looks like a phone number? Most of us have and in this article, we will discuss how to use Microsoft ASP technology to validate data submitted from a form. |
In my last article, I introduced you to the idea of using Microsoft's Active Server Pages to handle data submitted from a form on a web page. With that foundation in hand and some practice, one can create powerful, dynamic web pages. Building on that foundation, this article will show you how to gather user input from a web-based form and then test the validity of that input.
The first thing to accomplish is to make certain that we all understand the goals that this article aims to achieve. When someone says "form-field validation," they mean "validating" or checking the data submitted in a form-field. To be clear, "validation" does not mean making sure that the submitted data is correct in that it is either true or false (ie. validation does not check to ensure that someone named John enters his real name in a form-field. He may enter "Schmoe" or "Cheesehead" as far as the form is concerned), rather it means to ensure that the data is valid in such a way that it falls within certain presupposed parameters. Simply put, it means that when a user is asked to enter their social security number in a field designated to be a social security number, that they will not enter their address or dog's name.
If that is unclear, here is an illustrated example to guide you through that grammatical mess above.
Validation: Incorrect Concept
User's Real Name: "John Doe"
Validation does not make sure that John Doe enters John Doe, the anonymous nature of the Internet does not give web pages the ability to know and check a user's name, so Iza Goodboy will go through without question.
Validation: Correct Concept
User's Real Name: "John Doe"
In this case, the web page with form-field validation will catch the fact that the user entered a number instead of a name (which obviously consists of characters not numerals). This example correctly illustrates the concept of form-field validation.
On the next page, we will discuss the first building block of form-field validation, giving the form a memory.
If you remember the first article in this series then you will remember how we took submitted form data and stored it in variables as follows:
<%
Dim fname, lname
fname = Request.Form("First_Name")
lname = Request.Form("Last_Name")
%>
Assuming the HTML form is
using method="post" the, above code takes
First_Name
and Last_Name in the Forms Collection and stores them in
fname
and lname respectively. To take it a step further, recall that
using a conditional statement, we ensured that the ASP code only executed when
the form was submitted and a condition was met. When taken as a whole, it
becomes very easy to make a form have persistent memory. If you are confused
about what giving a form memory means, it is actually a rather simple concept
that you probably see everyday on the Web. Have you ever completed a page of a
multi-page form, submitted it, realized you made a mistake on page two, and
wanted to go back and fix it? You and everyone else! Well designed sites will
save the information you entered in the form until you are completely finished
entering the relevant data. All that you need to do in your own web page is add
some simple code to the form-field tag. Below is an example of how this would be
accomplished with the First_Name above.
<form action="formtest.asp" method="post"> ... ... <input type="text" name="First_Name" value="<%=fname%>"> </form>
Through the use of the value attribute, ASP allows us to
literally complete the HTML code before it reaches the client using server-side
variables. The great thing about VBScript and ASP in this instance, is that
variables do not need to be defined in order to return a value. This fact is
important when the page is accessed for the first time before the form is
submitted. In such a case, fname will just be empty and
value
will end up looking like value="" to the client and the
form-field will be blank. After the form is submitted for the first time, the
server will automatically insert the value of fname in the value,
giving your form simple memory!
| NOTE: There are other ways to give forms memory. The method we are using will only last as long as the user keeps the browser open and pointed to our site. If we need to save form-field information for later use, we need a more robust and persistent solution. One possibility is to use cookies to store the relevant values. Then, instead of storing submitted form-field data in variables, one would store data taken directly from a Cookies (which in ASP has a collection just like Forms). The input tag would look exactly the same. This method is particularly useful for shopping carts or storing payment information on an e-Commerce site like Buy.com. |
To achieve the same effect with a
select or
checkbox
(or any other potentially multi-valued field) you need to do a little more
advanced processing. For example, the following code will give a field for
"State" memory:
<% state = Request.Form("state") %>
<select name="state">
<option value="noneSelected">- Select from List -</option>
<option value="Alabama"
<% if state="Alabama" then response.write("SELECTED") %>>
Alabama - AL</option>
<option value="Alaska"
<% if state="Alaska" then response.write("SELECTED") %>>
Alaska - AK</option>
<option value="Arizona"
<% if state="Arizona" then response.write("SELECTED") %>>
Arizona - AZ</option>
<option value="Arkansas"
<% if state="Arkansas" then response.write("SELECTED") %>>
Arkansas - AR</option>
...
...
<option value="Wyoming"
<% if state="Wyoming" then response.write("SELECTED") %>>
Wyoming - WY</option>
</select>
Now that you understand how to give your form memory, the first thing to do is go back to your form and implement this functionality now, before doing anything else. This step will be time-consuming to you as a developer, but will make your visitors happier, and that is (should be) a primarily goal of all web developers. Once you have done that, move on to the next page and we will begin talking about actually validating the submitted form data.
The most commonly used and simple need for validation is to ensure that your site visitors do not leave a crucial form-field blank. You could use client-side scripting to prevent this, but not all users will have the right type of browser or JavaScript support enabled. So, to make sure no one slips through the cracks, it is time to use some server-side scripting to accomplish this task. For this example, let us assume that you have a form with First Name, Last Name, Social Security Number, Address, City, State, Zip Code, Telephone Number and Email Address - like this one (feel free to use the source code for this standard form on your own pages):
Next, assume that none of the fields can be left blank when submitted. The
best thing for you as a developer to do, is to write a small block of code that
will check each form-field sequentially. We will accomplish this task with a
For...Each
loop inside our conditional test that makes sure the form has been submitted. Note:
For...Each loops are used in VBScript and ASP to sequentially
iterate, or move through, each item in a collection.
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if Request.Form("isSubmitted") then
...
...
ErrorMsg = ""
x = 0
For Each formField in Request.Form
if Len(Request.Form(formField)) = 0 OR Request.Form(formField)
= "noneSelected" then
errorArray(x) = True
ErrorMsg = ErrorMsg & Ucase(formField) & "<br>"
else
errorArray(x) = False
end if
x = x + 1
Next
%>
You are probably thinking that was a pretty big mouthful for such a small request, so let's take a look at what this little block of code does, line by line.
const numFields = 9 is a constant that we set equal to the
number of fields in the form we are validating. Using constants is a good
practice because if you ever re-use this code elsewhere you can keep everything
the same, change the constant, and validate as many fields as necessary.
dim errorrArray() sets up, or declares, an array named "errorArray,"
whose length is not defined. We will be using this array to store the names of
the form-fields that return errors so that they can be referenced later to
provide meaningful error messages to your users.
The next line, redim preserve errorArray(x), redefines the size
of the array to match the current value of numFields. Remember, this array is
where errors are being stored, so it is important that it matches the number of
form elements in the collection. The little extra bit of code,
preserve,
basically makes sure that the array is kept active in memory throughout the rest
of the code.
if Request.Form("isSubmitted") then is there only to
show you where this code block of code is going in relation to our conditional
statement that checks to see if the form is submitted. The two ellipses (...)
indicate whatever code you may already have there, like the code that stores the
values of the form-fields in variables.
ErrorMsg = "" and
x = 0 both initialize
variables (ErrorMsg and x, respectively) with a default value of an empty string
for ErrorMsg and 0 for x. ErrorMsg is a string that will be used to store an
HTML-formatted message displayed on the page when a validation error occurs
(more on this later). X is being used as a type of counter that will start at 0
and continue to increase until the For...Each loop is concluded. It
will be used to reference specific locations within the array, errorArray.
For Each formField in Request.Form is a special version of a
For...Next
loop called a For...Each loop that sequences through a collection,
in this case our form. On each iteration of the loop,
formField
will be equal the name of the current form-field in the collection. For example,
if the loop is on Zip Code, formField will equal "zip_code"
and the this Request.Form(formField) code will return the value of
zip_code.
Pretty convenient, no?
if Len(Request.Form(formField)) = 0 Request.Form(formField) = "noneSelected"
then is a simple conditional statement that asks "If the current
form-field has no length (is empty) or is 'noneSelected" for the state
field, then do the following..."
errorArray(x) = True and
ErrorMsg = ErrorMsg &
Ucase(formField) & "<br>" are executed when the
previous if statement is found to be "True" or when the value of the
current form-field is empty. Thus, the current element of errorArray is set to
"True" to denote an error and the ErrorMsg string is set
to equal itself (in case this is not the first error) and then adds the name of
the form-field that is incorrect.
If the form-field does have a length, or is not empty, then the current element in the errorArray is set to "False" since there is no error to report.
x = x + 1 increments x every time each time the code loops.
Okay, if you have followed that successfully, (if not, email
me and I'll help if I can) the next step is to provide some notice to the
site visitor that they have submitted an error. This step is actually very easy,
we simply add a small conditional test right underneath the
body
tag (or wherever you want):
... <body> <% if ErrorMsg <> "" then %> <font color="red" size="3"><b> <%= ErrorMsg %> </font><br> <% end if %> <form name="sample1" method="post"> ...
All this code does is ask: "If the
ErrorMsg variable is not
empty, then there is an error message to tell the user, so I will output it in
big red bold text." If there is no value in
ErrorMsg then the
output is ignored and the form is returned as usual. At this point, you are
probably asking what that silly array was for, and now I will tell you. Have you
ever seen the forms where the name of the field that was left blank is a
different color or bold? We are going to recreate that effect using this array.
If you think this part is going to be hard to do, don't, it is not. All that needs to be done is not unlike what you already did to retain the value for the state field. Before each "caption" for the input fields, you simply need to put, in ascending order (from 0...n) a check to see if the corresponding value of the array is true or not. The following code will show you exactly what to do if that is not clear:
<tr> <td><% if errorArray(0) = "True" then %> <font color="red"><b> <% end if %>First Name: <% if errorArray(0) = "True" then %> </b></font> <% end if %> </td> <td> <input name="first_name" size="25" maxlength="50" value="<%= first_name %>"> </td> </tr> <tr> <td> <% if errorArray(1) = "True" then %> <font color="red"><b> <% end if %>Last Name: <% if errorArray(1) = "True" then %> </b></font> <% end if %> </td> <td> <input name="last_name" size="25" maxlength="50" value="<%= last_name %>"> </td> </tr>
| WARNING: In writing this article, I believe I discovered some type of bug or oddity about the ASP compiler. Every form element will be read in sequentially, as they are coded. However, for whatever reason, this particular page grabs City before Last Name. I asked around, and no one is certain why. So, a word of caution to you, although errorArray(1) should be for Last Name, it is actually City, and errorArray(2) is Last Name. Needless to say, if you encounter problems, experiment a bit to see what order the form elements are being processed. |
NOTE: The second
check of the array after the caption is actually to put in
the closing tags for font and
bold. However,
these really are not necessary. One of the neat things about tables is
that, in most browsers, the ending </td> actually
ends any formatting within that cell. However, the WDVL believes in
compliant code and so, if you want to be correct, close the tags. If
not, omit at your own discretion and risk. |
If you would like to see this in action, I have set up a demo on Enfused.com. Please note that I added the code to my form so that it has short-term memory of what the user submits.
Once you have played around a bit and tried this stuff yourself (which I might add is the only true way to learn), move on to the next page and we will talk about validating specific fields.
You now know how to make sure something is at least entered for every field, but what about specific fields? What if you do not care if someone enters their last name but must have them enter a valid first name? Not a problem, this can be accomplished very easily building on the skills you have already acquired reading this article. First, we are going to drop the validation code we used on the last page and do each field individually. There is, of course, a disadvantage to this method in that you cannot easily re-use proprietary hard-coded validation code in other forms you utilize in the future. However, if you are a savvy programmer, there are ways to make everything very general and re-usable. If you just want to check for empty fields, the code we discussed on the previous page will work great for most anything.
Instead of the code on the previous page, try the following instead:
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if Request.Form("isSubmitted") then
...
...
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = "Last Name<br>"
end if
end if
%>
Rather then going through that line-by-line (since most of it should be
familiar to you), let's take a quick look at the code inside the second
if...then
statement. It says: if Len(last_name) = 0 then,
errorArray(1)
= "True" and
ErrorMsg = "Last Name<br>".
As you probably surmised, this little block is hard coded to see if last_name
(did you remember to assign Request.Form("last_name") to a variable? I
called mine last_name) has any value. If it does not, then element
1
of the errorArray is hard coded as "True" and the
ErrorMsg
variable is set equal to "Last Name" and an HTML line-break.
That covers last name, but what do we do about First Name, which we have decided is both a required field and one that we must validate to ensure that a valid submission is entered. To begin, start easy and just make sure the field has a value at all by repeating what we did for Last Name.
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if Request.Form("isSubmitted") then
...
...
if Len(first_name) = 0 then
errorArray(0) = "True"
ErrorMsg = "First Name<"
end if
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = ErrorMsg & "Last Name<br>"
'Note, I added ErrorMsg & to this line to make
'sure we keep the whole string
end if
end if
%>
That part was easy, now all we need to do is make sure that name is not a number or some other invalid value. To do that, there are a number of options, of which two are most popular: regular expressions and string searching. Regular Expressions are probably something with which you Perl fans are very familiar. It is the life-blood of string-handling and comparison with Perl, as Aaron Weiss points out in his The Perl You Need to Know series. For those who do not know, a Regular Expressions is a pattern that you define with letters, numbers and symbols that is then compared against a string. The computer tries to match this pattern to the same pattern in the string. If a match is found, True is returned, if not False is returned. If that does not sound familiar to you, you have actually probably used Regular Expressions before. Think of when you went to Start >> Find in Windows and entered files of type *.doc. When you did that, you were searching for all files that matched the extension .doc - that is a regular expression. Unfortunately, Regular Expressions are something of a new beast to VBScript for the Web and ASP, and as such, they are handled a bit differently then Perl Regular Expressions. We will discuss this more in a few minutes.
The other option you have is to actually perform more complex string
searching on the field, in our case first_name, using string
specific functions. Quite honestly, I have had mixed results when trying to use
regular expressions in ASP (probably because I learned them in Perl) and as
such, I tend to stick to using string functions, even if they are a little less
efficient code wise. At any rate, I will show you how to do both with an
emphasis on regular expressions because they are far more useful and easy once
you have gotten the hang of them.
To begin, we will use some looping and a string function to figure out if
first_name
has any non-characters in it. To do that, we will need to loop through every
character in first_name. We will do that with a
for...next
loop, like so:
<% ... for y = 1 to len(first_name) testVar = mid(first_name, y, 1) if (asc(testVar) < 65) or ((asc(testVar) > 90) AND (asc(testVar) < 97)) or (asc(testVar) > 122) then errorArray(0) = "True" ErrorMsg = "First Name<br>" Exit For end if next ... %>
Alright, that looks pretty complex, but do not worry, the code is explained line-by-line below.
for y = 1 to len(first_name) starts a
for...next
loop that loops from one (1) to the length (or to the max number of characters)
in first name.
testVar = mid(first_name, y, 1) sets the variable testVar equal
to the value returned by the mid funtion performed on the string,
first_name. The syntax for mid is
mid(string, start, length).
if (asc(testVar) < 65) or ((asc(testVar) > 90) AND (asc(testVar)
< 97)) or (asc(testVar) > 122) is a conditional test that converts
the value of testVar into its ASCII value. If it is less then 65,
in between 90 and 97, or greater then 122, it is not an alphabetic character
(for a list of the
ASCII characters and their decimal equivalents, check
this site out.) If the character is not alphabetic, the code inside the
if...then
is executed, which is our standard error code. The only change is the
Exit
For which basically tells the
for...next loop to call it
quits, since we have already found at least one error.
The only thing left to explain is where this code goes in the grand scheme of things, so check it out below. You will see that it first checks to make sure the field is not blank, then if it is not, it will check for non-alphabetic characters.
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if Request.Form("isSubmitted") then
...
...
if Len(first_name) = 0 then
errorArray(0) = "True"
ErrorMsg = "First Name<br>"
else 'here is the new code
for y = 1 to len(first_name)
testVar = mid(first_name, y, 1)
if (asc(testVar) < 65) or ((asc(testVar) > 90)
AND (asc(testVar) < 97)) or (asc(testVar) > 122) then
errorArray(0) = "True"
ErrorMsg = "First Name<br>"
Exit For
end if
next
end if
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = ErrorMsg & "Last Name<br>"
'Note, I added ErrorMsg & to this line to make
'sure we keep the whole string
end if
end if
%>
That really was not too bad, but it seems fairly tedious to go through every
character with a for...next loop. That is where Regular Expressions
come in. If you can get set up and working properly, then they are definitely
the way to go, and you will see why in a minute.
For starters, I recommend you check out Microsoft's
VBScript Regular Expression Introduction, if you are brand new to the
technique (or if you are a very Perl oriented individual). Once you've glanced
through that and printed out the Regular
Expression Syntax page, study the following code that performs the same
thing as our for...next
loop above. In fact, this particular
Regular Expression kills two birds with one stone by eliminating the need to
check for a blank field!
<% ... dim re, results set re = New RegExp re.Pattern = "^\D+$" re.Global = True re.IgnoreCase = True results = re.Test(first_name) if results then errorArray(0) = "False" else errorArray(0) = "True" ErrorMsg = "First Name<br>" end if ... %>
To begin, you must declare the variables
re and
results
(you can name them whatever you want). Then, we invoke the
RegExp
object in the form of an instance, re.
Following that, it is important to set some parameters for the regular
expression. Most importantly is the pattern that will be matched, which is,
^\D+$.
If you check out that reference sheet I asked you to print, you will note that
\D
stands for any non-digit character, while the + tells the Regular
Expression to match one or more of these characters. The
^ and
$
makes sure it checks and is limited to the whole string. Granted, that means it
will not pick up symbols, but that is not necessarily a bad thing if a foreign
name is possible. However, if you want to be thorough, try this:
re.Pattern
=
"^[^0-9\/><\.,\\!\^\$\*\+\?@#%&\(\);:\[\]\{\}=""']+$".
Yes, that is frightening, but all it says is not (^) 0-9 or any of
the symbols following. If there is a backslash before a symbol, that means it
has been "escaped." Symbols that represent a behavior in a Reqular
Expression must first be escaped if you want to search for them. Whichever you
decide to use, if results is found to be true (and the pattern is
matched), then there is no error, else there is and we note that with our array
and ErrorMsg.
As you can see, while a bit more complex, this is very effective at finding patterns in a string. This feature will make itself more evident when we get into validating specific patterns like social security numbers, telephone numbers, etc. on the next page. If you would like to see Regular Expressions in action, visit this other sample at Enfused. Also, just for your convenience, here is what the code will look like in the whole scheme of things:
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if request.form("isSubmitted") = "yes" then
...
...
ErrorMsg = ""
dim re, results
set re = New RegExp
re.Pattern = "^[^0-9\/<<\.,\\!\^\$\*\+\?@#%&\(\);:\[\]\{\}=""']+$"
re.Global = True
re.IgnoreCase = True
results = re.Test(first_name)
if results then
errorArray(0) = "False"
else
errorArray(0) = "True"
ErrorMsg = "First Name<br<"
end if
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = ErrorMsg & "Last Name<br<"
'Note, I added ErrorMsg & to this line to make
'sure we keep the whole string
end if
end if
%>
I do not want to overload you in this tutorial, so on the next page I will guide you through a few more regular expressions for common fields and then we will call it quits so you can go practice.
That really was not too bad, but it seems fairly tedious to go through every
character with a for...next loop. That is where Regular Expressions
come in. If you can get set up and working properly, then they are definitely
the way to go, and you will see why in a minute.
For starters, I recommend you check out Microsoft's
VBScript Regular Expression Introduction, if you are brand new to the
technique (or if you are a very Perl oriented individual). Once you've glanced
through that and printed out the Regular
Expression Syntax page, study the following code that performs the same
thing as our for...next
loop above. In fact, this particular
Regular Expression kills two birds with one stone by eliminating the need to
check for a blank field!
<% ... dim re, results set re = New RegExp re.Pattern = "^\D+$" re.Global = True re.IgnoreCase = True results = re.Test(first_name) if results then errorArray(0) = "False" else errorArray(0) = "True" ErrorMsg = "First Name<br>" end if ... %>
To begin, you must declare the variables
re and
results
(you can name them whatever you want). Then, we invoke the
RegExp
object in the form of an instance, re.
Following that, it is important to set some parameters for the regular
expression. Most importantly is the pattern that will be matched, which is,
^\D+$.
If you check out that reference sheet I asked you to print, you will note that
\D
stands for any non-digit character, while the + tells the Regular
Expression to match one or more of these characters. The
^ and
$
makes sure it checks and is limited to the whole string. Granted, that means it
will not pick up symbols, but that is not necessarily a bad thing if a foreign
name is possible. However, if you want to be thorough, try this:
re.Pattern
=
"^[^0-9\/><\.,\\!\^\$\*\+\?@#%&\(\);:\[\]\{\}=""']+$".
Yes, that is frightening, but all it says is not (^) 0-9 or any of
the symbols following. If there is a backslash before a symbol, that means it
has been "escaped." Symbols that represent a behavior in a Reqular
Expression must first be escaped if you want to search for them. Whichever you
decide to use, if results is found to be true (and the pattern is
matched), then there is no error, else there is and we note that with our array
and ErrorMsg.
As you can see, while a bit more complex, this is very effective at finding patterns in a string. This feature will make itself more evident when we get into validating specific patterns like social security numbers, telephone numbers, etc. on the next page. If you would like to see Regular Expressions in action, visit this other sample at Enfused. Also, just for your convenience, here is what the code will look like in the whole scheme of things:
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if request.form("isSubmitted") = "yes" then
...
...
ErrorMsg = ""
dim re, results
set re = New RegExp
re.Pattern = "^[^0-9\/><\.,\\!\^\$\*\+\?@#%&\(\);:\[\]\{\}=""']+$"
re.Global = True
re.IgnoreCase = True
results = re.Test(first_name)
if results then
errorArray(0) = "False"
else
errorArray(0) = "True"
ErrorMsg = "First Name<br>"
end if
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = ErrorMsg & "Last Name<br>"
'Note, I added ErrorMsg & to this line to make
'sure we keep the whole string
end if
end if
%>
I do not want to overload you in this tutorial, so on the next page I will guide you through a few more regular expressions for common fields and then we will call it quits so you can go practice.
This page will focus primarily on validating all the other fields we have somewhat ignored on the previous page, like Social Security, Telephone, Zip Code and the Email Address. Since this article is getting pretty long, I will spend less time explaining and more time showing; however, you should walk away with a lot of useful code and understanding for your own web projects.
To validate a social security field you have to first conceptualize how
people are going to enter the data. Most people will probably enter 111-11-1111
or 111111111. Now, you can allow either to be valid or force a specific format.
I recommend that if you force a specific format, just make sure you tell your
users. Below is a good pattern to use assuming that you are forcing 111-11-1111.
It checks for 3 digits (\d{3}), a dash, 2 digits, a dash, and 4
digits. Just insert this code after your code for checking the Last Name.
<%
...
re.Pattern = "^\d{3}-\d{2}-\d{4}$"
results = re.Test(social_security)
if results then
errorArray(2) = "False"
else
errorArray(2) = "True"
ErrorMsg = ErrorMsg & "Social Security<br>"
end if
...
%>
Assuming you are in the US, zip codes now have a special format and look
like: 11111-1111. However, not all people know the four digit extension; so you
had better be sure to make your code accepting of both types. I recommend the
following pattern shown in the code below. It is a bit trickier then the other
ones we have used so far, so pull out your reference sheet again.
\d{5}
checks for the first five digits, which is common to both zip codes, whether the
user knows the four digit extension or not. The next part in parenthesis is what
one would call a nested pattern. (-\d{4})? checks for the dash and
four digit extension zero or one times (the question mark
? takes
care of that). That is all there is too it!
<%
...
re.Pattern = "^\d{5}(-\d{4})?$"
results = re.Test(zip_code)
if results then
errorArray(6) = "False"
else
errorArray(6) = "True"
ErrorMsg = ErrorMsg & "Zip Code<br>"
end if
...
%>
Validating a telephone number can get tricky, because there are many ways to
properly enter a telephone number. Therefore, for this article, we will force a
very normal format of ###-####. If you want to be more accepting, use your
imagination and reference sheet to create a more complex pattern to match.
Notice how it is not unlike the social security number. Tests for 3 digits, a
dash and then 4 digits. Make sure for all these tests that you keep those
^
and $ in there, those will ensure that the full string is matched
and no extraneous characters are ignored. (For example, if someone enters
240-4334-343444, that will validate without the
$, but if you put
the $ in, it will return an error).
<%
...
re.Pattern = "^\d{3}-\d{4}$"
results = re.Test(telephone)
if results then
errorArray(7) = "False"
else
errorArray(7) = "True"
ErrorMsg = ErrorMsg & "Telephone Number<br>"
end if
...
%>
If you had hoped you would learn how to get a user to give you a real and totally valid email address, I am sorry to dash your hopes, but that will not happen here. A lot can be done to attempt to validate an email address, but it takes some extremely complex matching and you can never be one hundred percent accurate. The following pattern is fairly basic but will suffice for most situations. First, think of the things that are standard to email addresses. There is the @ sign, and a ., that is about it. So, we will work around those to come to a usable solution.
<% ... re.Pattern = "^\w+@\w+\.\w+" results = re.Test(email) if results then errorArray(8) = "False" else errorArray(8) = "True" ErrorMsg = ErrorMsg & "Email Address<br>" end if ... %>
As you can see, it is not a hugely complex pattern, but it gets the job done.
It checks for "word" (A-Za-z0-9_) characters (any number of them, but
at least one), the @ sign, any number of word characters, the . (escaped by a
backslash \.) and then some more word characters. Make sure you
drop the $ from the end, because some email addresses end in something like
mail.cc.foo.com. Once you get the hang of this stuff, it will come much easier
to you and you can do a great many things. Check out the Enfused
sample page to see all of this stuff in action.
This article has been long and probably a little tough for some of you. If that is the case, I strongly recommend you go try this all on your own for a while. When you get frustrated, start to see how the error messages work, and can debug it pretty well on your own; come back here and re-read this article and you will find that it makes much more sense the second time through. Also, if you get horribly stuck, you can always email me. I cannot guarantee a reply, but I like to help! For those of you who like to see the code in its entirety, here it is for your viewing pleasure. Note: This code is the code that checks specific fields using Regular Expressions, not all fields are validated, but they could be if we wanted to.
<%
const numFields = 9
dim errorArray()
redim preserve errorArray(numFields)
if request.form("isSubmitted") = "yes" then
first_name = request.form("first_name")
last_name = request.form("last_name")
social_security = request.form("social_security")
address = request.form("address")
city = request.form("city")
state = request.form("state")
zip_code = request.form("zip_code")
telephone = request.form("telephone")
email = request.form("email")
ErrorMsg = ""
dim re, results
set re = New RegExp
'First Name
re.Pattern = "^[^0-9\/><\.,\\!\^\$\*\+\?@#%&\(\);:\[\]\{\}=""']+$"
re.Global = True
re.IgnoreCase = True
results = re.Test(first_name)
if results then
errorArray(0) = "False"
else
errorArray(0) = "True"
ErrorMsg = "First Name<br>"
end if
'Last Name
if Len(last_name) = 0 then
errorArray(1) = "True"
ErrorMsg = ErrorMsg & "Last Name<br>"
end if
'SS #
re.Pattern = "^\d{3}-\d{2}-\d{4}$"
results = re.Test(social_security)
if results then
errorArray(2) = "False"
else
errorArray(2) = "True"
ErrorMsg = ErrorMsg & "Social Security<br>"
end if
'Zip Code
re.Pattern = "^\d{5}(-\d{4})?$"
results = re.Test(zip_code)
if results then
errorArray(6) = "False"
else
errorArray(6) = "True"
ErrorMsg = ErrorMsg & "Zip Code<br>"
end if
'Telephone
re.Pattern = "^\d{3}-\d{4}$"
results = re.Test(telephone)
if results then
errorArray(7) = "False"
else
errorArray(7) = "True"
ErrorMsg = ErrorMsg & "Telephone Number<br>"
end if
'Email
re.Pattern = "^\w+@\w+\.\w+"
results = re.Test(email)
if results then
errorArray(8) = "False"
else
errorArray(8) = "True"
ErrorMsg = ErrorMsg & "Email Address<br>"
end if
end if
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Form Field Validation Sample</title>
</head>
<body>
<% if ErrorMsg <> "" then %>
<font color="red" size="3"><b>
<%= ErrorMsg %>
</font><br>
<% end if %>
<form name="sample1" method="post">
<table width="50%" cellspacing="1" cellpadding="0" border="0">
<tr>
<td><% if errorArray(0) = "True" then %>
<font color="red"><b>
<% end if %>First Name:
<% if errorArray(0) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="first_name"
size="25"
maxlength="50"
value="<%= first_name %>"></td>
</tr><tr>
<td><% if errorArray(1) = "True" then %>
<font color="red"><b>
<% end if %>Last Name:
<% if errorArray(1) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="last_name"
size="25"
maxlength="50"
value="<%= last_name %>"></td>
</tr><tr>
<td><% if errorArray(2) = "True" then %>
<font color="red"><b>
<% end if %>Social Security:
<% if errorArray(2) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="social_security"
size="12"
maxlength="12"
value="<%= social_security %>"></td>
</tr><tr>
<td>Address:</td>
<td><input name="address"
size="35"
maxlength="100"
value="<%= address %>"></td>
</tr><tr>
<td>City:</td>
<td><input name="city"
size="25"
maxlength="50"
value="<%= city %>"></td>
</tr><tr>
<td>State: </td>
<td>
<select name="state">
<option value="noneSelected">- Select from List -</option>
<option value="Alabama"
<% if state="Alabama" then response.write("SELECTED") %>>
Alabama - AL</option>
<option value="Alaska"
<% if state="Alaska" then response.write("SELECTED") %>>
Alaska - AK</option>
<option value="Arizona"
<% if state="Arizona" then response.write("SELECTED") %>>
Arizona - AZ</option>
<option value="Arkansas"
<% if state="Arkansas" then response.write("SELECTED") %>>
Arkansas - AR</option>
<option value="California"
<% if state="California" then response.write("SELECTED") %>>
California - CA</option>
<option value="Colorado"
<% if state="Colorado" then response.write("SELECTED") %>>
Colorado - CO</option>
<option value="Connecticut"
<% if state="Connecticut" then response.write("SELECTED") %>>
Connecticut - CT</option>
<option value="Delaware"
<% if state="Delaware" then response.write("SELECTED") %>>
Delaware - DE</option>
<option value="District of Columbia"
<% if state="District of Columbia" then response.write("SELECTED") %>>
District of Columbia - DC</option>
<option value="Florida"
<% if state="Florida" then response.write("SELECTED") %>>
Florida - FL</option>
<option value="Georgia"
<% if state="Georgia" then response.write("SELECTED") %>>
Georgia - GA</option>
<option value="Hawaii"
<% if state="Hawaii" then response.write("SELECTED") %>>
Hawaii - HI</option>
<option value="Idaho"
<% if state="Idaho" then response.write("SELECTED") %>>
Idaho - ID</option>
<option value="Illinois"
<% if state="Illinois" then response.write("SELECTED") %>>
Illinois - IL</option>
<option value="Indiana"
<% if state="Indiana" then response.write("SELECTED") %>>
Indiana - IN</option>
<option value="Iowa"
<% if state="Iowa" then response.write("SELECTED") %>>
Iowa - IA</option>
<option value="Kansas"
<% if state="Kansas" then response.write("SELECTED") %>>
Kansas - KS</option>
<option value="Kentucky"
<% if state="Kentucky" then response.write("SELECTED") %>>
Kentucky - KY</option>
<option value="Louisiana"
<% if state="Louisiana" then response.write("SELECTED") %>>
Louisiana - LA</option>
<option value="Maine"
<% if state="Maine" then response.write("SELECTED") %>>
Maine - ME</option>
<option value="Maryland"
<% if state="Maryland" then response.write("SELECTED") %>>
Maryland - MD</option>
<option value="Massachusetts"
<% if state="Massachusetts" then response.write("SELECTED") %>>
Massachusetts - MA</option>
<option value="Michigan"
<% if state="Michigan" then response.write("SELECTED") %>>
Michigan - MI</option>
<option value="Minnesota"
<% if state="Minnesota" then response.write("SELECTED") %>>
Minnesota - MN</option>
<option value="Mississippi"
<% if state="Mississippi" then response.write("SELECTED") %>>
Mississippi - MS</option>
<option value="Missouri"
<% if state="Missouri" then response.write("SELECTED") %>>
Missouri - MO</option>
<option value="Montana"
<% if state="Montana" then response.write("SELECTED") %>>
Montana - MT</option>
<option value="Nebraska"
<% if state="Nebraska" then response.write("SELECTED") %>>
Nebraska - NE</option>
<option value="Nevada"
<% if state="Nevada" then response.write("SELECTED") %>>
Nevada - NV</option>
<option value="New Hampshire"
<% if state="New Hampshire" then response.write("SELECTED") %>>
New Hampshire - NH</option>
<option value="New Jersey"
<% if state="New Jersey" then response.write("SELECTED") %>>
New Jersey - NJ</option>
<option value="New Mexico"
<% if state="New Mexico" then response.write("SELECTED") %>>
New Mexico - NM</option>
<option value="New York"
<% if state="New York" then response.write("SELECTED") %>>
New York - NY</option>
<option value="North Carolina"
<% if state="North Carolina" then response.write("SELECTED") %>>
North Carolina - NC</option>
<option value="North Dakota"
<% if state="North Dakota" then response.write("SELECTED") %>>
North Dakota - ND</option>
<option value="Ohio"
<% if state="Ohio" then response.write("SELECTED") %>>
Ohio - OH</option>
<option value="Oklahoma"
<% if state="Oklahoma" then response.write("SELECTED") %>>
Oklahoma - OK</option>
<option value="Oregon"
<% if state="Oregon" then response.write("SELECTED") %>>
Oregon - OR</option>
<option value="Pennsylvania"
<% if state="Pennsylvania" then response.write("SELECTED") %>>
Pennsylvania - PA</option>
<option value="Rhode Island"
<% if state="Rhode Island" then response.write("SELECTED") %>>
Rhode Island - RI</option>
<option value="South Carolina"
<% if state="South Carolina" then response.write("SELECTED") %>>
South Carolina - SC</option>
<option value="South Dakota"
<% if state="South Dakota" then response.write("SELECTED") %>>
South Dakota - SD</option>
<option value="Tennessee"
<% if state="Tennessee" then response.write("SELECTED") %>>
Tennessee - TN</option>
<option value="Texas"
<% if state="Texas" then response.write("SELECTED") %>>
Texas - TX</option>
<option value="Utah"
<% if state="Utah" then response.write("SELECTED") %>>
Utah - UT</option>
<option value="Vermont"
<% if state="Vermont" then response.write("SELECTED") %>>
Vermont - VT</option>
<option value="Virginia"
<% if state="Virginia" then response.write("SELECTED") %>>
Virginia - VA</option>
<option value="Washington"
<% if state="Washington" then response.write("SELECTED") %>>
Washington - WA</option>
<option value="West Virginia"
<% if state="West Virginia" then response.write("SELECTED") %>>
West Virginia - WV</option>
<option value="Wisconsin"
<% if state="Wisconsin" then response.write("SELECTED") %>>
isconsin - WI</option>
<option value="Wyoming"
<% if state="Wyoming" then response.write("SELECTED") %>>
Wyoming - WY</option>
</select>
</td>
</tr><tr>
<td><% if errorArray(6) = "True" then %>
<font color="red"><b>
<% end if %>Zip Code:
<% if errorArray(6) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="zip_code" value="<%= zip_code %>"></td>
</tr><tr>
<td><% if errorArray(7) = "True" then %>
<font color="red"><b>
<% end if %>Telephone No.:
<% if errorArray(7) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="telephone" value="<%= telephone %>"></td>
</tr><tr>
<td><% if errorArray(8) = "True" then %>
<font color="red"><b>
<% end if %>Email Address:
<% if errorArray(8) = "True" then %>
</b></font>
<% end if %></td>
<td><input name="email" value="<%= email %>"></td>
</tr><tr>
<td colspan="2">
<input type="submit" value="Submit">
<input type="hidden" name="isSubmitted" value="yes">
</td>
</tr>
</table>
</form>
</body>
</html>
In this article we discussed using Microsoft's Active Server Page technology
to validate user-submitted form data. With this knowledge, which includes
Regular Expressions, for...each looping, string manipulation, and
adding simple memory to forms, you are well on your way to creating better web
pages. The potential uses for this particular set of technological understanding
are limitless, particularly in an e-Business/Commerce environment!
October 16, 2000
|
If you have been following along in this series and read about how to use Microsoft Active Server Pages to make your forms functional, interactive, smart and valid, then the next logical step is to do something a little more permanent with the data. Sending an email is fine, but if you are building something like an online registration database for internal marketing purposes or for allowing repeat access to features on your site, then you'll need to put that data in a database. |
To follow along in this article, you will need to have a thorough understanding of the techniques discussed in the two other articles in this series. You will also need access to some type of ODBC (Open Database Connectivity) compliant database package. I will be using Microsoft Access 2000 on Windows 98, but you can use Windows 2000/NT/9x if you so choose.
Before delving right into the meat of this topic, it is important to define a framework within which we will be working. Technology is best used as a means to an end, so we will develop a working and practical (albeit small) registration system. This registration system will collect demographic information about the site visitor, as well as a username and password they select, so they may access subscription based services on your site.
An example can be seen on Enfused's Registration Page, although we won't go into so much detail. We are also going to assume that you don't need some detailed registration agreement, which you can easily implement at another time. Read the contents of that page, or just skip and click "I AGREE" and you will see the front-end of what we will be recreating on a generic basis.
In addition, please go back to the article on form-field validation and grab the code on the final page, we will be building off of that page to complete our registration system. Note: If you want to save time, I have prepared a zip file including the database and files we will be working with. You can download it now and just follow along if you want.
October 16, 2000
The nice thing about generic designs is that they are re-usable, which saves a lot of headache and a lot of coding if done correctly. Since the data we need to collect is already ready to go in our existing form, we need only add some logic for a username and password. I think adding them to the top of the form is most appropriate, so in an abbreviated format, here is what it should look like:
<%
const numFields = 11
'change the above from 9 to 11
dim errorArray()
redim preserve errorArray(numFields)
if request.form("isSubmitted") = "yes" then
'add username and password here
username = request.form("username")
password = request.form("password")
first_name = request.form("first_name")
last_name = request.form("last_name")
social_security = request.form("social_security")
address = request.form("address")
city = request.form("city")
state = request.form("state")
zip_code = request.form("zip_code")
telephone = request.form("telephone")
email = request.form("email")
'the rest of your ASP goes here...
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Form Field Validation Sample</title>
</head>
<body>
<% if ErrorMsg <> "" then %>
<font color="red" size="3"><b>
<%= ErrorMsg %>
</font><br>
<% end if %>
<form name="sample1" method="post">
<table width="50%" cellspacing="1" cellpadding="0" border="0">
<!-- NEW CODE GOES HERE -->
<tr>
<td>
<% if errorArray(9) = "True" then %>
<font color="red"><b>
<% end if %>Username:
<% if errorArray(9) = "True" then %>
</b></font>
<% end if %>
</td>
<td>
<input name="username" size="10"
maxlength="10" value="<%= username %>">
</td>
</tr>
<tr>
<td>
<% if errorArray(10) = "True" then %>
<font color="red"><b>
<% end if %>Password:
<% if errorArray(10) = "True" then %>
</b></font>
<% end if %>
</td>
<td>
<input type="password" name="password"
size="10" maxlength="10">
</td>
</tr>
<!-- END NEW CODE -->
<!-- RESUME REST OF OLD CODE -->
Some things to note in the above code. First and foremost,
remember to change the number of required fields assigned to the constant
numFields.
That is very important for validation, because it defines how many elements will
be in the errorArray. Also note that rather then renumbering
everything, we are merely tacking two elements on the end for Username and
Password. It does not matter if they appear first or last in the actual HTML for
the form. Lastly, we need to discuss how we will validate this information.
There are a number of considerations to take into account. First, neither
username nor password can be left blank. Second, username should be greater then
four characters and can be made up of alphanumeric characters. Password must be
at least eight characters long and can also be made up of alphanumeric
characters. Third, username cannot be the same as a username already stored in
the database. For now, we can easily deal with the first two considerations, but
until we learn about how to talk to the database, the third will have to wait.
To be consistent, I recommend using regular expressions to
validate the username and password. However, do not feel required to do so, any
way you think up that is best for you will do fine. The two blocks of code shown
below both utilize regular expression patterns that check for
\w or
any alphabetic or numeric character (including underscore). It checks for four
characters in the case of username and 8 in the case of password. Note that the
$
was omitted from the end of the pattern so that it does not match against the
whole field globally - that means a user can have a larger username then four if
they want - up to the maximum length of the input field. Again, I will leave it
up to you to spruce up things like the error message (ErrorMsg).
'...
'Username
re.Pattern = "\w{4}"
results = re.Test(username)
if results then
errorArray(9) = "False"
else
errorArray(9) = "True"
ErrorMsg = ErrorMsg & "Username<br>"
end if
'Password
re.Pattern = "\w{8}"
results = re.Test(password)
if results then
errorArray(10) = "False"
else
errorArray(10) = "True"
ErrorMsg = ErrorMsg & "Password<br>"
end if
'...
|
NOTE: Do not forget to
modify the ErrorMsg code for First Name. It should now look like
|
All right, now that the username and password are squared away (at least for the time being), move on to the next page and we will talk about setting up the database.
October 16, 2000
To get the database set up is actually not a very complex task if you understand Microsoft Access and are comfortable playing with Windows settings from the Control Panel.
The first thing you need to do is start Access (or whatever you
are using) and create a new database. Store the database wherever you like and
call it something simple and memorable, like registration_db. Next, create a new
table and call it something like tlb_users. Build the table using design view so
you can set the constraints for the fields. Make sure each field is named
appropriately to reflect the data being collected by the form. Also, be sure to
assign a primary key - just make up an auto-number field for that. Finally, make
certain that you properly set the constraints for each field - primarily field
lengths. If you have address with maxlength="100" then
your database should also allow for 100 characters in the address field. If you
don't want to fool around with making this database, you can download
the one I made. For those of you who want to take the pure do-it-yourself
approach, here is a screenshot of my tbl_users.
If you are totally lost at this point, I do not recommend you go forward. At the bottom of this page, I will provide some links to Access and relational database tutorials so you can get up to speed. Once you have read those, come back and try again! It will take some time to get a handle on all of this though, if you are fairly new to these concepts and techniques.
The next thing you need to do is make the database accessible to your web page. To do that, you will have to set up a DSN (data source name) in the ODBC settings found inside the Windows Control Panel. A data source name is something you configure that will store information about how to connect to the database using ODBC (Open Database Connectivity - basically a driver that enable one to send SQL commands to a database management system, from outside the system itself - like via a web page).
Windows makes setting up a DSN fairly easy and painless - all you need to know is the name of your database and where it is on your hard drive. Please note that you are going to have to have some administrative privileges to do this if you are on an NT server. If you are working with a third party web host, you will need to contact them and ask them to set it up for you. With Windows 9x and Personal Web Server, you can set it up on your own!
First, go to Start > Settings > Control Panel. Then click on "Data Sources" (if NT) or "ODBC Data Sources" (if Windows 9x). Then, click on the System DSN tab. Click Add... and select the database type you are using - for Access users that is Microsoft Access Driver (*.mdb). Enter something simple for the data source name and remember what you enter; you will need it when we add the necessary logic to the web page. Description you can leave blank or fill in, it is not really necessary. Next, where you see a row of buttons under the heading Database, click the Select button. Browse through your hard drive and find the database you created or downloaded. Then, select it, click OK and then click OK again on the original screen. You will see that screen disappear, but will notice that there is now something in the list on the System DSN tab - that is the database you just set up, identified by the name you assigned in the dialog box.
Believe it or not, that is it, we are ready to go back to the code and make this work! On the next page we will discuss just how we will get the web page to talk to the database, via ODBC.
October 16, 2000
Microsoft was both kind enough and wise enough to include a means of talking to various data sources by including ActiveX Data Objects (aka ADO) with ASP. ADO will allow the developer to connect to an ODBC data source (what you set up on the last page), and, using special methods specific to ADO, send SQL commands to the data source. We will not be taking an exhaustive look at ADO for this article, because that would take a few articles in and of itself, we are just going to use it so we can get the job done - which is all most of us probably care about. If you are the type of person with an insatiable hunger to be a technical mastermind, check out the links at the bottom of this page for all the untold details.
There are a number of objects within the ADO model, they are:
Connection
Error
Command
Parameter
Recordset
Field
Each of these objects has a number of properties and methods - most of which we will not even take a look at. As a matter of fact, forget all about Error, Command, Parameter and Field - we will not need those for what we are going to do. Instead, let's start with Connection, the object needed to get our web page talking to the database.
Connection does exactly what you think it would do, establishes
a connection to the database, via something called a Connection String. To
start, as with any other object, you must invoke an instance of it. This act is
a simple one and requires that you declare a variable and then create the object
on the server, like so (assuming conn is the name of the declared variable):
set
conn = Server.CreateObject("ADODB.Connection"). Once you
have invoked the object, it is important to set the necessary properties in
order to successfully talk to your database. The most important one at this
point is the Connection String.
A typical Connection String will consist of the DSN for the
database, and possibly the username and password to the database (if you
assigned them). The syntax is: ConnectionName.ConnectionString =
"dsn=DSN You Assigned[;user=Username;password=Database
Password]" (Note: Code inside brackets is optional, the
brackets themselves are not part of the syntax).
The following block of code is what a completed Connection would look like for our example registration system. I will explain all the code line-by-line below: (Note: This structure is not exactly how it appears in the final version of this particular project - the declarations and instance creation are done earlier on at the top of the page - I have illustrated what I mean on a subsequent page).
dim conn, strSQL, rst
set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString = "dsn=wdvl_test"
strSQL = "SELECT * FROM tbl_users;"
set rst = Server.CreateObject("ADODB.Recordset")
rst.Open strSQL, conn, 3, 3
Not bad, right?
dim conn, strSQL, rst is code you
should be familiar with by now, this line declares variables called conn, strSQL
and rst as type Variant. conn will be used for our Connection
object, strSQL will be used for a line of SQL (Structured Query
Language), and rst is going to be used for a Recordset, which I
will explain momentarily.
set conn = Server.CreateObject("ADODB.Connection")
invokes an instance of the ADODB.Connection on the server, allowing the
developer to establish a connection to the database, as outlined in a preceding
paragraph.
conn.ConnectionString = "dsn=wdvl_test"
sets the ConnectionString property equal to the DSN we setup for the database on
the previous page. Since we did not add any security features to the database,
the optional user and password parameters were dropped.
On the next page we will discuss the next few lines of code, starting with a very brief look at SQL.
ADO References
LearnASP.com: ADO Table of
Contents
ASP101: ADO 2.0 Reference
15 Seconds: A
Practical Introduction to ADO
MSDN:
The ADO Object Model
Print:
QUE:
Using ASP Special Edition * This book helped me with this article!
Definitely worth a look! (And no, I do not work for QUE).
WROX:
Beginning ASP Databases
October 16, 2000
SQL, or Structured Query Language, is the standard way of communicating with relational databases. Even though you do not know it, everything you do with the Microsoft Access GUI (like declare field names or build a query) is actually being done with SQL behind the scenes. For instance, when you create a new table in Access, the DBMS (Database Management System - ie. Access in this case) actually goes behind the scenes and uses the CREATE TABLE SQL command to create the table you specified. So, while it is not imperative that you learn every bit of SQL that exists, you should learn the fundamental commands. This is not an SQL tutorial, so I cannot teach you all of them, but we will go over what you need to get the job done, the SELECT command. Again, there are links at the end of this page for those who want to or need to learn more.
The nice thing about SQL is that, unlike other programming languages, you do not need to tell it how to extract data - you simply tell it what you want and it handles the rest. Because it is simpler, more english-like and focuses on "what" one needs to extract from the system, it is called a 4GL language (C++ and others are called 3GL). You may never need to know that, but if you are ever with programmers, you can try to look hip by flashing that little tidbit of knowledge.
As you can tell, unless you are trying to do something pretty advanced, SQL is a fairly easy language. There are a few syntactical things you should know before we examine the SELECT statement. First, there is not any "correct" format for SQL. A statement can be four lines long or one long line - SQL does not care. Second, there is no one "correct" way to use SQL commands, you can use them ALL CAPS or no caps, that is up to you, I prefer to make them ALL CAPS so I can distinguish between the command and the stuff that follows after. I also prefer to write each command per line, as you will see in the next paragraph. Please note, SQL is extremely picky about case with field names - they have to match whatever case you used in the database definition! Third, SQL is not very space sensitive. As long as you put one space in between parameters and commands, SQL is fine. If you want to put tabs, 20 spaces or whole lines, go ahead, SQL does not care. Finally, SQL statements are terminated by a semi-colon. That really is all you need to know to dig right in.
"SELECT" is a very powerful SQL command, because with it, one is able to query (or request information) from the database. We will be using SELECT exclusively for the registration database scenario - and not even anywhere close to its full potential. Let's take a look at where we left off on the code from the previous page.
dim conn, strSQL, rst
set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString = "dsn=wdvl_test"
strSQL = "SELECT * FROM tbl_users;"
set rst = Server.CreateObject("ADODB.Recordset")
rst.Open strSQL, conn, 3, 3
strSQL = "SELECT * FROM tbl_users;" is
about as simple of an SQL command you can get! SELECT statements are composed of
the SELECT, followed by a list of field names you want to select, followed by
FROM (more SQL syntax) and then the name of a table or another query from which
you wish to pull the data. In this line, * is used the same way it is used by
Windows - as a wildcard. When you use the asterisk in SQL, you are telling the
DBMS to select all of the fields from the designated table, which is tbl_users
in this example. Because we are not talking to the database directly, we assign
the whole command to a variable, strSQL, which will later be sent
to the database by ADO.
Now, for example's sake, let's say you just want to access the first name and email addresses of your registrants, perhaps to send out an important announcement later on. Also, we should probably order those names alphabetically from A to Z. Here is how you would do it:
SELECT First_Name FROM tbl_users ORDER BY First_Name;
Simple stuff! We told it what field name (note case-sensitive),
what table and used "ORDER BY field_name" to sort the results
from A to Z. To order them from Z to A, simply tack on a DESC (for descending)
to the end of the ORDER BY line. Now suppose you wanted ADO to have that SQL
command. We have not talked about sending that command to the database, but you
should store it as a string in some variable to keep your code clean, but how is
it possible to store three lines in one variable? You can do three things. One,
crunch the SQL up into one line (strSQL = "SELECT First_Name FROM
tbl_users ORDER BY First_Name;"). Two, store each line separately in
strSQL, by combining strings each time:
strSQL = "SELECT First_Name " <-- note the space before the quote, that is not a typo, but correct syntax. strSQL = strSQL & "FROM tbl_users " strSQL = strSQL & "ORDER BY First_Name;"
Or, third, you can make the string run three lines long, as illustrated by the following code:
strSQL = "SELECT First_Name " & _ "FROM tbl_users " & _ "ORDER BY First_Name;"
You can pick whichever one suits you best when working with ADO in the future. One thing I did not answer at this point is why we need all the fields in our SQL statement. The answer is due to the fact that we need some sort of outline, if you will, of the data we will be manipulating - which leads us to the ADO Recordset.
A Recordset is basically a picture of the database, drawn by you, that can be used to manipulate data in the data source. By using the SQL statement we created above and then making a Recordset based off of it (consider the SQL statement the blue-print for the Recordset), a snapshot of the entire tbl_users is created and made available to the web page. Creating a Recordset is about as simple as a Connection, with a few more parameters.
set rst = Server.CreateObject("ADODB.Recordset")
invokes an instance of the Recordset object. To actually use the Recordset, you
need to define some parameters with the Open method of the Recordset object, not
much unlike ConnectionString for the Connection object.
rst.Open strSQL, conn, 3, 3 opens a Recordset using
the SQL stored in strSQL, the connection defined by
conn, a dynamic
cursor (the first 3 - more later), and an optimistic lock (the second 3).
If you can make it through this, you will have made it through
the hardest part! Let's take a closer look at that Open method. The first part
is fairly obvious, it needs to know a blue-print for how to build the Recordset,
and that is our SQL stored in strSQL. Next, the Open method needs to know where
the database is and how to connect to it - that is where our friend,
conn
comes in. This instance of the Connection object will give the Open method all
the info it needs to create the appropriate Recordset.
The next two are a bit more vague, but understandable. Recordsets use cursors to navigate through the data they represent. Think of the cursor like a little arrow that points to where one is currently operating within the Recordset. For instance, when first opened, the Recordset's cursor points to the first record (or table row) in the set. If you do some manipulation and move to the next record (or row) then the cursor moves there as well. ADO has four cursor types which all behave in different ways. You really do not need to know those for this particular task, but know that we are using the most common one - the dynamic cursor. It allows us to read or write to any record within the set, whether the cursor is currently pointing to it or not. In other words, it allows us to jump around the set and also see changes made by other users as they occur.
The final parameter tells the Open method how it should handle record locking - or how record/rows should be dealt with when multiple people are acting on the database at the same time. Remember, this is going to be on a web site where many users may be looking at the same exact page at the same exact time, it is important that the data maintain its integrity through it all! There are four types of record locks, but again, you do not need to know those right now (see the links below for references). What you do need to know is that we are using optimistic locking (3), which means that records are only locked to other users when they are being updated/modified.
Move onto the next page and we will put this all together and have a working page!
SQL References
WDVL: Simple SQL - Getting
Started with SQL
WDVL: Retrieving
and Manipulating Data
SQL Tutorial
Database
Central: SQL Resources
October 16, 2000
All that remains is to get this data actually written to the database. Before we move on to that, in case you did not know, you should put the ADO related code we have been talking about around the validation code, like so:
if request.form("isSubmitted") = "yes" then
dim conn, strSQL, rst
set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString = "dsn=wdvl_test"
set rst = Server.CreateObject("ADODB.Recordset")
'...All the stuff in between...
'Email
re.Pattern = "^\w+@\w+\.\w+"
results = re.Test(email)
if results then
errorArray(8) = "False"
else
errorArray(8) = "True"
ErrorMsg = ErrorMsg & "Email Address<br>"
end if
'One of the problems with the original page is that
'it doesn't do anything with the form after it's validated!
'We add a check for ErrorMsg here (to ensure no errors)
'and then we actually do something with the data!
if ErrorMsg = "" then
strSQL = "SELECT * FROM tbl_users;"
rst.Open strSQL, conn, 3, 3
'There will be more to come here!
end if
end if
%gt;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
Etc...
Writing the data to the database is a simple matter that
involves a few ADO Recordset methods and a little manipulation. First, you need
to know how to add a new record to the database. In Access you would just move
to the next line in Datasheet view and just start typing. On the web you need to
specifically tell it to create the new record. This task is done using the
AddNew method of the Recordset and looks like this:
rst.AddNew.
Following that easy command, you will need to match up the database's field
names to the web pages stored versions of the data being submitted. If that does
not make sense, look at the following example:
'...
rst("First_Name") = first_name
'etc...
The rst("Field_Name") on the left-hand
side of the equals sign is a reference to the database field "First_Name"
being made through the Recordset we created. The variable on the right side of
the equals sign is the one created by the web page and assigned the value of
Request.Form("first_name").
You will need to do this for each database field in the Recordset you created.
Once you are done, you need to commit those changes to the actual data source,
which is done by adding in the code: rst.Update. That is it! The
record is added into the database!
October 16, 2000
Just to make sure everyone is clear, the following block of code is all the ADO related stuff (minus initialization) we did and where it fits in the page. The validation and HTML form code was omitted because that has not really changed. Also, I added a confirmation message so that the user knows his/her submission was successful.
'The last field validated sits above this block...
if ErrorMsg = "" then
strSQL = "SELECT * FROM tbl_users;"
rst.Open strSQL, conn, 3, 3
'Now write the data.
rst.AddNew
rst("Username") = username
rst("Password") = password
rst("First_Name") = first_name
rst("Last_Name") = last_name
rst("Social_Security") = social_security
rst("Address") = address
rst("City") = city
rst("State") = state
rst("Zip_Code") = zip_code
rst("Phone") = telephone
rst("Email") = email
rst.Update
'The next four lines are not necessary but help improve
'server performance by clearing up memory.
rst.Close
conn.Close
set rst = nothing
set conn = nothing
'Making ErrorMsg act like a confirmation message!
ErrorMsg = "Your submission was successful, thanks for registering!"
end if
end if
%>
HTML Etc...
Thought I forgot, did you? Well it is true, I almost did, but here we are anyway! Cracking down on repeat usernames is as easy as writing to the database - the only problem is that it is going to restructure part of our page a little, so pay close attention. Way back in the validation section we need to query the database to see if the username already exists. So, let's add the following snippet of code up there:
'...
'Username
re.Pattern = "\w{4}"
results = re.Test(username)
if results then
strSQL = "SELECT Username FROM tbl_users;"
rst.Open strSQL, conn, 3, 3
while not rst.EOF
if rst("Username") = username then
duplicate = "True"
end if
rst.MoveNext
wend
if duplicate = "True" then
errorArray(9) = "True"
ErrorMsg = ErrorMsg & "Username<br>"
else
errorArray(9) = "False"
end if
rst.close
'Make sure you close the recordset or you will get an error
'when you try to open it below with a different strSQL.
else
errorArray(9) = "True"
ErrorMsg = ErrorMsg & "Username<br>"
end if
'...
All that we are doing is saying, "Hey, if the username matches the criteria, let's make sure it is not already in the database. If it is, let's make the array value true and send back an error, if not, we are good to go!" We do it this way because we do not care about matching it to the database if it does not pass the regular expression, that username could not possibly be in there anyway! Also, that while loop is pretty easy to use. All it does is iterate through each record in the Recordset until it comes to the EOF, or End Of File.
Believe it or not reader, we are done! Mission accomplished, database connected, updated and user satisfied! Of course, there is so much more that you can do with ADO. It is an extremely useful and powerful component within the ASP framework. If you want to get daring you can look up more about ADO from some of the resources I provided and start dealing with time outs, transaction-based processing and all sorts of other neat stuff! Do not forget to download the source code and database if you do not want to do it yourself and as always, Feel free to email me with questions. See you next month!
November 13, 2000
|
In this final installment of ASP Form Handling, Chris Assenza discusses such topics as handling radio buttons and check boxes, emailing attachments with CDONTS, and some ways of using the data stored in the registration database we created last month. |
Introduction
This month's article marks the end of our discussion of ASP Form Handling. Hopefully you have fully understood everything we have done thus far (and if you are new to this series, welcome aboard, check out the first article). In this article, we are going to cover a number of miscellaneous topics related to all the techniques discussed in previous articles. Some of these topics come straight from questions I received via email (thanks readers) and include: handling radio buttons and check boxes, emailing attachments with CDONTS, sending HTML in an email message, and some ways of using the data stored in the registration database we created last month. Let's start on the next page by revisiting Form Handling techniques.
Forms:
Saving State Revisited
Advanced
CDONTS Techniques
Using
the Registration Database
Sending
Mass Emails to Subscribers
November 13, 2000
A number of readers have inquired about how to save the state of radio buttons and checkboxes. The technique for accomplishing this is no different then saving the state of a drop-down or select box. Let us assume that you have coded a form that has two sets of radio buttons, a few checkboxes and a drop-down box, like so:
Now, assume that the user has just submitted the form but they made a mistake on some field (not shown) and you want to give them the form again, but do not want to have them fill everything back out, you know the concept by now. Well, here is how:
<%
'pretend we've got the code to check if
'the form's been submitted here
'now let's assign the form data to some variables
radio_group1 = request.form("r1")
radio_group2 = request.form("r2")
checkbox1 = request.form("cb1")
checkbox2 = request.form("cb2")
checkbox3 = request.form("cb3")
select_opt = request.form("select_example")
%>
<!--html code down to form-->
<form>
<input type="radio" name="r1" value="r1"
<% if radio_group1 = "r1" then %> <%= selected %>
<% end if %>>
Radio Group 1, Option 1<br>
<input type="radio" name="r1" value="r2"
<% if radio_group1 = "r2" then %> <%= selected %>
<% end if %>>
Radio Group 1, Option 2<br>
<input type="radio" name="r1" value="r3"
<% if radio_group1 = "r3" then %> <%= selected %>
<% end if %>>
Radio Group 1, Option 3<br>
<br>
<input type="radio" name="r2" value="r1"
<% if radio_group2 = "r1"then %> <%= selected %>
<% end if %>>
>Radio Group 2, Option 1<br>
<input type="radio" name="r2" value="r2"
<% if radio_group2 = "r2" then %> <%= selected %>
<% end if %>>
Radio Group 2, Option 2<br>
<input type="radio" name="r2" value="r3"
<% if radio_group2 = "r3" then %> <%= selected %>
<% end if %>>
Radio Group 2, Option 3<br>
<br>
<input type="checkbox" name="cb1" value="cb1"
<% if checkbox1 = "cb1" then %> <%= selected %>
<% end if %>>
Checkbox 1<br>
<input type="checkbox" name="cb2" value="cb2"
<% if chekcbox2 = "cb2" then %> <%= selected %>
<% end if %>>
Checkbox 2<br>
<input type="checkbox" name="cb3" value="cb3"
<% if checkbox1 = "cb3" then %> <%= selected %>
<% end if %>>
Checkbox 3<br>
<br>
<select name="select_example">
<option name="o1" value="o1"
<% if select_opt = "o1" then %> <%= selected %>
<% end if %>>
Select Option 1</option>
<option name="o2" value="o2"
<% if select_opt = "o2" then %> <%= selected %>
<% end if %>>
Select Option 2</option>
<option name="o3" value="o3"
<% if select_opt = "o3" then %> <%= selected %>
<% end if %>>
Select Option 3</option>
</select>
</form>
Now that sure is a mess, but fear not, it really is very simple. We need only to dissect one part of that code and you will understand all of it, if you do not already.
Let's take a look at the first radio group and the first option in that group.
<input type="radio" name="r1" value="r1" (note I dropped the >) <% if radio_group1 = "r1" then %> <%= selected %> <% end if %>> (and put it here) Radio Group 1, Option 1<br>
The first thing to note is that we had to put the code on
multiple lines, everything from the <% if ...
to the <%
end if %> can be placed on one long line. In fact, I recommend it
because it is more legible and easier to work with. Please also note that I
dropped the closing > after the value attribute, and put it
after the end if. But how does it work? Well, that is the easy
part. The if statement checks the value stored in the variable
"radio_group1" and compares it to the value of the current option. If
the two are equal, then that particular option within the group is marked as
"Selected." If the two values do not match, then the ASP code
does not do anything. Unless the user did not pick anything the first time the
form was submitted, one of the options in the group will be selected because one
if statement will be found true! Checkboxes work the same way, they just are not
grouped like radio buttons - think of them each as unique items or if it makes
more sense, radio buttons with a maximum of one option. Lastly, selects work
exactly like radio buttons as well - compare the variable to the option values.
On the next page, we will take a more advanced look at CDONTS.
November 13, 2000
Let's say you have your registration web page completed and want
to send the user a confirmation email with some standard attachments about
rules, procedures and policies associated with registration at your site. If you
understood CDONTS from the first
article, this task should not be too challenging. However, we never really
discussed sending an attachment, like a MS Word document, so here we go.
<%
'pretend we've got all sorts of ASP code
'up here to handle the form data
'begin CDONTS code
dim objCDO
Set objCDO = Server.CreateObject("CDONTS.NewMail")
objCDO.To = email '(variable we stored the user's email in)
objCDO.From = "someaddy@email.com"
objCDO.Subject = "Confirmation Email"
objCDO.Body = "Thank you for registering."
objCDO.AttachFile ("c:\reg_confirm.doc")
objCDO.Send
'rest of the web page and ASP below.
%>
That is pretty easy, and does not require much explanation. You simply say "AttachFile" and in parenthesis show where the file is on your web site's server. Attaching a file from the client's hard drive is much more complex and a bit out of the scope of this article. You need to deal with A) Putting a field on the form for the file, B) Getting the file from the user's hard drive to your web server, and C) Getting the file from the web server to your inbox. ASP does not support file uploading in forms by default, so you will need a third party component to get the job done (if you want to try this yourself, I recommend EZsite Upload - if you can figure that out, you'll be able to figure the rest out for yourself).
Some readers were not clear about how to send HTML in an email using CDONTS, perhaps to send a more visually provocative opt-in advertisement or something like that. Fortunately, we can accomplish this task with ease. Let's revisit the code above and discuss how.
<%
'pretend we've got all sorts of ASP code
'up here to handle the form data
'begin CDONTS code
dim objCDO
Set objCDO = Server.CreateObject("CDONTS.NewMail")
objCDO.To = email '(variable we stored the user's email in)
objCDO.From = "someaddy@email.com"
objCDO.Subject = "Confirmation Email"
objCDO.BodyFormat = 0
objCDO.MailFormat = 0
bodyHTML = "<html><head></head><body>" & _
"<font face=""3"" color=""red"">" & _
"Hello, I'm an a message sent via HTML</font><br><br>" & _
"<img src=""http://www.enfused.com/images/net216.jpg"">" & _
"</body></html>"
objCDO.Body = bodyHTML
objCDO.Send
'rest of the web page and ASP below.
%>
Look carefully at the code above, the first thing you should
notice is that we added objCDO.BodyFormat = 0 and
objCDO.MailFormat
= 0 . Instead of setting these equal to 1, like we did in the first
article, this time they have been set equal to 0. Those attributes will tell
CDONTS to send the mail as HTML. As for the body of the HTML message, it is
literally an HTML page that you can create any way you like. But there are a few
caveats of which you must be aware. First, assigning HTML code to a variable
requires creative use of quotation marks. Note that all the HTML code is inside
double quotes already, so if you have an attribute that uses a double quote, how
can one enter it without terminating the original quote? Simply use two quotes
like I did above. That will indicate to the server that you want a quote
actually embedded within the variable, not that you are terminating the string.
If you forget to do this for attributes with quotes, you will get errors, so be
careful.
Second, take a look at how we stored all the HTML in one
variable. You will recall seeing this technique before when we discussed SQL, at
the end of the line if you add & _ you can then continue the
string on the next line without worrying about writing "bodyHTML = bodyHTML
+" every line. Third, note that the image embedded in this email is
pointing to an HTTP location. If you think about what we are doing carefully,
the reasoning behind that should make sense. The user is not going to have a
copy of the image on their hard drive, so when they get the email it will have
to have a source for the image. So, point them out to your public web server.
There is another way to do this, which is less taxing on your web server - and
that is to attach the image to the email. Here is how you do that:
'these two lines of code will replace 'what was done above with the image. 'attach the image to the email and 'give it a name for use later on objCDO.AttachURL "c:\images\net216.gif", "net216.gif" '... 'inside the bodyHTML variable bodyHTML = "<html>etc, etc..." & _ "<img src=""net216.gif""><br><br>" 'notice how the name you assigned above 'is referenced as the image source?
Once you have all your HTML code squared away, set objCDO.body equal to your variable (bodyHTML) and send away! Move on to the next page to read about using the data we stored in the registration database last month.
November 13, 2000
Good question actually, once you have collected user data from a form and stored it in a database, what do you do with that data? One thing you can do is allow access to special portions of your site. For instance, say a user registered as "brainman" with the password "flobe" and you wanted to give this user (and all others) access to your subscription content. The answer is, as usual, really very easy - in fact, if you have been following this series along, you have already done it, just for different reasons!
The answer involves a simple form, some ASP validation and processing (with SQL) and a redirect! Let's take a look at the form:
<html> <head><title>Login Page</title></head> <body> <form name="logon" action="logon.asp"> Username: <input type="text" name="username"> Password: <input type="text" name="password"> <input type="hidden" name="isSubmitted" value="yes"> <input type="submit" value="Login"> </form> </body> </html>
You cannot get much easier then that, right? This form asks for a username, password and has a submit button. The form is using the post method so we will use "request.form" in our ASP code and the action is pointing to itself (pretend the page is named "login.asp"). If you have not understood so far, now is the time to pick it up - with computer stuff, repetition is the key to expertise in any particular area. Now, let's move on to the ASP code, which should also be old hat to you by now!
<%
if request.form("isSubmitted") = "yes" then
username = request.form("username")
password = request.form("password")
dim conn, strSQL, rst
set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString = "dsn=wdvl_test"
conn.Open
set rst = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT * FROM tbl_Users;"
rst.Open strSQL, conn, 3, 3
found = 0
while not rst.EOF
if ((username = rst("Username")) AND
(password = rst("Password"))) then
found = 1
end if
wend
if found = 1 then
response.redirect 'subscription_zone.html'
else
ErrorMsg = "Username or password incorrect, please try again."
end if
end if
%>
<html>
<head><title>Login Page</title></head>
<body>
<% if ErrorMsg <> "" then %>
<font color="red" size="+2">
<b><%= ErrorMsg %></b>
</font>
<% end if %>
<form name="logon" method="post" action="logon.asp">
Username: <input type="text" name="username">
Password: <input type="text" name="password">
<input type="hidden" name="isSubmitted" value="yes">
<input type="submit" value="Login">
</form>
</body>
</html>
Note: The line "if ((username = rst("Username")) AND (password = rst("Password"))) then" is split at the word AND for display purposes, but in actual use it should be one line.
Rather then going through that code line-by-line, I will simply
explain the concepts because you should recognize this code by now. First, the
ASP checks the value of the isSubmitted form-field. If it is equal to
"yes" the page proceeds to do some processing. After assigning the
fields to variables, the next step is to establish a connection to the backend
database. The SQL statement selects all the records from the tbl_Users table and
makes them available as a recordset called "rst." Next, it is
necessary to compare the values submitted on the page and the values in the
recordset. We do this using a while loop that iterates through the recordset
until it hits the end of the file. Each time, the
if ((username =
rst("Username")) AND (password = rst("Password"))) then
statement asks if username (the variable) is equal to the current username in
the recordset and asks if the passwords match. If a match is found, then
the found variable is given a value of one, otherwise it stays equal to zero.
Following the while loop, the next block of code checks to see what value
found
ended with. If it was a one, then response.redirect 'subscription_zone.html'
sends the user to another page (whatever is defined in the single
quotes). If found still equals zero, an ErrorMsg is stored and displayed when
the form is redisplayed. On the next page, we will take a look at another use of
the registration database - sending bulk email to your subscribers.
November 13, 2000
Another potential use for your registration database ties together just about everything discussed in this series of articles. This time, let's assume that you have a big database full of registrants, and you need to contact each and everyone of them to update them about a change to your service offerings. The best way, is of course, email, but how will you send it to all of them without setting up a mailing list and bulk email program? Easy, use a combination of form handling, CDONTS and SQL to get the job done.
For this particular exercise, I am not going to give you all the code, just snippets to help you on your way, you need to work on it and set it up yourself. We will begin by taking a closer look at the conceptual design.
First, you will need a simple web page that has a number of form fields on it. One should be a "From" field to say who the message is from. A second should be the subject of the email. For a third field, consider an option for sending HTML or plain text. Finally, the fourth field should be the body of the message.
Next, you need to develop a system that checks if the form is submitted and then processes that form appropriately. You will need it to A) Create the email message B) Obtain the email addresses for all your registered users, and C) Send an email to each user.
Now, part "A" should be simple, assign the value of
the body field to bodyHTML or some other variable (I use msgBody below). Then,
when the time comes, set objCDO.body = bodyHTML. But how about
getting the email addresses out of the system and sending the mail? When sending
a bulk message you need to start thinking about your server's capacity and the
most efficient way to do things, because sending out a few hundred to thousand
emails is pretty taxing. I recommend something like the following:
<%
'assume variables are declared and assigned
'values up here, among other things.
strSQL = "SELECT First_Name, Last_Name, Email FROM tbl_Users;"
rst.Open strSQL, conn,3,3
while not rst.EOF
msgBody = ""
Set objCDO = Server.CreateObject("CDONTS.NewMail")
objCDO.From = "Administrator@Somedomain.com"
objCDO.To = rst("Email")
objCDO.Subject = subj
'subj is the variable for the form field
msgBody = "Dear " & rst("First_Name") & " "
msgBody = msgBody & rst("Last_Name") & ": "
msgBody = msgBody & bodytext & vbCrLf
'bodytext is the variable for the form field
objCDO.Body = msgBody
objCDO.Send
set objCDO = nothing
rst.MoveNext
wend
%>
Again, nothing too complex that cannot be understood with a
little effort. Presuming all the preprocessing is done, like assigning variables
and validation, the first thing one needs to do is establish a connection to the
backend database. The SQL statement used above retrieves the first name, last
name and email address of every user in the tbl_Users table. The next section of
code is the standard while not rst.EOF or end-of-file technique.
Each iteration (or time through) the loop, the server will invoke a new mail
object, configure the email attributes and send the email.
msgBody = "Dear " & rst("First_Name")
& " " & rst("Last_Name") & ": "
might be a bit confusing, so let's take a look at it more carefully. All that is
really happening is that the first line of the msgBody is being set equal to
"Dear So and So: ". We do this by concatenating (sticking together)
the first name, a space, last name, and a colon, using the ampersand: &. The
same sort of thing occurs on the next line. msgBody is set equal to itself to
carry over changes from the previous line and bodytext is added to it. Assume
bodytext is the variable you set equal to request.form("email_body").
Finally, the message is sent and the object set to nothing to free up resources
and be less taxing on the server as it sends out many emails. The whole process
repeats until the end of the recordset!
One thing I did not mention was how to deal with the "Send HTML or Plain Text" type form field. I am not going to show you line-by-line, but I will give you a terribly obvious hint. In the while loop, add some conditional processing (if statement) to check what the value of that form field is. If it is HTML, write some code that sets the mail and body formats equal to 0, if not, set them to 1. Easy as pie!
Hopefully some of you out there have learned what you wanted to learn with this series. We have discussed using ASP for form handling, validation, sending email, and working with simple databases. Using any of these techniques in conjunction with another can solve many problems the average web developer will encounter and can, in fact, be fun to work with. Next month I will be talking about something new, but I have not decided on any one topic. If there is something you are aching to know how to do but have not been able to figure it out, drop me an email and I will consider it for my next article! See you next month!