欢迎光临
我们一直在努力

复杂表单的动态生成与动态验证

建站超值云服务器,限时71元/月

这里所谓的复杂表单,是指表单中包含多种不同的输入类型,比如下拉列表框、单行文本、多行文本、数值等。在经常需要更换这类表单的场合,需要有一个表单的动态生成程序。本文介绍的正是这样一个系统,它以数据库保存表单定义数据,利用asp脚本动态生成表单html代码以及验证表单输入的脚本。

一、定义数据库表结构

   在web上经常可以看到“每周调查”之类的表单,这就是一种需要经常更新的表单。如果有一个动态生成表单及其验证脚本的程序,可以大大减少制作这些表单的工作量。

   在本文的动态表单生成与验证示例中,我们使用一个access数据库来存储有关表单的定义信息,同时为简单计,用户在表单中输入的数据也保存到同一数据库。定义表单需要两个表:第一个表(definitons)用于表单输入域的定义,第二个表(lists)保存各个输入域的附加信息,比如选择列表的选择项。

   表definitons包含如下字段:

fieldname —— 赋予表单输入域的变量名字

label —— 即文本标签,显示在输入域前面的提示性文字

type —— 单个字符,该字符表示表单输入域的形式和输入值的类型,具体如下:

(t) 文本输入框,即< input type="text" >。

(n) 文本输入框,但要求输入数字值。

(m) 备注型内容,用于注释或其他大量文本的输入,它是一个多行文本编辑框。

(b) 要求输入“是”或“否”。本实现中将用复选框来获取这种输入,复选框的文本标签为“是”。如果用户选中它,则返回值是“on”。

(r) 单选按钮。

(l) 下拉列表框。

min —— 仅对数字型输入值有效,在这里给出最小值。在本例中有一个“age”(年龄)数字型输入框,它的最小值设定为1。

max —— 该字段的值与输入域形式有关。对于数字型输入框,它表示的是允许的最大值。例如“age”的max值为100。对于文本输入框,max表示允许的最多字符个数。对于多行文本编辑框,max表示可见区域的文本行数。

required —— 表示是否必须输入。这种类型的值如果没有输入,则输入验证程序将报告错误。在表单中,必须输入的值以星号标记,并以脚注的形式提示用户该类值必须输入。

   本文的示例表单是一个asp程序员调查表,在definitons表中该表单的定义主要如下:

fieldname label type min max required

name 姓名 文本(t) – 50 否

age 年龄 数字(n) 1 100 否

sex 性别 单选按钮(r) – – 是

e-mail 邮件地址 文本(t) – – 是

language 编程语言 下拉列表框(l) – – 否

   表lists用于保存输入域定义的一些附加信息,本例有“sex”和“languages”两个输入值要用到它。表lists非常简单,只包含如下三个字段:

fieldname —— 当前记录属于哪个表单输入域

value —— 选择项的值

label —— 用户所看到的选择项的提示文本

   输入域“sex”只能从两个值选取:“男”或“女”。“language”列出了几种可应用于asp环境的编程语言,包括:vbscript,javascript,c,perl和“其他”。

   第三个表“records”保存用户提交的内容,它也包含三个字段,每个记录对应用户的一次提交:

record —— 备注类型,以查询字符串形式保存的用户输入。

