• 0
  • 0

表单规则校验函数

2021-11-03 700 0 admin 所属分类:PHP 记录

大多数时候提交表单都是手写业务代码,大部分都是字段名不一样,但是校验逻辑是一样的,因此 仿校验器抽离出规则进行校验

/**
 * 校验表单字段 是否符合既定规则
 * @param $data  表单数组
 * @param array $rules 请求规则 格式为 '表单字段' => '规则信息1|规则信息2'
 *          规则信息约定 多个规则用 |号隔开 每一个规则如有 详细约束 参数可以补充在 : 后面
 *          必填项  + 限定数字  'name' => 'require|number'
 *          必填项  + 限定数字 (10-25) 之间  'name' => 'require|number|between:10,25'
 *          必填项  + 限定数字 + 最大不超过50  'age' => 'require|number|max:50'
 *          必填项  + 限定数字 + 不小于18  'age' => 'require|number|min:18'
 *          必填项  + 限定坐标  'pos' => 'require|position'
 *          邮箱  'qqemail' => 'email'
 *          tel 座机  'call' => 'tel'
 *          mobile 手机  'call' => 'mobile'
 *          phone 手机+座机  'call' => 'phone'
 *    !!!   depend 依赖项检测  'name' => '其他表单名1,其他表单名2'  不支持检测 数组变量+非数组变量的情况
 * @param array $messages 错误提示内容 不传 则用 表单字段名.规则 报错
 */
