123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- <?php
- /**
- * [WeEngine System] Copyright (c) 2014 WE7.CC
- * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
- */
- class Validator {
- const IMG = 'jpg, jepg, png, gif, bmp'; const IMG_MIMETYPE = 'image/jpeg,image/jpeg,image/png,image/gif,image/bmp';
- private $defaults = array(
- 'required' => ':attribute 必须填写',
- 'integer' => ':attribute必须是整数',
- 'int' => ':attribute必须是整数',
- 'numeric' => ':attribute必须是数字',
- 'string' => ':attribute必须是字符串',
- 'json' => ':attribute 必须是json',
- 'array' => ':attribute必须是数组',
- 'min' => ':attribute不能小于%s',
- 'max' => ':attribute不能大于%s',
- 'between' => ':attribute 必须在 %s %s 范围内',
- 'size' => ':attribute 大小必须是 %s',
- 'url' => ':attribute不是有效的url', 'email' => ':attribute不是有效的邮箱',
- 'mobile' => ':attribute不是有效的手机号',
- 'file' => ':attribute必须是一个文件',
- 'image' => ':attribute必须是一个图片',
- 'ip' => ':attribute不是有效的ip',
- 'in' => ':attribute 必须在 %s 内',
- 'notin' => ':attribute 不在 %s 内',
- 'date' => ':attribute 必须是有效的日期',
- 'after' => ':attribute 日期不能小于 %s',
- 'before' => ':attribute 日期不能大于 %s',
- 'regex' => ':attribute 不是有效的数据', 'same' => ':attribute 和 %s 不一致', 'bool' => ':attribute 必须是bool值',
- 'path' => ':attribute 不是有效的路径'
- );
-
- private $custom = array();
-
- private $rules = array();
-
- private $messages = array();
-
- private $data = array();
-
- private $errors = array();
- public function __construct($data, $rules = array(), $messages = array()) {
- $this->data = $data;
- $this->rules = $this->parseRule($rules);
- $this->messages = $messages;
- }
- public static function create($data, $rules, array $messages = array()) {
- return new self($data, $rules, $messages);
- }
-
- public function addRule($name, callable $callable) {
- if (!$name) {
- throw new InvalidArgumentException('无效的参数');
- }
- if (!is_callable($callable)) {
- throw new InvalidArgumentException('无效的callable 对象');
- }
- $this->custom[$name] = $callable;
- }
-
- public function isError() {
- return count($this->errors) !== 0;
- }
-
- public function error() {
- return $this->errors;
- }
-
- public function message() {
- $init = array();
- $errmsg = array_reduce($this->error(), function($result, $value){
- return array_merge($result, array_values($value));
- }, $init);
- return implode(',' , array_values($errmsg));
- }
- public function getData() {
- return $this->data;
- }
-
- protected function parseRule(array $rules) {
- $result = array();
- if (count($rules) == 0) {
- throw new InvalidArgumentException('无效的rules');
- }
- foreach ($rules as $key => $rule) {
- $result[$key] = $this->parseSingleRule($rule);
- }
- return $result;
- }
-
- protected function parseSingleRule($value) {
- if (is_string($value)) {
- $rules = explode('|', $value);
- $result = array();
- foreach ($rules as $dataKey => $rule) {
- $kv = explode(':', $rule);
- $params = array();
- if (count($kv) > 1) {
- $params = explode(',', $kv[1]);
- }
- $result[] = array('name' => $kv[0], 'params' => $params);
- }
- return $result;
- }
- if (is_array($value)) {
- $value = array_map(function($item) {
- if(is_string($item)) {
- $name_params = explode(':', $item);
- $params = array();
- if (count($name_params) > 1) {
- $params = explode(',', $name_params[1]);
- }
- return array('name'=>$name_params[0], 'params'=>$params);
- }
- if (!is_array($item)) {
- throw new InvalidArgumentException('无效的rule参数');
- }
- $newitem = $item;
- if (! isset($item['name'])) {
- $newitem = array();
- $newitem['name'] = $newitem[0];
- $newitem['params'] = count($item) > 1 ? $item[1] : array();
- }
- return $newitem;
- }, $value);
- return $value;
- }
- throw new InvalidArgumentException('无效的rule配置项');
- }
- private function getRules($key) {
- return isset($this->rules[$key]) ? $this->rules[$key] : array();
- }
- public function valid() {
- $this->errors = array();
- foreach ($this->data as $key => $value) {
- $rules = $this->getRules($key);
- foreach ($rules as $rule) {
- $this->doValid($key, $value, $rule);
- }
- }
- return $this->isError() ? error(1, $this->message()) : error(0);
- }
-
- private function doSingle($callback, $dataKey, $value, $rule) {
- $valid = call_user_func($callback, $dataKey, $value, $rule['params']);
- if (!$valid) {
- $this->errors[$dataKey][$rule['name']] = $this->getMessage($dataKey, $rule);
- return false;
- }
- return true;
- }
-
- private function doCustom($callback, $dataKey, $value, $rule) {
- $valid = call_user_func($callback, $dataKey, $value, $rule['params'], $this);
- if (!$valid) {
- $this->errors[$dataKey][$rule['name']] = $this->getMessage($dataKey, $rule);
- return false;
- }
- return true;
- }
-
- private function doValid($dataKey, $value, $rule) {
- $ruleName = $rule['name'];
- if (isset($this->defaults[$ruleName])) {
- $callback = array($this, 'valid' . ucfirst($ruleName));
- return $this->doSingle($callback, $dataKey, $value, $rule);
- }
- if (isset($this->custom[$ruleName])) {
- $callback = $this->custom[$ruleName];
- return $this->doCustom($callback, $dataKey, $value, $rule, $this);
- }
- throw new InvalidArgumentException('valid' . $rule['name'] . ' 方法未定义');
- }
-
- private function getValue($key) {
- return isset($this->data[$key]) ? $this->data[$key] : null;
- }
- protected function getMessage($dataKey, $rule) {
- $message = $this->getErrorMessage($dataKey, $rule['name']);
- if ($message) {
- $message = str_replace(':attribute', $dataKey, $message);
- $message = vsprintf($message, $rule['params']); }
- return $message;
- }
- protected function getErrorMessage($dataKey, $ruleName) {
- $dr = $dataKey . '.' . $ruleName;
- if ($this->messages[$dr]) {
- return $this->messages[$dr];
- }
- if (isset($this->messages[$dataKey])) {
- return $this->messages[$dataKey];
- }
- return isset($this->defaults[$ruleName]) ? $this->defaults[$ruleName] : '错误';
- }
-
- public function validRequired($key, $value, $params) {
- if (is_null($value)) {
- return false;
- }
- if (is_array($value)) {
- return count($value) != 0;
- }
- if (is_string($value)) {
- return $value !== '';
- }
- return true;
- }
- public function validInteger($key, $value, $params) {
- return filter_var($value, FILTER_VALIDATE_INT) !== false;
- }
- public function validInt($key, $value, $params) {
- return $this->validInteger($key, $value, $params);
- }
- public function validNumeric($key, $value, $params) {
- return is_numeric($value);
- }
- public function validString($key, $value, $params) {
- return is_string($value);
- }
- public function validJson($key, $value, $params) {
- if (!is_scalar($value) && !method_exists($value, '__toString')) {
- return false;
- }
- json_decode($value);
- return json_last_error() === JSON_ERROR_NONE;
- }
-
- public function validArray($key, $value, $params) {
- return is_array($value);
- }
-
- public function validFile($key, $value, $params) {
- return is_file($value);
- }
- public function validImage($key, $value, $params) {
- return $this->isImage($value);
- }
- public function validEmail($key, $value, $params) {
- return filter_var($value, FILTER_VALIDATE_EMAIL);
- }
- public function validMobile($key, $value, $params) {
- return $this->validRegex($key, $value, array('/^1[34578]\d{9}$/'));
- }
-
- public function validRegex($key, $value, $params) {
- $this->checkParams(1, $params, 'regex');
- return preg_match($params[0], $value);
- }
-
- public function validIp($key, $value, $params) {
- if (!is_null($value)) {
- return filter_var($value, FILTER_VALIDATE_IP);
- }
- return false;
- }
-
- public function validSize($key, $value, $params) {
- $this->checkParams(1, $params, 'size');
- return $this->getSize($key, $value) == $params[0];
- }
-
- public function validMax($key, $value, $params) {
- $this->checkParams(1, $params, 'max');
- $size = $this->getSize($key, $value);
- return $size <= $params[0];
- }
-
- public function validMin($key, $value, $params) {
- $this->checkParams(1, $params, 'min');
- $size = $this->getSize($key, $value);
- return $size >= $params[0];
- }
- public function validUrl($key, $value, $params) {
- if (!filter_var($value, FILTER_VALIDATE_URL)) {
- return false;
- }
-
- $parseData = parse_url($value);
- $scheme = $parseData['scheme'];
- $allowSchemes = array('http', 'https');
- if (!in_array($scheme, $allowSchemes)) { return false;
- }
- if (!isset($parseData['host'])) {
- return false;
- }
- $host = $parseData['host'];
- if (strexists($host, '@')) {
- return false;
- }
- $pattern = '/^(10|172|192|127)/'; if (preg_match($pattern, $host)) {
- return false;
- }
- return parse_path($value);
- }
- public function validDate($key, $value, $params) {
- return $this->checkDate($value);
- }
- public function validIn($key, $value, $params) {
- if (is_array($params)) {
- return in_array($value, $params, true);
- }
- return false;
- }
- public function validNotin($key, $value, $params) {
- return !$this->validIn($key, $value, $params);
- }
-
- public function validSame($key, $value, $params) {
- $this->checkParams(1, $params, 'same');
- $otherField = $params[0];
- $otherValue = isset($this->data[$otherField]) ? $this->data[$otherField] : null;
- return (is_string($value) || is_numeric($value)) && $value === $otherValue;
- }
- public function validBetween($key, $value, $params) {
- $this->checkParams(2, $params, 'between');
- $size = $this->getSize($key, $value);
- return $size >= $params[0] && $size <= $params[1];
- }
-
- public function validAfter($key, $value, $params) {
- $this->checkParams(1, $params, 'afterdate');
- $date = $params[0]; return $this->compareDate($value, $date, '>');
- }
-
- public function validBefore($key, $value, $params) {
- $this->checkParams(1, $params, 'beforedate');
- $date = $params[0]; return $this->compareDate($value, $date, '<');
- }
- private function compareDate($value, $param, $operator = '=') {
- if (!$this->checkDate($param)) {
- $param = $this->getValue($param);
- }
- if ($this->checkDate($value) && $this->checkDate($param)) {
- $currentTime = $this->getDateTimestamp($value);
- $paramTime = $this->getDateTimestamp($param);
- return $this->compare($currentTime, $paramTime, $operator);
- }
- return false;
- }
-
- public function validBool($key, $value, $params) {
- $acceptable = array(true, false, 0, 1, '0', '1');
- return in_array($value, $acceptable, true);
- }
-
- public function validPath($key, $value, $params) {
- return parse_path($value);
- }
- protected function getSize($key, $value) {
- if (is_numeric($value)) {
- return $value;
- } elseif (is_array($value)) {
- return count($value);
- } elseif (is_file($value)) {
- return filesize($value) / 1024;
- } elseif ($value instanceof SplFileInfo) {
- return $value->getSize() / 1024;
- } elseif (is_string($value)) {
- return mb_strlen($value);
- }
- return false;
- }
- private function isImage($value) {
- if (is_file($value)) {
- $filename = $value;
- if ($value instanceof SplFileInfo) {
- $filename = $value->getFilename();
- }
- if (is_string($filename)) {
- $pathinfo = pathinfo($filename);
- $extension = strtolower($pathinfo['extension']);
- return !empty($extension) && in_array($extension, array('jpg', 'jpeg', 'gif', 'png'));
- }
- }
- return false;
- }
- private function mimeTypeIsImage($mimeType) {
- $imgMimeType = explode(',', static::IMG_MIMETYPE);
- return in_array($mimeType, $imgMimeType);
- }
-
- private function checkDate($value) {
- if ($value instanceof DateTimeInterface) {
- return true;
- }
- if ((!is_string($value) && !is_numeric($value)) || strtotime($value) === false) {
- return false;
- }
- $date = date_parse($value);
- return checkdate($date['month'], $date['day'], $date['year']);
- }
- private function checkParams($count, $params, $ruleName) {
- if (count($params) != $count) {
- throw new InvalidArgumentException("$ruleName 参数个数必须为 $count 个");
- }
- }
- private function getDateTimestamp($date) {
- return $date instanceof DateTimeInterface ? $date->getTimestamp() : strtotime($date);
- }
-
- protected function compare($first, $second, $operator) {
- switch ($operator) {
- case '<':
- return $first < $second;
- case '>':
- return $first > $second;
- case '<=':
- return $first <= $second;
- case '>=':
- return $first >= $second;
- case '=':
- return $first == $second;
- default:
- throw new InvalidArgumentException();
- }
- }
- }
|