1. 表单与HTML
表单是Web应用中最常用的组件,由提交按钮以及其他相关元素组成。表单被应用在各个领域中,用于实现注册用户、填写银行账户和登录等功能。
表单使用<form>作为开始标签,以</form>为结尾,否则将不起任何作用。在一个HTML页面中允许有若干个表单,在编写时以表单的名字(name)和FormID作为它们之间的区分。
下面是最简单的表单,代码如下:
<form>
<input type="submit" />
</form>
这个表单在浏览器上只会显示一个按钮“提交查询内容”字样,没有太多的意义。如果要提交数据并形成一个完整的表单,需要在标签增加两个比较重要的属性标签:action和method,如以下表单所示:
<form name="regform" id="regform"action="getPasswd.php" method="post">
</form>
其中,action标签指的是接收处理结果的文件位置,当action值为空时,则提交给当前文件本身,如果action的值为其他文件或URL,则提交给该文件或URL地址处理。
method标签是描述提交数据时使用的方法,它有两种值:GET和POST,如果没有设置method属性或该属性为空值,浏览器默认method的值为POST方法。
下面是处理POST表单的方法。
例5-1:getPasswd.php – 接受POST表单提交的值
<?php
$action =$_SERVER['PHP_SELF'];
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
}
?>
<form name="regform" id="regform"action="<?php echo $action;?>"method="post">
</form>
如果要在浏览器中发送表单或数据给服务器端,使用GET或POST方法都能实现。GET方法是在访问URL时,使用浏览器地址栏来传递值。我们可以在很多网站上看到这类URL串,图5-1所示的就是使用GET方法传递参数。
GET方法方便直观,缺点是访问该网站的用户也可以修改URL串后发送给服务器,如果程序处理得不够好很容易出错,而且GET传递的字符串长度不能超过250个字符,如果超长,浏览器会自动截断,导致数据缺失。另外,GET方法不支持ASCII字符之外的任何字符,比如包含有汉字或其他非ASCII字符时,需要使用额外的编码操作,虽然有时候浏览器也能自动完成(可以使用url_encode和url_decode函数,使用方法详见**节)。
POST方法发送变量数据时,对于用户来说是不透明的,按HTTP协议来说,数据附加于header的头信息中,用户不能随意修改,这对于Web应用程序而言,安全性要好得多,而且使用POST可以发送大体积的数据给Web服务器。
因为POST是随HTTP的header信息一起发送的,当触发POST表单提交后,如果用户浏览页面时单击“后退”按钮,浏览器不会自动重发POST数据。如果用户此时单击“刷新”按钮,将会有“数据已经过期,是否重新提交表单”的提示,这一点不如GET使用方便。使用GET传值时,即便用户使用“后退”或“刷新”按钮,浏览器的URL地址也是仍然存在的。
因此,我们在开发中需要根据实际应用灵活选择GET和POST来提交表单数据。
值得一提的是,如果在HTML中缺少表单结束标记,那么整个表单是不会触发任何提交动作的。在实际开发时,一些粗心的人会发现单击按钮没有任何反映,其实细心检查一下表单的代码就可以了,有时即使少写了一个HTML字符,浏览器也不会替我们干活的。
2. 表单元素
表单所使用的标签元素有十几个,PHP开发中常用及较重要的标签如下所示。
表单元素 | 说 |
input type="checkbox" | 复选框,允许用户选择多个选择项 |
input type="file" | 文件浏览框,当文件上传时,可用来打开一个模式窗口以选择文件 |
input type="hidden" | 隐藏标签,用于在表单中以隐含方式提交变量值 |
input type="password" | 密码文本框,用户在该文本框输入字符时将被替换显示为*号 |
input type="radio" | 单选项,用于设置一组选择项,用户只能选择一个 |
input type="reset" | 清除与重置表单内容,用于清除表单中所有文本框的内容,而且使选择菜单项恢复到初始值 |
input type="submit" | 表单提交按钮 |
input type="text" | 单行文本框 |
select | 下拉列表框,可单选和多选。默认为单选,如果增加多项选择功能,增加<selectname="select" size="自定义列数"multiple="multiple">即可 |
option | 列表下拉菜单,和select配合使用,显示供选择的值 |
textarea | 多行文本框,在使用文本框时需要关闭标签之间的文本内容,形成如下格式:<Textarea>你的文字</Textarea> |
其中,hidden标签被称为隐藏或隐含的标签,它不会在用户浏览的页面界面上出现,当用户填写资料表单和跨页之间传值时,可以使用该标签传递一些隐含的值。
password密码文本框用于隐藏密码,用户输入的文本将以*显示在文本框中,但是密码并没有加密,只是被*替换显示,这点请注意。
下面介绍表单的属性,它们用于表单中约束表单元素的行为或显示,其含义与约束如下所示。
属性名称 | 说 |
name | 文本框的名称,PHP根据该名称,在超级全局数组中建立以name为名称的键名 |
size | 文本框的宽度,在select下拉菜单中,表示可以看到的选项行数 |
value | 文本框中的默认值,注意,该值不能应用到type=password密码文本框以及type=file文件文本框中 |
multiple | 此属性用于下拉列表菜单select中,指定该选项用户可以使用Ctrl和Shift键进行多选 |
rows | 多行文本框显示时可以容纳的字符列数宽度 |
cols | 多行文本框显示时可以容纳的字符行数高度 |
除了以上一些必要的属性元素外,还有一些标准属性,如class,style,id等,可以参阅HTML相关资料。
在一些动态脚本中,需要使用PHP根据不同的请求从数据库生成表单元素,下面我们就来展示几种生成表单按钮或选项的方法。
1.动态生成一组单选按钮。
<?php
$options = array("010" => "北京",
$default = "024";
$html = generate_radio_group("city_id", $options, $default);
echo $html;
function generate_radio_group($name, $options, $default=""){
$name = htmlentities($name);
foreach($options as $value => $label) {
}
return($html);
}
?>
该脚本将生成一列单选按钮组,名称为city_id,默认选项为024-“沈阳”。
2.动态生成多选项下拉列表菜单。
<?php
function generate_checkboxes($name,$options, $default=array()){
if (!is_array($default)){
}
foreach($options as $value => $label) {
}
return($html);
}
$interests = array("音乐" => "音乐",
$html = generate_checkboxes("interests",$options,$interests);
?>
选择您的爱好:
<form action="interests.php"method=post>
<?php echo $html;?>
<input type=submit value="继续">
</form>
3.生成多选下拉列表菜单。
<?php
$options = array(
);
$default ="news";
$html =generate_muilti_option("select", $options, $default);
echo $html;
function generate_muilti_option ($name,$options, $default){
}
?>
一般动态生成的菜单,多为从数据库取得数据或数据数组,转换成动态HTML菜单,也可以手工创建.
3. 表单的处理方法
3.1 检查表单提交的来源
有些时候,我们需要对表单提交的来源进行处理,比如只允许某个主机或向脚本本身进行提交,防止有的人伪造相同的表单向我们的程序提交,造成安全问题。
前面我们介绍到,PHP的$_SERVER服务器超级全局数组提供了一个叫$_SERVER['HTTP_REFERER']的变量,用于保存上一页的来源,比如表单提交或者超级链接的URL地址。如果有人从他的计算机中提交表单或从浏览器地址中直接输入当前脚本名称,该变量会保存表单来源或为空值,这样我们就可以通过它的值进行处理。
下面的例子只允许文件本身提交表单传递值。
例:formreferer.php – 判断表单来源地址
<?php
$action = $_SERVER['PHP_SELF'];
if ($_SERVER['REQUEST_METHOD'] == 'POST'){
$ref
服务器地址为:
$srv
--------------------------------------------------------------------------------
";
}else{
?>
<form action="<?php echo$action;?>" method="post">
<input type="submit"value="提交"/>
</form>
该例中用到的$_SERVER服务器变量有如下几个:
? HTTP_REFERER 保存一个完整的来源URL地址。
? SERVER_NAME 当前的服务器名称。
? PHP_SELF 当前脚本的完整路径,包括文件名。
我们可以通过“http://<SERVER_NAME><PHP_SELF>==<HTTP_REFERER>”来比较,如果相同,则是合法的表单提交,否则不予处理。运行上例脚本,单击“提交”按钮后的结果如下所示。
![PHP表单详解 PHP表单详解](http://img.blog.163.com/photo/BZLr7JwbpVf-LW0k6EIx7g==/4237605774379896029.jpg)
3.2 一个完整表单处理
前面我们已经了解了处理表单的简单方式。下面我们将创建一个复杂的表单,代码如下所示。
<form action="someform.php"method="post">
<table width="541" border="0">
<tr>
</tr>
<tr>
</tr>
<tr>
</tr>
<tr>
</tr>
<tr>
体育爱好:
网球
足球
<input type="radio" name="fave_sport"value="baseball">
篮球
<input type="radio" name="fave_sport"value="polo">
保龄球 </td>
</tr>
<tr>
php
<input type="checkbox" name="languages[]"value="java" id="languages[]">
java
<input type="checkbox" name="languages[]"value="perl" id="languages[]">
perl
<input type="checkbox" name="languages[]"value="cpp" id="languages[]">
c++
<input type="checkbox" name="languages[]"value=".net" id="languages[]">
.NET
<input type="checkbox" name="languages[]"value="delphi" id="languages[]">
delphi </td>
</tr>
<tr>
</tr>
<tr>
</tr>
</table>
</form>
该表单包括了常用表单元素:单行文本框、多行文本框、单选项(radio)、多选项(checkbox),以及多选菜单。下面进行详细的说明。
? maxlength是与密码文本框关联的属性,它限制用户输入密码的最大长度为10个字符。
?age列表框是列表菜单,它的命名属性下都有自己的值供选择。selected是一个特定的属性选择元素,如果某个option附加有该属性,在显示时就把该项列为第一项显示。
? intro文本框中的内容,按照rows和cols显示文字、行和列宽。
?fave_sport是一组单选按钮(radio),我们要按组命名元素名称,比如这一组单选按钮都叫做fave_sport,用户只可选择一个,发送脚本端也只存在一个值。
?和单选项一样,所有多选项成员也须有同名的属性,而属性名称需要添加括号[],这样就把多选项的值以数组形式发送给PHP,languages就是这种形式。
? checked标签是指单选项和多选项中的某个值,默认已经被选择。
上面表单的显示画面如下所示。
![PHP表单详解 PHP表单详解](http://img.blog.163.com/photo/B3WMmpIyWTIq2Jh3V6as0w==/323133273264809038.jpg)
因为上面HTML中的form表单使用的是POST方法传递数据,所以用户提交的数据会保存到$_POST或$_REQUEST的超级全局数组中,我们根据$_POST数组中的值就可以处理提交的数据。
将上面表单中数据提交到someform.php脚本,该脚本的处理逻辑如下:
<?php
//通过判断按钮的变量名是否在$_POST中定义,如果有表示该表单已提交
if(isset($_POST["btn_submit"])){
";
}
?>
说明:使用POST方式提交表单,通过HTTP协议的header部分传递表单数据,理论上数据的大小无上限。不过,在使用PHP进行POST提交时,文件大小受PHP配置文件(php.ini)限制,我们可以修改php.ini文件中的post_max_size参数,可将默认的2M字节,修改为自己需要的大小,但由于HTTP协议的特性,这个值不宜设置过大,最大以8M为宜。
4 其他处理表单的方法
下面,让我们一起来看两种处理表单的编程方法以及它们的优缺点。
4.1 使用import_request_variables()函数
使用import_request_variables()函数可以有选择地注册全局变量集合。你可以使用该函数导入$_GET、$_POST和$_COOKIE的值,还可以为每个导入的变量添加前缀(prefix)。
bool import_request_variables ( string types [,stringprefix])
参数中types字符串中允许为g、p、c字符,或者3个字符间任意的组合。其中,“g”表示GET变量,“p”表示POST变量,“c”表示cookies。
注意:3个字符的排列顺序是有区别的,当使用“pg”时,POST变量将使用相同的名字覆盖$_GET变量;反之,当使用“gp”时,$_GET变量数组将优先于$_POST。
prefix参数作为变量名的前缀,置于所有被导入到全局作用域的变量之前。比如我们有个名为“userid”的$_GET超级全局变量数组,同时提供了“pref_”作为前缀,那么我们将获得一个名为$pref_userid的全局变量。如果我们要导入其他全局变量(例如$_SERVER变量),则请考虑使用extract()函数(在函数一章中有介绍)。注意,在使用prefix前缀时,不要与现有数据或变量名产生冲突。
使用import_request_variable()函数实现变量导入的脚本例子如下:
//导入POST提交的变量值,前缀为post_
import_request_variable("p", "post_");
//导入GET和POST提交的变量值,前缀为gp_,GET优先于POST
import_request_variable("gp", "gp_");
//导入Cookie和GET的变量值,Cookie变量值优先于GET
import_request_variable("cg", "cg_");
如果我们在import_request_variables()函数中使用了“pg参数”,请看如下脚本实例:
<?php
if(isset($_REQUEST['btn_submit'])){
echo "正常取得的表单POST变量值:".$_REQUEST['Username']."<br/>";
import_request_variables("pg", "import_");
//显示导入的变量名称
echo "使用import_request_variables函数导入的变量值:".$import_Username;
}
?>
<form id="test_form" name="test_form"method="POST" action="">
请输入您的名字:
<label>
<input type="text" name="Username" id="Username"/>
</label>
<label>
<input type="submit" name="btn_submit"id="btn_submit" value="提交" />
</label>
<br />
</form>
该表单提示用户输入一个名字,完成并提交后,脚本会把提交的名字显示在浏览器上,如下所示。
![PHP表单详解 PHP表单详解](http://img.blog.163.com/photo/rgRji8mLw9KacFgVL18pmw==/323133273264809040.jpg)
注意:prefix前缀参数是必选的,如果未指定前缀,或者指定一个空字符串作为变量前缀,PHP会抛出一个E_NOTICE错误。
import_request_variables()函数为我们提供一个中间方法,适用于如下几种情况:
1.当用户不能使用超级变量数组时;
2.在php.ini配置文件的register_globals参数为Off(PHP5之后的版本默认为Off)时,使用import_request_variables将GET/POST/Cookie这几个超级变量数组导入到全局作用域中。
3.在开发时,只要声明了引入的变量范围,就不必写$_GET或$_REQUEST一堆很长的超级全局数组名称了。
4.2 使用extract()函数
我们可以使用extract()函数,比如在接收页面脚本的最前面加上extract($_POST);extract($_GET);这样的语句,导出几个用于表单处理的超级变量数组值,如以下代码所示:
@extract(i_addslashes($_POST), EXTR_OVERWRITE);
@extract(i_addslashes($_GET), EXTR_OVERWRITE);
@extract(i_addslashes($_COOKIE), EXTR_OVERWRITE);
@extract(i_addslashes($_SESSION), EXTR_OVERWRITE);
我们看一个使用extract导出为正常变量的脚本例子:
<?php
?>
<form action="" method="post">
姓名:
年龄:<select name="age">
<input type="submit" name="btn_submit" value="提交"/>
</form>
实现的界面如下所示。
![PHP表单详解 PHP表单详解](http://img.blog.163.com/photo/JSsKMXcv_DnaHbW5MR_pCA==/323133273264809041.jpg)
5. 多页面间传递数据
当遇到一个非常大的表单时,不可能把所有的表单都放在一个页面里面,需要将一个大表单分解成若干个小表单,并保存于几个页面中,当第一个表单填写完后,需要收集该表单的值并传递给下一个表单页面。
我们可以使用如下方法进行处理。
?使用表单的隐含元素(hidden)。
?把当前表单的数据保存在SESSION中(详情请参见会话一章)。
?把当前表单的数据保存在MySQL数据库中。
你可以从以上三个方案中选择一种易于程序处理和调试的解决方案。表单的传值可以使用POST,这样传递数据的尺寸不成问题,另外,在调试程序时,我们可以通过查看HTML源文件方式,来知道当前的变量是否是预想的值。
对于一个非常大的表单,我们就要想办法把它们分解成两个或更多个表单以方便用户输入,这需要在页面间传值,代码如下:
<INPUT TYPE="HIDDEN"NAME="Name" VALUE="<?php echo $_REQUEST['Name'];?>">
<INPUTTYPE="HIDDEN" NAME="Password" VALUE="<?php echo$_REQUEST['Password']; ?>">
当多个页面传递数据时,我们可以使用类似上面的语句来处理一页或通过URL传递的值。
6. 多页面间传递数据
当遇到一个非常大的表单时,不可能把所有的表单都放在一个页面里面,需要将一个大表单分解成若干个小表单,并保存于几个页面中,当第一个表单填写完后,需要收集该表单的值并传递给下一个表单页面。
我们可以使用如下方法进行处理。
?使用表单的隐含元素(hidden)。
?把当前表单的数据保存在SESSION中(详情请参见会话一章)。
?把当前表单的数据保存在MySQL数据库中。
你可以从以上三个方案中选择一种易于程序处理和调试的解决方案。表单的传值可以使用POST,这样传递数据的尺寸不成问题,另外,在调试程序时,我们可以通过查看HTML源文件方式,来知道当前的变量是否是预想的值。
对于一个非常大的表单,我们就要想办法把它们分解成两个或更多个表单以方便用户输入,这需要在页面间传值,代码如下:
<INPUT TYPE="HIDDEN" NAME="Name"VALUE="<?php echo $_REQUEST['Name'];?>">
<INPUT TYPE="HIDDEN" NAME="Password"VALUE="<?php echo $_REQUEST['Password'];?>">
当多个页面传递数据时,我们可以使用类似上面的语句来处理前一页或通过URL传递的值。
7. 表单安全
网站的访客是千差万别的,他可能是一个学生,也可能是一位教授,可能是一个什么都不懂的电脑菜鸟,更有可能是个黑客,不管是弹出意外的错误,还是故意找碴,他们总是喜欢不按我们希望的方式输入,或者寻找我们网站的安全漏洞。
网站中一些常见漏洞,很多原因是开发者的大意造成的,当然还有一部分原因是因为操作系统或服务器配置的原因。常见的安全隐患与比例如下所示。
程序缺陷 | 比 |
用户输入不做验证 | 42.60% |
访问控制缺陷 | 3.60% |
SESSION ID验证漏洞 | 5.40% |
数据库SQL注入 | 28.60% |
文章转载地址:http://blog.sina.com.cn/s/blog_68f8522f0100mg88.html