表单验证
当用户提交表单后,接受数据的脚本需要完成以下任务:
- 检查必须的数据。如用户名不能为空。
- 验证数据是否为正确的类型,合适的标准。例如用户名不能是已存在的他人用户名,或者甚至是一个保留字等。
- 清理数据使其安全。如将某些字符转义,防止执行SQL语句。
- 如果需要,预格式化数据(数据需要清除空白吗?经过 HTML 编码?等。)
- 准备数据,插入数据库。
虽然这些任务都不是多困难,但仍然需要开发人员编写很多代码,而CodeIgnite框架提供了表单验证类,能对用户提交的数据进行验证,并给出错误提示,大大提高了开发效率。
表单验证的步骤
在login方法中,使用CodeIgnite框架提供的表单验证类进行数据验证。表单验证的过程如下:
- 装载表单验证类
form_validation
; - 设置表单验证规则
set_rules
; - 运行表单验证;
- 验证通过后,进行下一步操作。
public function login() {
// 载入验证类
$this->load->library( 'form_validation' );
// 设置验证规则
// 验证规则的三个参数分别是字段名、提示信息、验证规则
$this->form_validation->set_rules( 'uemail', '邮箱', 'required|valid_email' );
// 运行验证规则
if ( $this->form_validation->run() ) {
//do something
} else {
$this->login_form();
}
}
表单验证辅助函数
当用户输入不符合要求时,应该给用户一个提示信息,并而不是用户在暗黑中摸索。CodeIgnite框架中有相关的辅助函数form_error
可以让开发人员设置错误提示信息。
在表单视图文件的相应位置,增加表单验证错误信息显示:
<input type="email" class="form-control" name="uemail" placeholder="请输入你注册时的邮箱" required autofocus value=""><?php echo form_error('uemail'); ?>
除此之外,即便用户输入不符合验证规则,我们应该让用户在重新填写表单时保留之前已经填写的信息。重新填写可以使用CodeIgnite框架表单辅助函数set_value
、set_select
等。
<input type="email" class="form-control" name="uemail" placeholder="请输入你注册时的邮箱" required autofocus value="<?php echo set_value('uemail'); ?>"><?php echo form_error('uemail'); ?>
创建自定义验证规则
CodeIgnite表单验证类内置了许多验证规则,可在官方网站表单验证页面内中查看全部内置规则。常用的有:
- required 非空,必须要有值。
- is_unique 如果表单元素的值与指定数据表栏位有重复,则返回False。用法
is_unique[table.field]
- valid_email 如果表单元素值包含不合法的email地址,则返回FALSE。
- regex_match[] 使用正则表达式建立验证规则。
这些内置验证规则虽很丰富,但在有的情况下,我们还需要自定义验证规则,在CodeIgnite中使用回调方法就能实现,如:希望密码必须包含大小写字母和数字,并且不能少于6位。
在user控制器的login方法中,增加如下代码:
$this->form_validation->set_rules( 'upassword', '密码', 'callback_password_recheck' );
其中callback_password_recheck
参数表示调用password_recheck
验证方法。该方法内容如下:
public function password_recheck( $str ) {
// 设置密码正则匹配模式
$pattern = '/(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])\w{6,}/';
// 执行正则验证
if ( !preg_match( $pattern, $str ) ) {
// 设置错误提示信息
$this->form_validation->set_message( 'password_recheck', '%s 必须同时包含大写字母、小写字母和数字,并且6位以上' );
return FALSE;
} else {
return TRUE;
}
}
其中,set_message
函数用来设置错误提示信息,当用户输入的密码不符合要求时,将看到此方法设定的提示信息。
正则表达式的内容,读者可参阅相应章节。
除了使用set_rules()方法外,还可以使用数组形式建立验证规则:
$config = array(
array(
'field' => 'username',
'label' => '学生姓名',
'rules' => 'regex_match[/^[\x80-\xff]{6,}$/]',
'errors' => array(
'regex_match' => '姓名必须是两个以上的汉字',
),
)
)
推荐使用数组的方式书写验证规则,这种方式的优点是清晰、可读性强,代码简洁。
接受表单数据
当用户提交的表单信息全部都通过验证规则后,脚本的主要任务是从安全性方面对用户提交的数据进行处理,如防止SQL注入攻击、防止跨站脚本攻击1等等。CodeIgnite框架提供了输入类input用来完成这一任务。input类无需手动加载,CodeIgnite框架会自动加载此类。
输入类会自动执行以下任务:
- 过滤 GET/POST/COOKIE 数组键,只允许字母-数字(以及一些其它的)字符。
- 可以过滤跨站脚本攻击 (Cross-site Scripting Hacks) 此功能可全局打开(enabled globally),或者按要求打开。
- 换行符统一换为
\n
(Windows 下为\r\n
)。
自动过滤跨站脚本攻击的功能,在默认情况下是关闭的,故需修改配置文件(application/config目录中的config.php
),修改如下内容:
$config['global_xss_filtering'] = TRUE;
这样,我们就可以使用input类来接受用户提交的数据了:
$data = array(
'uemail' => $this->input->post( 'uemail' ),
// 使用md5方式加密密码
'upassword' => md5( $this->input->post( 'upassword' ) ),
);
Input类的常用方法有:
- post() input类的post方法用来获取全局数组post中的数据,如果数据不存在,将返回布尔值FALSE,该方法的第二个参数为TRUE时,将会对数据进行XSS过滤;
- get() 获取全局数组get中的数据,其他同上。
- cookie() 获得全局数组cookie中的数据,其它同上。
- server() 获得全局数组server中的数据,其它同上。
需要注意,表单验证相关的辅助函数只能在表单在正常方式提交时才能正常使用,当使用异步方式提交表单时,无法提示错误信息和回填表单内容。开发人员最好使用基于前端的表单验证。
1. 理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。 ↩