Codeigniter-验证数据类

个人需求,仿着CI的表单验证写了一个自己的验证类

1.定义验证类

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
// required    No    如果元素为空,则返回FALSE     
// matches    Yes    如果表单元素的值与参数中对应的表单字段的值不相等,则返回FALSE    matches[form_item]
// is_unique    Yes    如果表单元素的值与指定数据表栏位有重复,则返回False(译者注:比如is_unique[User.Email],那么验证类会去查找User表中Email栏位有没有与表单元素一样的值,如存重复,则返回false,这样开发者就不必另写Callback验证代码。)    is_unique[table.field]
// min_length    Yes    如果表单元素值的字符长度少于参数中定义的数字,则返回FALSE    min_length[6]
// max_length    Yes    如果表单元素值的字符长度大于参数中定义的数字,则返回FALSE    max_length[12]
// exact_length    Yes    如果表单元素值的字符长度与参数中定义的数字不符,则返回FALSE    exact_length[8]
// greater_than    Yes    如果表单元素值是非数字类型,或小于参数定义的值,则返回FALSE    greater_than[8]
// less_than    Yes    如果表单元素值是非数字类型,或大于参数定义的值,则返回FALSE    less_than[8]
// alpha    No    如果表单元素值中包含除字母以外的其他字符,则返回FALSE     
// alpha_numeric    No    如果表单元素值中包含除字母和数字以外的其他字符,则返回FALSE     
// alpha_dash    No    如果表单元素值中包含除字母/数字/下划线/破折号以外的其他字符,则返回FALSE     
// numeric    No    如果表单元素值中包含除数字以外的字符,则返回 FALSE     
// integer    No    如果表单元素中包含除整数以外的字符,则返回FALSE     
// decimal    No    如果表单元素中包含非十进制数字时,则返回FALSE     
// is_natural    No    如果表单元素值中包含了非自然数的其他数值 (其他数值不包括零),则返回FALSE。自然数形如:0,1,2,3....等等。     
// is_natural_no_zero    No    如果表单元素值包含了非自然数的其他数值 (其他数值包括零),则返回FALSE。非零的自然数:1,2,3.....等等。     
// valid_email    No    如果表单元素值包含不合法的email地址,则返回FALSE     
// valid_emails    No    如果表单元素值中任何一个值包含不合法的email地址(地址之间用英文逗号分割),则返回FALSE。     
// valid_ip    No    如果表单元素的值不是一个合法的IP地址,则返回FALSE。通过可选参数"IPv4"或"IPv6"来指定 IP 地址格式。     
// valid_base64    No    如果表单元素的值包含除了base64 编码字符之外的其他字符,则返回FALSE。

class Validation {

    protected $_field_data = array();
    protected $_config_rules = array();

    public function __construct()
    {
        //获取CI对象
        $this->CI =& get_instance();

        //读取验证类配置文件 TODO
        
    }


    public function set_rules($field, $rules = '')
    {
        //如果field是数组,我们遍历它并递归调用这些验证方法
        if (is_array($field)) {
            foreach ($field as $key => $row) {
                //检查数组数据
                if (!isset($row['field']) OR !isset($row['rules'])){
                    continue;
                }

                $this->set_rules($row['field'], $row['rules']);
            }
            return $this;
        }

        //不存在$field或者为空,返回
        if (!is_string($field) OR $field == '') {
            return $this;
        }

        //如果field是数组,拆分
        if (strpos($field, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $field, $matches)) {

            foreach ($matches[1] as $index) {
                if ($index != ''){
                    $indexes[] = $index;
                }
            }

            $is_array = TRUE;
        }
        else {
            $indexes = array();
            $is_array = FALSE;
        }

        //设置字段规则
        $this->_field_data[$field] = array(
            'field' => $field,
            'rules' => $rules,
            'is_array' => $is_array,
            'keys' => $indexes,
            'data' => NULL,
        );

        return $this;
    }

    public function _reduce_array($array, $keys, $i = 0)
    {
        if(is_array($array)) {
            //递归查询每个键名下的数组
            if (isset($keys[$i])){
                if (isset($array[$key[$i]])) {
                    $array = $this->_reduce_array($array[$key[$i]], $keys, ($i+1));
                }
                else{
                    return NULL;
                }
            }
            else {
                return $array;
            }
        }

        return $array;
    }

