├── .gitignore ├── composer.json ├── README.md ├── LICENSE └── src └── Validate.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | /vendor/ 3 | 4 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 5 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 6 | # composer.lock 7 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xiangshouding/ep-validate", 3 | "description": "Another validate tool", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "xiangshouding", 9 | "email": "fansekey@gmail.com" 10 | } 11 | ], 12 | "autoload": { 13 | "classmap": [ 14 | "src" 15 | ] 16 | }, 17 | "minimum-stability": "stable", 18 | "require": {} 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ep-validate 2 | Another validate tool 3 | 4 | 5 | ## 说明 6 | 7 | 校验参数可能是遇到最多的问题,特别是在导入数据的时候。一个定义清晰的校验工具就不可获取了。 8 | 9 | 宏观的去考察一下,有个 json schema 的项目特别令人愉悦,但奈何类库代码颇多,有时候校验并不需要引入如此庞大的一套体系。 10 | 11 | 在纠结了几天后,决定还是简单来一个吧,自己用着比较舒服,遂放到这块。 12 | 13 | 14 | ## 安装 15 | 16 | ``` 17 | composer install xiangshouding/ep-validate 18 | ``` 19 | 20 | ## 使用 21 | 22 | ```php 23 | 24 | $data = array( 25 | 'name' => 'bozlll', 26 | 'age' => 27, 27 | 'gender' => 'm', 28 | 'ext' => array( 29 | 'school' => 'HIT', 30 | 'class' => 4 31 | ) 32 | ); 33 | 34 | $rules = array( 35 | 'name' => 'required|string|max:30', 36 | 'age' => 'required|int', 37 | 'gender' => 'required|enum:m,f', 38 | 'ext' => '$ref:ext', 39 | '$define' => array( 40 | 'ext' => array( 41 | 'school' => 'string', 42 | 'class' => 'string' 43 | ) 44 | ), 45 | ); 46 | 47 | $validate = new Ep_Validate($data, $rules); 48 | 49 | if (!$validate->ok()) { 50 | throw new Exception($validate->getValidateError()); 51 | } 52 | 53 | ... 54 | 55 | ``` 56 | 57 | ## 检验规则 58 | 59 | ... 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 fansekey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Validate.php: -------------------------------------------------------------------------------- 1 | '三傻', 54 | * 'age' => 200 55 | * ] 56 | * 57 | * @var array 58 | */ 59 | protected $input = array(); 60 | 61 | /** 62 | * 用户输入的校验规则 63 | * 64 | * [ 65 | * 'key' => 'require|json' 66 | * ] 67 | * 68 | * @var array 69 | */ 70 | protected $config = array(); 71 | 72 | /** 73 | * 74 | * Ep_Validate constructor. 75 | * 76 | * @param array $input 77 | * @param array $config 78 | * @param array $refDefined 79 | */ 80 | public function __construct(array $input, array $config = [], array $refDefined = array()) 81 | { 82 | $this->input = $input; 83 | $this->config = $config; 84 | 85 | foreach ($this->builtin as $rule) 86 | { 87 | $this->rules[$rule] = call_user_func( 88 | array($this, $this->getRuleName($rule)) 89 | ); 90 | } 91 | 92 | $this->setRefDefined($refDefined); 93 | } 94 | 95 | /** 96 | * 调用诸多 check 逻辑进行 check. 97 | * 98 | * @return bool 99 | */ 100 | public function ok() 101 | { 102 | if (!$this->input) 103 | { 104 | $this->errors[] = 'invalid arguments'; 105 | return false; 106 | } 107 | 108 | $rules = $this->prepare($this->config); 109 | 110 | foreach ((array)$rules as $key => $validates) 111 | { 112 | foreach ($validates as $check => $params) 113 | { 114 | if ($check == 'required') 115 | { 116 | if (! isset($this->input[$key])) 117 | { 118 | $this->errors[] = "$key is required."; 119 | return false; 120 | } 121 | } else 122 | { 123 | if (isset($this->input[$key]) && ! $this->check($this->input[$key], $check, $params)) 124 | { 125 | $this->errors[] = "$key = " . $this->input[$key] . " invalid."; 126 | return false; 127 | } 128 | } 129 | } 130 | } 131 | 132 | return true; 133 | } 134 | 135 | /** 136 | * 获取 Validate 错误信息 137 | * 138 | * @return string 139 | */ 140 | public function getValidateError() 141 | { 142 | return implode("\n ", $this->errors); 143 | } 144 | 145 | /** 146 | * 字符最大不得超过 147 | * 148 | * ['key' => 'string|max: 10'] 149 | * 150 | * @return Closure 151 | */ 152 | public function ruleMax() 153 | { 154 | return function ($value, $max) 155 | { 156 | return strlen($value) <= $max; 157 | }; 158 | } 159 | 160 | /** 161 | * 字符最小限制 162 | * 163 | * ['name' => 'string|min: 10'] 164 | * 165 | * @return Closure 166 | */ 167 | public function ruleMin() 168 | { 169 | return function ($value, $min) 170 | { 171 | return strlen($value) >= $min; 172 | }; 173 | } 174 | 175 | /** 176 | * 提供的必须是一个 json 串 177 | * 178 | * [ 'data' => 'json'] 179 | * 180 | * @return Closure 181 | */ 182 | public function ruleJson() 183 | { 184 | return function ($value) 185 | { 186 | $this->registerRuleErrorMsg('json', $value . ' can\'t json_decode to Array or Object and maybe json_decode result not is a array.'); 187 | 188 | $json = json_decode($value, true); 189 | 190 | if ($json === null || !is_array($json)) 191 | { 192 | return false; 193 | } 194 | 195 | return true; 196 | }; 197 | } 198 | 199 | /** 200 | * 校验提供的 json 解析后是个数字数组 201 | * 202 | * @return Closure 203 | */ 204 | public function ruleJsonArray() 205 | { 206 | return function ($value) 207 | { 208 | $this->registerRuleErrorMsg('json_array', $value . ' can\'t json_decode to Array or maybe it a assoc array.'); 209 | 210 | $json = json_decode($value, true); 211 | 212 | if ($json === null || !is_array($json)) 213 | { 214 | return false; 215 | } 216 | 217 | $keyCombine = join('', array_keys($json)); 218 | 219 | if (!is_numeric($keyCombine)) 220 | { 221 | return false; 222 | } 223 | 224 | return true; 225 | }; 226 | } 227 | 228 | /** 229 | * 校验给定 json 解析后是个 assoc 数组 230 | * 231 | * @return Closure 232 | */ 233 | public function ruleJsonObject() 234 | { 235 | return function ($value) 236 | { 237 | $json = json_decode($value, true); 238 | 239 | if ($json === null || !is_array($json)) 240 | { 241 | return false; 242 | } 243 | 244 | $keyCombine = join('', array_keys($json)); 245 | 246 | if (is_numeric($keyCombine)) 247 | { 248 | return false; 249 | } 250 | 251 | return true; 252 | }; 253 | } 254 | 255 | /** 256 | * 提供必须是字符串 257 | * 258 | * @return Closure 259 | */ 260 | public function ruleString() 261 | { 262 | return function ($value) 263 | { 264 | return is_string($value); 265 | }; 266 | } 267 | 268 | /** 269 | * 提供必须是数字 270 | * 271 | * @return Closure 272 | */ 273 | public function ruleInt() 274 | { 275 | return function ($value) 276 | { 277 | return is_numeric($value); 278 | }; 279 | } 280 | 281 | /** 282 | * 提供常量的检查 283 | * 284 | * @return Closure 285 | */ 286 | public function ruleEnum() 287 | { 288 | return function () 289 | { 290 | if (func_num_args() <= 1) 291 | { 292 | $this->registerRuleErrorMsg('enum', 'can\'t given enum value.'); 293 | 294 | return false; 295 | } 296 | 297 | $arguments = func_get_args(); 298 | $value = array_shift($arguments); 299 | 300 | return in_array($value, $arguments); 301 | }; 302 | } 303 | 304 | /** 305 | * check or get rule name 306 | * 307 | * @param $ruleString 308 | * @return string 309 | */ 310 | protected function getRuleName($ruleString) 311 | { 312 | if (!is_string($ruleString) || !preg_match('@[a-zA-z0-9_]+@', $ruleString)) 313 | { 314 | throw new Exception( 315 | 'Invalid arguments' 316 | ); 317 | } 318 | 319 | $words = explode('_', $ruleString); 320 | 321 | $words = array_map(function ($w) 322 | { 323 | return ucfirst($w); 324 | }, $words); 325 | 326 | return 'rule' . implode('', $words); 327 | } 328 | 329 | 330 | /** 331 | * 对用户的配置进行预处理 332 | * 333 | * @param array $config 334 | * @return bool 335 | */ 336 | protected function prepare(array $config) 337 | { 338 | if (!$config) 339 | { 340 | return []; 341 | } 342 | 343 | $result = []; 344 | 345 | foreach ($config as $key => $option) 346 | { 347 | if ($key === '$define') 348 | { 349 | $this->setRefDefined((array) $option); 350 | continue; 351 | } 352 | 353 | $rules = array(); 354 | foreach (explode('|', $option) as $one) 355 | { 356 | if (($p = strpos($one, ':')) !== false) 357 | { 358 | $rules[substr($one, 0, $p)] = explode(',', substr($one, $p + 1)); 359 | } else 360 | { 361 | $rules[$one] = array(); 362 | } 363 | } 364 | 365 | $result[$key] = $rules; 366 | } 367 | 368 | return $result; 369 | } 370 | 371 | /** 372 | * 调用预设 check 逻辑校验 373 | * 374 | * @param array $value 输入字段的值 375 | * @param array $rule 校验规则 376 | * @param array $params 校验函数的参数 377 | * @return bool|mixed 378 | */ 379 | protected function check($value, $rule, $params = array()) 380 | { 381 | if (!is_array($value)) 382 | { 383 | $value = [$value]; 384 | } 385 | 386 | foreach ($value as $val) 387 | { 388 | // 嵌套校验 389 | if ($rule === '$ref') 390 | { 391 | if (count($params) != 1 || !is_string($params[0])) 392 | { 393 | $this->errors[] = '$ref value must a string.'; 394 | return false; 395 | } 396 | 397 | if (! ($_rules = $this->getRefDefined($params[0]))) { 398 | $this->errors[] = '$ref:' . $params[0] . ' not defined.'; 399 | return false; 400 | } 401 | 402 | if (is_string($val)) 403 | { 404 | $val = json_decode($val, true); 405 | } 406 | 407 | $validate = new self($val, $_rules, $this->getRefDefined()); 408 | 409 | if (!$validate->ok()) 410 | { 411 | $this->errors[] = $validate->getValidateError(); 412 | return false; 413 | } 414 | } 415 | 416 | // 无规则直接通过 417 | if (! isset($this->rules[$rule])) 418 | { 419 | return true; 420 | } 421 | 422 | $check = $this->rules[$rule]; 423 | 424 | array_unshift($params, $val); // 准备 check 函数的参数 425 | 426 | if (! call_user_func_array($check, $params)) 427 | { 428 | $this->errors[] = 'check validate rule `'.$rule.'` failed.' 429 | . isset($this->rulesErrorMsg[$rule]) ? $this->rulesErrorMsg[$rule] : ''; 430 | 431 | return false; 432 | } 433 | } 434 | 435 | return true; 436 | } 437 | 438 | /** 439 | * 注册规则错误信息,提供更优质的错误提醒 440 | * 441 | * @param string $ruleName 442 | * @param string $errorMsg 443 | * @return object 444 | */ 445 | protected function registerRuleErrorMsg($ruleName, $errorMsg) 446 | { 447 | $this->rulesErrorMsg[$ruleName] = $errorMsg; 448 | 449 | return $this; 450 | } 451 | 452 | /** 453 | * set $ref defined. 454 | * 455 | * @param array $refDefined 456 | * @return $this 457 | */ 458 | protected function setRefDefined(array $refDefined) 459 | { 460 | $this->defined = array_merge($this->defined, $refDefined); 461 | 462 | return $this; 463 | } 464 | 465 | /** 466 | * get $ref defined. 467 | * 468 | * @param string $ref 469 | * @return array 470 | */ 471 | protected function getRefDefined($ref = null) 472 | { 473 | if ($ref) 474 | { 475 | return $this->defined[$ref]; 476 | } 477 | return $this->defined; 478 | } 479 | } --------------------------------------------------------------------------------