表单验证–kohana3使用手册
验证类被按下面给出的规则用来验证任何数据的数组。它主要用来验证表单的$_POST数据。类中有一些规则已经为我们验证了并且允许我们使用回调函数。该类允许你的每个数组域设置自己的错误信息,那么你就能构建你自己的表单了。
首先是过滤器处理的字段,然后是规则,最后是回调函数。
开始
加载库
// 创建一个新的验证(Vaildate)类的对象来验证$_POST变量
$post = new Validate($_POST);
// 合并不同的数组
$post = new Validate(array_merge($_POST, $_FILES));
// 使用工厂方法能联合操作
$post = Validate::factory($_POST)->rule('field_name', 'not_empty')
->rule('field_name2', 'email');
// 增加一个过滤规则的数组
$rules = array(
'field_name' => array
(
'not_empty' => NULL,
'max_length' => array(32),
),
'field_name2' => array
(
'min_length' => array(4),
),
);
$post = Validate::factory($_POST)->rules('field_name', $rules['field_name'])
->rules('field_name2', $rules['field_name2']);
// 你也可以直接使用$_POST数组(不推荐)
$_POST = new Validate($_POST);
增加规则(必须)
验证(Validate)对象创建好之后,你需要给你增加一些规则。他们中的一些用类本身定义。
$post = new Validate($_POST);
$post->rule('username', 'not_empty')
->rule('password', 'not_empty')
->rule('password', 'min_length', array(5))
->rule('password', 'max_length', array(42));
$post = Validate::factory($_POST)->rule('username', 'not_empty')
->rules(
'password' => array(
'min_length' => array(5),
'max_length' => array(42),
)
);
规则被回调到函数并和该函数使用一样,但是它们返回一个布尔值,所以他们能验证数据是否通过。我们可以使用我们预定义的类,php,以及我们自己的规则。
预定义函数:
$post = Validate::factory($_POST)->rule(‘age’, ‘numeric’);
PHP函数:
$post = Validate::factory($_POST)->rule(‘age’, ‘is_numeric’);
用户定义的函数:
$post = Validate::factory($_POST)->rule('age', 'Model_User::check_numeric');
public static function check_numeric($str)
{
// 获得当前本地设置的允许小数点
list($decimal) = array_values(localeconv());
return (bool) preg_match('/^-?[0-9'.$decimal.']++$/D', (string) $str);
}
所有字段增加一个规则
同样的规则可以一次性被定义在所有的字段,只需要用TRUE来作为字段名
// 应用not_empty规则到$_POST所有字段 $post = Validate::factory($_POST)->rule(TRUE, 'not_empty');
增加过滤器(可选)
过滤器在验证之前处理。你可以在第一个参数使用TRUE来让过滤器应用在所有字段。验证过滤器是任何可以返回字符串的PHP函数。
你也可以使用可选的第三个参数来传递一个参数组成的数组给函数。你使用的函数被调用时必须返回值到第一个参数。
注意Kohana3.x版本不再有pre_filter和post_filter()。这就意味着你将使用filter()来预过滤,如果需要,为post过滤回调。
你可以为所有字段增加一个过滤器,只要在字段名处使用TRUE
// 去掉username的空白
$post = Validate::factory($_POST)->filter('username', 'trim');
// 传递参数到过滤器函数.
// will call: htmlspecialchars($_POST['username'], ENT_QUOTES)
$post = Validate::factory($_POST)->filter('username', 'htmlspecialchars', array(ENT_QUOTES));
// 为所有字段使用一个静态定义的函数作为过滤器
$post = Validate::factory($_POST)->filter(TRUE, 'Model_User::myfilter', array($param1, $param2));
class Model_User extends Model_Auth_User {
public static function myfilter($value, $param1, $param2)
{
$value = ... //some code// ...
return $value;
}
}
// 使用filters()来定义一个过滤器数组
$post = Validate::factory($_POST)->filters(
'username' => array(
'Model_User::myfilter' => array($param1, $param2),
'trim' => NULL,
)
);
增加回调(可选)
不同的规则,回调函数可以在字段上使用一些更复杂的验证。如果必须需要在验证对象中增加错误,那么就作为第一个参数来传递。
你可以为所有字段增加一个过滤器,只要在字段名处使用TRUE
调用 callback()方法:
用户定义的函数
// 调用用户定义的函数 reserved_username $post = Validate::factory($_POST)->callback( 'username', 'reserved_username');
用静态方法作为回调函数
$post = Validate::factory($_POST)->callback('username', 'Model_User::mystatic_callback');
用对象的方法作为回调函数
$post = Validate::factory($_POST)->callback( 'username', array($this, 'username_available'));
用callbacks()回调数组
$post = Validate::factory($_POST)->callbacks( 'username', array(
'reserved_username'
'Model_User::mystatic_callback',
array($this, 'username_available'),
)
);
示例:
// 使用email_change()回调函数来验证我们的$_POST数据。
// 检查用户是否能可以改变它的email地址当该邮件地址现在还没有其他用户使用.
$post = Validate::factory($_POST)->callback('email', array($this, 'email_change'));
/**
* 检验用户是否能改变email变成这样
*
* @param Validate $array validate object
* @param string $field field name
*/
public function email_change(Validate $array, $field)
{
$exists = (bool) DB::select(array('COUNT("*")', 'total_count'))
->from($this->_table_name)
->where('email', '=', $array[$field])
->where('id', '!=', $this->id)
->execute($this->_db)
->get('total_count');
if ($exists)
$array->error($field, 'email_change', array($array[$field]));
}
增加错误
你可以用error()方法增加错误
error($field, $error, array $params = NULL)
示例:
$post->error('username', 'username_available', array('johndoe'));
定义错误信息
可以在messages目录里找到国际化的文件。这些目录可以在system,application,modules目录中被发现。Kohana自己的信息文件在 system目录中。
当错误键在数组中没有被找到的时候,default键将会被使用。
例如:application/messages/register.php
return array
(
'email' => array(
'email_available' => 'The email address already exists',
'default' => 'Invalid Input.',
),
'username' => array(
'username_available' => 'The username already exists',
'default' => 'Invalid Input.',
),
); // application/messages/register.php的结尾
如果错误信息的值在你的i18n目录中存在,那么错误信息会自动被翻译。查看翻译信息。
检索错误信息
可以用errors()方法来检索错误信息。默认返回的数组,包含字段名组成的键(key),规则组成的值(value)
检索自定义的错误信息,必须传递一个错误信息文件到errors()方法。
$errors = $validation->errors();
假定定义了一个规则,规则(‘username’,’usernam_available’) $errors 数组
包含:
array(
('username' => 'username_available')
)
使用错误信息文件取得错误:
$errors = $validation->errors(‘register’)
假定你的信息目录中存在一个 register.php文件并且内容如上面写的。那么 $errors将包含:
array(
('username' => 'The username already exists')
)
检索输入的数据
经过as_array()来验证插入的数据是否可进入。这对于重新填写表单字段非常有用,例如:
$_POST = array_intersect_key( $post->as_array(), $_POST);
规则
验证(Validate)类中的特定规则
| 规则 | 参数 | 描述 | 示例 |
| not_empty | 无 | 如果表单字段为空,返回FALSE | |
| min_length | 有 | 如果字段太短,返回FALSE | length[5] - 最少5个字符长 |
| max_length | 有 | 如果字段太长,返回FALSE | length[30]- 最多30个字符长 |
| exact_length | 有 | 如果字段太长或太短,返回FALSE | length[25]- 仅可以25个字符 |
| matches | 有 | 如果字段不匹配参数,返回FALSE | matches[再一次密码] |
| date | 无 | 如果字段非有效日期,返回FALSE | |
| regex | 有 | 如果字段不符合正则表达式,返回FALSE | regex[表达式] – 正则表达式来匹配(包括分隔符) |
| 可选 | 如果email无效,返回FALSE | mail[TRUE] – 严格的rfc822 | |
| email_domain | 无 | 如果email域名没有有效地MX记录,返回FALSE | |
| url | 无 | 如果url无效,返回FALSE | |
| ip | 可选 | 如果ip无效,返回FALSE | ip[TRUE] – 允许私有ip网络 |
| credit_card | 有 | 如果信用卡无效,返回FALSE | credit_card[万事达卡] – 卡类型或者卡类型的数组 |
| phone | 可选 | 如果电话号码不是有效长度,返回FALSE | phone[7,10,11,14] – 7,10,11或14中的一个长度(默认7,10和11) |
| alpha | 可选 | 如果字段不是只有字母组成,返回FALSE | alpha[TRUE] – 触发 UTF-8 兼容性 |
| alpha_numeric | 可选 | 如果字段不是只有字母或者数字组成,返回FALSE | alpha_numeric[TRUE] – 触发 UTF-8 兼容性 |
| alpha_dash | 可选 | 如果字段不是只有字母,数字,下划线和破折号组成,返回FALSE | alpha_dash[TRUE] – 触发 UTF-8 兼容性 |
| digit | 可选 | 如果字段不是只有数字字符(无点号或横线),返回FALSE | digit[TRUE] – 触发UTF-8兼容 |
| numeric | 无 | 如果字段是一个无效的数字(正负或小数),返回FALSE | |
| decimal | 可选 | 如果字段不是完全的小数格式,可选参数是个特定的小数格式,则返回FALSE | decimal – 是任何有效的小数格式
decimal[4,2] 是4个整数和2个小数 |
| range | 有 | 如果字段不是随机在最大和最小范围之内,则返回FALSE | range[1,10] – 在1和10之间 |
| color | 无 | 如果字段不是一个适当的16进制HTML颜色值,则返回FALSE |
示例
创建和验证表单
//验证一个用户注册
function action_register()
{
#例举一个新用户
$user = ORM::factory('user');
#加载验证规则,过滤器和回调函数
$post = $user->validate_create($_POST);
#验证所有的字段的有效性
if ($post->check())
{
#影响并清理user对象的变量
$user->values($post);
#创建账户
$user->save();
#为用户添加登录角色
$login_role = new Model_Role(array('name' =>'login'));
$user->add('roles',$login_role);
#标记用户进入
Auth::instance()->login($post['username'], $post['password']);
#重定向用户账号
Request::instance()->redirect('myaccount');
}
else
{
#重新注入$_POST数据
$_POST = array_intersect_key( $post->as_array(), $_POST);
#影响所要进一步显示的错误
$this->errors = $post->errors('register');
}
}
我们的 Model_User
class Model_User extends Model_Auth_User {
protected $_rules = array
(
'username' => array
(
'not_empty' => NULL,
'min_length' => array(4),
'max_length' => array(32),
'regex' => array('/^[-\pL\pN_.]++$/uD'),
),
'password' => array
(
'not_empty' => NULL,
'min_length' => array(5),
'max_length' => array(42),
),
'password_confirm' => array
(
'matches' => array('password'),
),
'email' => array
(
'not_empty' => NULL,
'min_length' => array(4),
'max_length' => array(127),
'validate::email' => NULL,
),
);
protected $_callbacks = array
(
'username' => array('username_available'),
'email' => array('email_available'),
);
public function validate_create(& $array)
{
// 初始化验证库并设置一些规则
$array = Validate::factory($array)
->rules('password', $this->_rules['password'])
->rules('username', $this->_rules['username'])
->rules('email', $this->_rules['email'])
->rules('password_confirm', $this->_rules['password_confirm'])
->filter('username', 'trim')
->filter('email', 'trim')
->filter('password', 'trim')
->filter('password_confirm', 'trim');
#增加 Model_Auth_User 回调函数
foreach ($this->_callbacks as $field => $callbacks)
{
foreach ($callbacks as $callback){
$array->callback($field, array($this, $callback));
}
}
return $array;
}
public function validate_change(& $array, $save = FALSE){
// 初始化验证哭并设置一些规则
$array = Validate::factory($array)->rules('email', $this->_rules['email'])
->filter('email', 'trim')
->filter('password', 'trim')
->callback('email', array($this, 'email_change'));
if(trim($array['password']) != '')
$array->rules('password', array('min_length'=> array(5), 'max_length'=>array(42)));
return $array;
}
/**
* 验证用户是否改变了email成为这个
*
* @param Validate $array validate object
* @param string $field field name
*/
public function email_change(Validate $array, $field)
{
$exists = (bool) DB::select(array('COUNT("*")', 'total_count'))
->from($this->_table_name)
->where('email', '=', $array[$field])
->where('id', '!=', $this->id)
->execute($this->_db)
->get('total_count');
if ($exists)
$array->error($field, 'email_change', array($array[$field]));
}
/**
* 如果用户名存在于验证规则的unique_key_exists()失败是否触发错误
*
* @param Validate $array validate object
* @param string $field field name
* @param array $errors current validation errors
* @return array
*/
public function username_available(Validate $array, $field)
{
if ($this->unique_key_exists($array[$field])) {
$array->error($field, 'username_available', array($array[$field]));
}
}
/**
* 如果email存在于验证规则的unique_key_exists()失败,是否触发错误
*
* @param Validate $array validate object
* @param string $field field name
* @param array $errors current validation errors
* @return array
*/
public function email_available(Validate $array, $field)
{
if ($this->unique_key_exists($array[$field])) {
$array->error($field, 'email_available', array($array[$field]));
}
}
/**
* 测试是否是存在于数据库中唯一的键
*
* @param mixed value the value to test
* @return boolean
*/
public function unique_key_exists($value)
{
return (bool) DB::select(array('COUNT("*")', 'total_count'))
->from($this->_table_name)
->where($this->unique_key($value), '=', $value)
->execute($this->_db)
->get('total_count');
}
/**
* 允许一个模型使用email和username均为唯一标识符的情况下登录
*
* @param string $value unique value
* @return string field name
*/
public function unique_key($value)
{
return Validate::email($value) ? 'email' : 'username';
}
}
验证文件上传
这里是一个验证文件上传的示例
$validate = Validate::factory($_FILES);
$validate->rules('file',
array('Upload::valid' => array(),
'Upload::not_empty' => array(),
'Upload::type' =>array('Upload::type' => array('jpg','png','gif')),
'Upload::size' => array('1M'))
);
if ($validate->check())
{
//成功
Upload::save($_FILES['file'],'my_image.png','./',777);
}
else
{
//错误
$this->errors = $validate->errors('upload');
print_r($this->errors);
}
application/messages/upload.php
return array
(
'file' => array(
'Upload::valid' => 'valid msg',
'Upload::not_empty' => 'not_empty msg',
'Upload::type' => 'type msg',
'Upload::size' => 'size msg',
'default' => 'default msg'),
);