    public function _execute($row, $cycles = 0)
    {
        $is_valid = TRUE;
        //如果字段数据data是数组,我们执行递归调用
        if (is_array($row['data'])) {
            foreach ($data as $key => $value) {
                if ( ! $this->_execute($row, $cycles)) {
                    $is_valid = FALSE;
                    break;
                }

                $cycles++;
            }

            return $is_valid;
        }
        extract($row);
        // --------------------------------------------------------------------

        //如果字段为空,并不要求,没必要进行验证
        $callback = FALSE;
        if (!in_array('required', $rules) AND is_null($data)){
            return $is_valid;
        }

        // --------------------------------------------------------------------

        //应用到复选框TODO
        
        // --------------------------------------------------------------------
        
        //遍历并执行验证
        foreach ($rules as $key => $rule) {

            //如果验证规则带有回调函数
            $callback = FALSE;
            if (substr($rule, 0, 9) == 'callback_'){
                $rule = substr($rule, 9);
                $callback = TRUE;
            }

            //如果验证规则带有参数
            $param = FALSE;
            if (preg_match("/(.*?)\[(.*)\]/", $rule, $match)){
                $rule = $match[1];
                $param= $match[2];
            }

            // 调用对应规则的方法验证
            // 回调函数验证
            if ($callback === TRUE) {

                if (!method_exists($this->CI, $rule)){
                    continue;
                }

                $is_valid = $this->CI->$rule($data, $param);

                //如果不要求并验证结果为真,不进行其他规则的验证
                if ( ! in_array('required', $rules, TRUE) AND $is_valid !== FALSE)
                {
                    continue;
                }                
            }
            else{
                //如果验证类中不包含该验证方法,尝试php内置方法
                if (!method_exists($this, $rule)) {

                    if (function_exists($rule)) {
                        $is_valid = $rule($data);
                    }
                    else {
                        log_message('error', "找不到对应的验证方法:".$rule);
                    }

                    continue;
                }
                
                $is_valid = $this->$rule($data, $param);            
            }

            //如果验证不通过,记录错误
            if ($is_valid === FALSE) {
                if (isset($this->_error_messages[$rule])) {
                    log_message('error', $field.$cycles.'验证'.$rule.'不通过');
                }
                return $is_valid;
            }

        }

        return TRUE;
    }

    public function run($data)
    {
        //如果没有设置验证规则
        if (count($this->_field_data) == 0) {
            //检查是否设置默认验证规则配置文件
            //TODO
        }

        foreach ($this->_field_data as $field => $row) {

            //根据field的名字是数组或者字符串,决定我们从哪里获取它的值
            if ($row['is_array'] == TRUE) {
                $row['data'] = $this->_reduce_array($data, $row['keys']);//获取多维数组的值
            }
            else {
                if (isset($data[$field]) AND $data[$field] != ''){
                    $row['data'] = $data[$field];
                }
            }

            //执行验证
            if (!$this->_execute($row)){
                return FALSE;
            }
        }

        return TRUE;
    }

    public function required($str)
    {
        log_message('error',$str);
        if (!is_array($str)) {
            return (trim($str) == '') ? FALSE : TRUE;
        }
        else {
            return (!empty($str));
        }
    }

    /**
     * Performs a Regular Expression match test.
     *
     * @access    public
     * @param    string
     * @param    regex
     * @return    bool
     */
    public function regex_match($str, $regex)
    {
        if ( ! preg_match($regex, $str))
        {
            return FALSE;
        }

        return  TRUE;
    }
    
    // --------------------------------------------------------------------

    /**
     * Match one field to another
     *
     * @access    public
     * @param    string
     * @param    field
     * @return    bool
     */
    public function is_unique($str, $field)
    {
        list($table, $field)=explode('.', $field);
        $query = $this->CI->db->limit(1)->get_where($table, array($field => $str));
        
        return $query->num_rows() === 0;
    }

    // --------------------------------------------------------------------