function validateParams(&$data, $rules = [], $messages = [])
{
    foreach ($data as $k => $v) {
        if (!isset($rules[$k])) {
            continue;
        }
        // 校验必须
        $require = function ($param) use ($k, $messages) {
            $mk = "{$k}.require";
            if (is_array($param)) {
                foreach ($param as $p) {
                    if ($p == null || $p == '') {
                        fail($messages[$mk] ?? $mk);
                    }
                }
            } else {
                if ($param == null || $param == '') {
                    fail($messages[$mk] ?? $mk);
                }
            }
        };
        // 校验长度最值
        $maxOrMin = function ($param, $length, $kind = 'max') use ($k, $messages) {
            $mk = "{$k}.{$kind}";
            if ($kind == 'max' && strlen($param) > $length) {
                fail($messages[$mk] ?? $mk . ' length > ' . $length);
            } else if ($kind == 'min' && strlen($param) < $length) {
                fail($messages[$mk] ?? $mk . ' length < ' . $length);
            }
        };
        // 校验数值判断
        $checkNumber = function ($param, $length) use ($k, $messages) {
            $mk = "{$k}.number";
            if (is_array($param)) {
                foreach ($param as $p) {
                    if (is_numeric($p)) {
                        fail($messages[$mk] ?? $mk);
                    }
                }
            } else {
                if (is_numeric($param)) {
                    fail($messages[$mk] ?? $mk);
                }
            }
        };
        // 校验区间
        $checkBetween = function ($param, $range) use ($k, $messages) {
            $mk = "{$k}.between";
            sort($range, SORT_NUMERIC);
            if (is_array($param)) {
                foreach ($param as $p) {
                    if ($p < $range[0] || $p > $range[1]) {
                        fail($messages[$mk] ?? $mk);
                    }
                }
            } else {
                if ($param < $range[0] || $param > $range[1]) {
                    fail($messages[$mk] ?? $mk);
                }
            }
        };
        // 邮箱验证
        $checkEmail = function ($param) use ($k, $messages) {
            $mk = "{$k}.email";
            if (!is_string($param) || !preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/", $param, $matches)) {
                fail($messages[$mk] ?? $mk);
            }
        };
        // 号码验证 支持手机号码和座机
        $checkPhone = function ($param) use ($k, $messages) {
            $mk = "{$k}.phone";
            if (!preg_match("/^1(\d{10})||([0-9]{3,4}-)?[0-9]{7,8}$/", $param, $matches)) {
                fail($messages[$mk] ?? $mk);
            }
        };
        // 只检查手机号码
        $checkMobile = function ($param) use ($k, $messages) {
            $mk = "{$k}.mobile";
            if (!preg_match("/^1(\d{10})$/", $param, $matches)) {
                fail($messages[$mk] ?? $mk);
            }
        };
        // 只检查座机
        $checkTel = function ($param) use ($k, $messages) {
            $mk = "{$k}.tel";
            if (!preg_match("/^([0-9]{3,4}-)?[0-9]{7,8}$/", $param, $matches)) {
                fail($messages[$mk] ?? $mk);
            }
        };
        // 检查是否是经纬度坐标
        $checkPosition = function ($param) use ($k, $messages) {
            $mk = "{$k}.position";
            if (is_array($param)) {
                foreach ($param as $p) {
                    if (!verifyPosition($p)) {
                        fail($messages[$mk] ?? $mk);
                    }
                }
            } else {
                if (!verifyPosition($param)) {
                    fail($messages[$mk] ?? $mk);
                }
            }
        };
        //检测依赖项 用于判断某个变量存在的前提是另外一个变量存在  如果同时都不存在都 unset 掉  如果其中一个存在而有一个不存在 就返回报错
        $checkDepend = function ($depends) use ($k, $messages, &$data) {
            $mk = "{$k}.depend";
            $depends[] = $k;
            if (is_array($data[$k])) {
                // 如果是数组 检测数组每一个相同序号的元素是否对的上
                // 存储每一个二维数组的元素长度
                $lengths = [];
                foreach ($depends as $depend) {
                    $lengths[] = count($data[$depend]);
                }
                if (count(array_unique($lengths)) > 1) {
                    // 存在不同长度的二维元素 报错
                    fail("{$k} 依赖项列表元素无法一一对应");
                }
                foreach ($data[$k] as $kk => $vv) {
                    $all_exists = true;
                    $all_empty = true;
                    foreach ($depends as $depend) {
                        if (!isset($data[$depend][$kk]) || !$data[$depend][$kk]) {
                            $all_exists = false;
                            continue;
                        }
                        if ($data[$depend][$kk]) {
                            $all_empty = false;
                        }
                    }
                    if (!$all_exists && !$all_empty) {
                        // 部分存在 报错
                        fail($messages[$mk] ?? $mk . ' has error');
                    }
                    if ($all_empty) {
                        // 所有数字都为空  unset
                        foreach ($depends as $depend) {
                            unset($data[$depend][$kk]);
                        }
                        foreach ($depends as $depend) {
                            $data[$depend] = array_values($data[$depend]);
                        }
                    }
                }
            } else {
                $all_exists = true;
                $all_empty = true;
                foreach ($depends as $depend) {
                    if (!isset($data[$depend]) || !$data[$depend]) {
                        $all_exists = false;
                        continue;
                    }
                    if ($data[$depend]) {
                        $all_empty = false;
                    }
                }
                if (!$all_exists && !$all_empty) {
                    // 部分存在 报错
                    fail($messages[$mk] ?? $mk . ' has error');
                }
                if ($all_empty) {
                    // 所有数字都为空  unset
                    foreach ($depends as $depend) {
                        unset($data[$depend]);
                    }
                }
            }
        };
        $limits = is_array($rules[$k]['limit']) ?: explode("|", $rules[$k]['limit']);
        // 变量限定检测
        foreach ($limits as $kk => $limit) {
            list($limit, $param) = explode(":", $limit);
            switch ($limit) {
                case 'require':
                    $require($v);
                    break;
                case 'max':
                case 'min':
                    $maxOrMin($v, $param, $limit);
                    break;
                case 'number':
                    $checkNumber($v);
                    break;
                case 'between':
                    if (strpos($param, ",") === false) {
                        fail("校验 between 规则 限定参数有误");
                    }
                    $checkBetween($v, explode(",", $param));
                    break;
                case 'email':
                    $checkEmail($v);
                    break;
                case 'phone':
                    $checkPhone($v);
                    break;
                case 'mobile':
                    $checkMobile($v);
                    break;
                case 'tel':
                    $checkTel($v);
                    break;
                case 'postion':
                    $checkPosition($v);
                    break;
                case 'depend':
                    $checkDepend(explode(",", $param));
            }
        }
    }
}


比较特殊的是 depend 的情况,有些情况下我需要保证另外几个变量同时存在 才可以提交 ,这种情况就存在依赖关系


$rules = [
    'run_default_address_pos' => ['limit' => 'require|postion|depend:run_default_address_name']
];
$messages = [
    'run_default_address_pos.depend'  => '地址或坐标不能为空',
    'run_default_address_pos.require' => '坐标必填'
];
validateParams($_POST, $rules, $messages);


返回顶部