created —— 用户提交该表单的日期和时间。 remoteip —— 表单提交者的ip地址。

   在实际应用中可能要收集更多有关用户的信息,为简单计,本例只记录提交时间和用户ip地址这两个附加信息。

   二、准备工作

   在完成上述数据结构和表单的定义之后,接下来就可以编写脚本。脚本的任务是生成表单以及处理用户提交的表单。

   无论是表单的生成还是处理,以下三个过程(任务)都是必不可少的:第一是确定验证类型,在生成表单时验证类型值通过查询字符串获得,在处理表单时从表单隐藏域读取。程序支持的表单验证方式共有以下四种类型:不进行验证,客户端javascript验证,服务器端asp脚本验证,客户端和服务器端都进行验证(代号分别为0到3)。如果没有在查询字符串中指定合法的验证方式,则默认第四种验证方式。这种验证处理方式使得我们可以灵活地应用这个表单生成、处理系统,当客户端禁止使用javascript验证时就可以仅在服务器端执行验证过程。下面是确定验证类型的代码:

  检查验证类型

  ivaltype = request.querystring("val")

  if isnumeric(ivaltype) = false then ivaltype = 3

  if ivaltype > 3 or ivaltype < 0 then ivaltype =3

   第二个任务是打开数据库连接,创建两个记录集对象:rs对象,这是本程序中的主要记录集对象,用来操作definitions表;rslist对象,主要用于从lists表读取数据。示例程序提供两种数据库连接方法:使用odbc dsn或不使用odbc dsn(使用dsn时需要先创建名为dynamic的dsn,使用dsn连接数据库的代码已经被注释掉)。

   第三个任务是在生成(或处理)表单脚本的前面(和后面)输出一些静态的html代码,比如< head >< /head >,以及在脚本运行结束的时候释放rs、rslist等对象占用的资源。

   除了完成上述任务的代码外,示例应用中其余asp脚本可能生成的页面有两种类型:提问表单(见上图)以及表单提交后出现的结果页面(后者同时还负责用户提交结果的记录)。要确定究竟运行哪一部分脚本,最简单的方法就是检查是否已经提交表单:如是,则处理表单;否则生成表单。

 是生成表单还是处理表单?

  if len(request.form) = 0 then

  生成表单

  …略…

  else

  处理表单

  …略…

  end if

   三、动态生成表单

   生成表单时,程序按照definitons表中的各个输入域定义记录,依次生成相应的表单html代码和javascript代码。html代码中首先要生成的是文本标签:

 shtml = shtml & vbtab & "< tr >" & vbcrlf & vbtab & vbtab

 shtml = shtml & "< td valign=" & chr(34) & "top" & chr(34)

 shtml = shtml & " >" & vbcrlf & vbtab & vbtab & vbtab

 shtml = shtml & "< b >" & rs.fields("label")

   然后程序检查当前输入域是否必须输入。如果必须,则在标签文本之后加一个星号(表示该值必须输入),同时对于必须输入的值,还要生成相应的javascript代码来验证它。对于单选按钮或选择列表,需进一步检查用户确实选择了某个选项;对于所有其他输入类型,只要检查输入值不为空即可。

   紧接文本标签的是表单的输入元素,这些元素的html代码根据definitions表中指定的类型和属性生成。再接下来就是根据输入值要求生成执行客户端验证任务的javascript代码。对于本例,只有数字型的值需要进一步检查以保证用户的输入确实是数字,而且数字值在许可的最大值和最小值之间。生成上述代码之后,就可以结束一个表格行(也就是一个输入域)继续处理definitions表的下一个记录。一旦所有的数据库记录处理完毕,下一步就可以加入“提交”按钮和“清除”按钮的html代码。如果换个角度来看,程序在这里的任务就是根据数据库记录生成各个输入域,每个输入域占用一个表格行,每个表格行二个单元:第一个单元用来显示文本标签,第二个单元显示输入元素本身(代码见dform.asp)。

   上述过程结束之后,表单的html代码和验证用javascript函数分别保存到了变量shtml和sjavascript中。在把这些内容写入页面之前,程序检查客户端是否要求执行javascript验证,如果不要求执行这类验证,则清除sjavascript变量:

 if ivaltype = 0 or ivaltype = 2 then sjavascript = ""

   在输出body标记之后,程序输出如下javascript函数:

 < script language="javascript" >

 < !–

  function validate(theform){

  //客户端表单验证

  < %=sjavascript% >

  return true;

  }

 

  function checkradio(objradio){

  //单选按钮中是否有某个值被选中

  for(var n = 0; n < objradio.length; n++){

  if(objradio[n].checked){

  return true;

  }

  }

  return false;

  }

 

  function checklist(objlist){

  //是否已经在选择列表中选择了某个值

  for(var n = 1; n < objlist.length; n++){

  if(objlist.options[n].selected){

  return true;

  }

  }

  return false;

  }

 //– >

 < /script >

   如果客户端不需要javascript验证,则validate函数只剩下一个“return true”语句。上面代码中的后面两个静态javascript函数(checkradio和checklist)用于验证单选按钮和下拉列表框,当这两种输入域需要验证时validate函数将调用它们。

   现在可以开始把表单写入页面:

 < form action="./dform.asp" method="post" name="myform" onsubmit="return validate(this)" >

   在这里,只有当validate函数返回true时才执行表单提交操作。因此当客户端javascript验证功能关闭时,validate函数将自动返回true。

   接下来要加入的是名为val的隐藏域。如前所述,该值指示表单的验证模式。

 < input type="hidden" name="val" value="< %=ivaltype% >" >

   当用户提交表单时,处理脚本将根据该值确定是否执行服务器端验证。

   然后输出的是表格标记以及表格标题。标题保存在变量stitlelabel中,该值在脚本开始执行时初始化:

 < table border="0" >

  < tr >

  < td colspan="2" align="center" >

  < h2 >< %=stitlelable% >< /h2 >

  < /td >

  < /tr >

   作为改进措施,可以在表definitions、lists和records中增加一个字段formid。formid唯一标识一个表单,这样程序就可以同时地定义多个表单、保存多个表单的用户应答结果。至于上面的stitlelabel,我们可以用另外一个表(比如forms)来保存。

   紧接着表格标记和表格标题,程序输出的是html表单以及“提交”、“清除”按钮的代码。在此之后,程序检查shtml字符串中是否包含“*”,如包含的话说明表单中存在必须输入的内容,此时就输出一个脚注以说明该星号的含义。

 < %=shtml% >

  < tr >

  < td colspan="2" align="center" >

  < input type="submit" value="提交表单" > < input type="reset" value="清除" >

  < /td >

 < %

  是否存在必需输入的表单域,如存在,则输出表单脚注解释*的含义

  if instr(shtml,"*") then

 % >

  < /tr >

  < td colspan="2" align="center" >

  < font size="2" >注意:有星号标记的值必需输入。< /font >

  < /td >

  < /tr >

 < %

  end if

 % >

 < /table >

 < /form >

   至此为止,表单的生成任务已经完成。

   四、处理提交结果

   asp脚本剩下的任务是服务器端的表单处理,包括验证、将结果保存到数据库以及“提交成功/失败”页面的显示。在这部分表单验证代码中用到了一个字符串变量sbadform,程序用它来保存错误信息。如果在验证过程结束时sbadform为空,说明用户提交的表单是合法的;否则,拒绝该表单的提交并把sbadform返回给浏览器。

   不管表单采用哪种验证模式,检查http_referer都是一种好的习惯。这种检查可以防止脚本被盗用。要检查某个post是否来自本网站的页面或脚本,只需比较两个服务器变量即可:

  if instr(request.servervariables("http_referer"), _

  request.servervariables("http_host")) = 0 then

  sbadform = "< li >表单提交自不正确的位置。" & vbcrlf

  end if

   如果表单的隐藏域指示必须进行服务器端验证,则程序遍历表单定义数据库记录作相应的检查,其过程与表单的生成非常相似,只不过此时程序是验证表单,且把输入值非法信息加入到sbadform中去而已。具体代码见dform.asp。

   程序最后检查sbadform是否为空。如不为空,则拒绝表单提交并将sbadform写入浏览器。如果sbadform为空,则在records表增加一个记录保存表单数据。在保存表单内容之前需要删除隐藏域val,这个隐藏域总是表单的第一个输入域:

  if len(sbadform) = 0 then

  rs.open "records", db, 3, 2, &h0002

  rs.addnew

  rs.fields("record") = mid(request.form, instr(request.form, "&") + 1)

  rs.fields("created") = now()

  rs.fields("remoteip") = request.servervariables("remote_addr")

  rs.update

  response.write("< h1 >谢谢.< /h1 >")

  rs.close

  else

  response.write("< h1 >表单提交失败。< /h1 >")

  response.write(vbcrlf & sbadform)

  end if

  end if

   这就是服务器端表单处理的全部过程。根据是否存在已经提交的表单,我们可以把前面生成表单的代码和这里表单处理的代码用if语句封装,使得这两部分脚本共享部分公用代码,比如html文档的头、数据库对象的创建和资源释放等。

   总地看来,dform.asp只具备了动态表单生成、验证所必需的核心功能,忽略了许多细节问题的处理。比如前面已经提到的多表单问题:增加一个表管理多个表单,使得脚本具有管理、生成、处理指定表单的能力。另外一个明显的缺乏是表单定义数据的增加、删除和更新功能,以及用户提交结果数据的访问,这类功能可以在一个独立的程序中实现,而且在大多数情况下可以做成传统的应用程序(非b/s结构的应用)。最后,dform.asp支持的输入域类型也有限,在实践中可能会有其他的表单输入要求,比如专用的e-mail地址输入框等。然而,对于那些经常要更新表单的网站来说,本文所讨论的表单动态生成、动态验证功能确实是非常有用的。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 复杂表单的动态生成与动态验证
分享到: 更多 (0)