    /**
     * Minimum Length
     *
     * @access    public
     * @param    string
     * @param    value
     * @return    bool
     */
    public function min_length($str, $val)
    {
        if (preg_match("/[^0-9]/", $val))
        {
            return FALSE;
        }

        if (function_exists('mb_strlen'))
        {
            return (mb_strlen($str) < $val) ? FALSE : TRUE;
        }

        return (strlen($str) < $val) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Max Length
     *
     * @access    public
     * @param    string
     * @param    value
     * @return    bool
     */
    public function max_length($str, $val)
    {
        if (preg_match("/[^0-9]/", $val))
        {
            return FALSE;
        }

        if (function_exists('mb_strlen'))
        {
            return (mb_strlen($str) > $val) ? FALSE : TRUE;
        }

        return (strlen($str) > $val) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Exact Length
     *
     * @access    public
     * @param    string
     * @param    value
     * @return    bool
     */
    public function exact_length($str, $val)
    {
        if (preg_match("/[^0-9]/", $val))
        {
            return FALSE;
        }

        if (function_exists('mb_strlen'))
        {
            return (mb_strlen($str) != $val) ? FALSE : TRUE;
        }

        return (strlen($str) != $val) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Valid Email
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function valid_email($str)
    {
        return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Valid Emails
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function valid_emails($str)
    {
        if (strpos($str, ',') === FALSE)
        {
            return $this->valid_email(trim($str));
        }

        foreach (explode(',', $str) as $email)
        {
            if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE)
            {
                return FALSE;
            }
        }

        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Validate IP Address
     *
     * @access    public
     * @param    string
     * @param    string "ipv4" or "ipv6" to validate a specific ip format
     * @return    string
     */
    public function valid_ip($ip, $which = '')
    {
        return $this->CI->input->valid_ip($ip, $which);
    }

    // --------------------------------------------------------------------

    /**
     * Alpha
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function alpha($str)
    {
        return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Alpha-numeric
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function alpha_numeric($str)
    {
        return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Alpha-numeric with underscores and dashes
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function alpha_dash($str)
    {
        return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Numeric
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function numeric($str)
    {
        return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str);

    }

    // --------------------------------------------------------------------

    /**
     * Is Numeric
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function is_numeric($str)
    {
        return ( ! is_numeric($str)) ? FALSE : TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Integer
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function integer($str)
    {
        return (bool) preg_match('/^[\-+]?[0-9]+$/', $str);
    }

    // --------------------------------------------------------------------

    /**
     * Decimal number
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function decimal($str)
    {
        return (bool) preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str);
    }

    // --------------------------------------------------------------------

    /**
     * Greather than
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function greater_than($str, $min)
    {
        if ( ! is_numeric($str))
        {
            return FALSE;
        }
        return $str > $min;
    }

    // --------------------------------------------------------------------

    /**
     * Less than
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function less_than($str, $max)
    {
        if ( ! is_numeric($str))
        {
            return FALSE;
        }
        return $str < $max;
    }

    // --------------------------------------------------------------------

    /**
     * Is a Natural number  (0,1,2,3, etc.)
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function is_natural($str)
    {
        return (bool) preg_match( '/^[0-9]+$/', $str);
    }

    // --------------------------------------------------------------------

    /**
     * Is a Natural number, but not a zero  (1,2,3, etc.)
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function is_natural_no_zero($str)
    {
        if ( ! preg_match( '/^[0-9]+$/', $str))
        {
            return FALSE;
        }

        if ($str == 0)
        {
            return FALSE;
        }

        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Valid Base64
     *
     * Tests a string for characters outside of the Base64 alphabet
     * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045
     *
     * @access    public
     * @param    string
     * @return    bool
     */
    public function valid_base64($str)
    {
        return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str);
    }
}

因为我只支持前台能运行js的用户,只是防止非法人跨过浏览器直接访问

所以,我的验证类阉割了原来显示验证错误的功能,一旦有一个验证不通过,记录日志并直接退出!简单粗暴 哈哈

另外,该类还有没有完善的地方,复选框部分代码,和读取配置文件设置默认验证规则的代码,回调函数只能限制在控制器的问题,待完善

2.加入自动加载中

3.配置使用 在控制器中加入如下代码,

//验证$input
$rules = array(
    array('field' => 'name','rules' => array('required', 'callback_test'))
);
if (!$this->validation->set_rules($rules)->run($input)){
    exit('请检查是否javascript不生效了!');
}
posted @ 2015-01-19 18:23  yo胡yo  阅读(652)  评论(0编辑  收藏  举报