diff --git a/.gitignore b/.gitignore index 5d947ca..efca283 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,34 @@ -# Build and Release Folders -bin-debug/ -bin-release/ -[Oo]bj/ -[Bb]in/ +# Created by .ignore support plugin (hsz.mobi) +### Yii template +assets/* +!assets/.gitignore +protected/runtime/* +!protected/runtime/.gitignore +protected/data/*.db +themes/classic/views/ -# Other files and folders -.settings/ +### Example user template template +### Example user template -# Executables -*.swf -*.air -*.ipa -*.apk +# IntelliJ project files +.idea +*.iml +out +gen -# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` -# should NOT be excluded as they contain compiler settings and other important -# information for Eclipse / Flash Builder. +composer.lock + +*.log +commands/result +config/setting.php +tests/ +vendor/ +runtime/ + +*.xml +*.lock + +oot +d + +composer.lock diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..02ea215 --- /dev/null +++ b/composer.json @@ -0,0 +1,25 @@ +{ + "name": "game-worker/validator", + "description": "db", + "authors": [ + { + "name": "XiangLin", + "email": "as2252258@163.com" + } + ], + "license": "MIT", + "require": { + "php": ">=8.0", + "ext-json": "*", + "ext-pdo": "*", + "game-worker/snowflake": "dev-master" + }, + "autoload": { + "psr-4": { + "validator\\": "src/" + } + }, + "require-dev": { + "kwn/php-rdkafka-stubs": "^2.0" + } +} diff --git a/src/ArrayValidator.php b/src/ArrayValidator.php new file mode 100644 index 0000000..232e1fe --- /dev/null +++ b/src/ArrayValidator.php @@ -0,0 +1,70 @@ +getParams(); + if (empty($param) || !is_array($param)) { + return true; + } + if (!isset($param[$this->field])) { + return true; + } + if (!is_array($param[$this->field])) { + return $this->addError("The param :attribute must a array"); + } + return true; + } + + /** + * @param $data + * @return array + * + * 转成数组 + */ + private function toArray($data): array + { + if (is_numeric($data)) { + return []; + } else if (is_null(json_decode($data, true))) { + return []; + } elseif (is_object($data)) { + $data = get_object_vars($data); + } + + $_tmp = []; + foreach ($data as $key => $val) { + if (is_object($val)) { + $_tmp[$key] = $this->toArray($val); + } else if (is_array($val)) { + $_tmp[$key] = $this->toArray($val); + } else { + $_tmp[$key] = $val; + } + } + + return $_tmp; + } + +} diff --git a/src/BaseValidator.php b/src/BaseValidator.php new file mode 100644 index 0000000..3121fa1 --- /dev/null +++ b/src/BaseValidator.php @@ -0,0 +1,134 @@ +model = $model; + } + + /** + * @return ActiveRecord|null + */ + public function getModel(): ?ActiveRecord + { + return $this->model; + } + + + /** + * BaseValidator constructor. + * @param array $config + */ + public function __construct(array $config = []) + { + $this->regConfig($config); + } + + + /** + * @param $config + */ + private function regConfig($config) + { + if (empty($config) || !is_array($config)) { + return; + } + foreach ($config as $key => $val) { + $this->$key = $val; + } + } + + /** + * @throws Exception + * @return bool + */ + public function trigger(): bool + { + throw new Exception('Child Class must define method of trigger'); + } + + /** + * @return array + */ + protected function getParams(): array + { + return $this->params; + } + + /** + * @param array $data + * @return $this + */ + public function setParams(array $data): static + { + $this->params = $data; + return $this; + } + + /** + * @param $message + * @return bool + */ + public function addError($message): bool + { + $this->isFail = FALSE; + + $message = str_replace(':attribute', $this->field, $message); + + $this->message = $message; + + return $this->isFail; + } + + /** + * @return string + */ + public function getError(): string + { + return $this->message; + } + + /** + * @param $name + * @param $value + * @throws Exception + */ + public function __set($name, $value) + { + $method = 'set' . ucfirst($name); + if (method_exists($this, $method)) { + $this->$method($value); + } else if (property_exists($this, $name)) { + $this->$name = $value; + } else { + throw new Exception('unknown property ' . $name . ' in class ' . static::class); + } + } +} diff --git a/src/DateTimeValidator.php b/src/DateTimeValidator.php new file mode 100644 index 0000000..6fe093f --- /dev/null +++ b/src/DateTimeValidator.php @@ -0,0 +1,128 @@ +getParams(); + if (empty($param) || !is_array($param)) { + return true; + } + if (!isset($param[$this->field]) || empty($param[$this->field])) { + return true; + } + $value = $param[$this->field]; + switch (strtolower($this->method)) { + case self::DATE: + return $this->validatorDate($value); + case self::DATE_TIME: + return $this->validateDatetime($value); + case self::TIME: + return $this->validatorTime($value); + case self::STR_TO_TIME: + return $this->validatorTimestamp($value); + default: + return true; + } + } + + /** + * @param $value + * @return bool + * + * 效验分秒 格式如 01:02 or 01-02 + */ + public function validatorTime($value): bool + { + if (empty($value) || !is_string($value)) { + return $this->addError('The param :attribute not is a date value'); + } + $match = preg_match('/^[0-5]?\d{1}.{1}[0-5]?\d{1}$/', $value, $result); + if ($match && $result[0] == $value) { + return true; + } else { + return $this->addError('The param :attribute format error'); + } + } + + + /** + * @param $value + * @return bool + * + * 效验分秒 格式如 2017-12-22 01:02 + */ + public function validateDatetime($value): bool + { + if (empty($value) || !is_string($value)) { + return $this->addError('The param :attribute not is a date value'); + } + $match = '/^\d{4}\-\d{2}\-\d{2}\s+\d{2}:\d{2}:\d{2}$/'; + $match = preg_match($match, $value, $result); + if ($match && $result[0] == $value) { + return true; + } else { + return $this->addError('The param :attribute format error'); + } + } + + /** + * @param $value + * @return bool + * + * 效验分秒 格式如 2017-12-22 + */ + public function validatorDate($value): bool + { + if (empty($value) || !is_string($value)) { + return $this->addError('The param :attribute not is a date value'); + } + $match = preg_match('/^(\d{4}).*([0-12]).*([0-31]).*$/', $value, $result); + if ($match && $result[0] == $value) { + return true; + } else { + return $this->addError('The param :attribute format error'); + } + } + + /** + * @param $value + * @return bool + * + * 效验时间戳 格式如 1521452254 + */ + public function validatorTimestamp($value): bool + { + if (empty($value) || !is_numeric($value)) { + return $this->addError('The param :attribute not is a timestamp value'); + } + if (strlen((string)$value) != 10) { + return $this->addError('The param :attribute not is a timestamp value'); + } + if (!date('YmdHis', $value)) { + return $this->addError('The param :attribute format error'); + } + return true; + } +} diff --git a/src/EmailValidator.php b/src/EmailValidator.php new file mode 100644 index 0000000..6ec3df7 --- /dev/null +++ b/src/EmailValidator.php @@ -0,0 +1,35 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + return true; + } else { + $value = $param[$this->field]; + if (preg_match('/^[a-zA-Z0-9]+([\.\_]{1,})[a-zA-Z0-9]+@[a-zA-Z]+(\.\w+)+/', $value)) { + return true; + } else { + return $this->addError('The param :attribute format error'); + } + } + } + +} diff --git a/src/EmptyValidator.php b/src/EmptyValidator.php new file mode 100644 index 0000000..de861da --- /dev/null +++ b/src/EmptyValidator.php @@ -0,0 +1,55 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + return $this->addError(':attribute not exists'); + } + + $value = $param[$this->field]; + + switch (strtolower($this->method)) { + case self::CAN_NOT_EMPTY: + if (strlen($value) < 1) { + return $this->addError('The :attribute can not empty.'); + } + break; + case self::CAN_NOT_NULL: + if ($value === null) { + return $this->addError('The :attribute can not is null.'); + } + break; + } + + return true; + } +} diff --git a/src/EnumValidator.php b/src/EnumValidator.php new file mode 100644 index 0000000..b3ae820 --- /dev/null +++ b/src/EnumValidator.php @@ -0,0 +1,50 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + return $this->addError('The param :attribute is null'); + } + $value = $param[$this->field]; + if (is_null($value)) { + return $this->addError('The param :attribute is null'); + } + + if (!is_array($this->value)) { + return true; + } + if (!in_array($value, $this->value)) { + return $this->addError($this->i()); + } + + return true; + } + + /** + * @return string + */ + private function i(): string + { + return 'The param :attribute value only in ' . implode(',', $this->value); + } + +} diff --git a/src/IntegerValidator.php b/src/IntegerValidator.php new file mode 100644 index 0000000..4afc8af --- /dev/null +++ b/src/IntegerValidator.php @@ -0,0 +1,45 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + return true; + } + + $value = $param[$this->field] ?? null; + if ($value === null) { + return $this->addError('The :attribute can not is null.'); + } + if ($this->type !== self::MIN && $value < $this->value) { + return $this->addError('The ' . $this->field . ' cannot be less than the default value.'); + } + + if ($this->type !== self::MAX && $value > $this->value) { + return $this->addError('The ' . $this->field . ' cannot be greater than the default value.'); + } + return true; + } +} diff --git a/src/LengthValidator.php b/src/LengthValidator.php new file mode 100644 index 0000000..9b5ef67 --- /dev/null +++ b/src/LengthValidator.php @@ -0,0 +1,115 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + if ($this->method != self::MAX_LENGTH) { + return $this->addError('The param :attribute not exists'); + } else { + return TRUE; + } + } + $value = $param[$this->field]; + if (is_null($value)) { + return $this->addError('The param :attribute is null'); + } + return match (strtolower($this->method)) { + self::MAX_LENGTH => $this->maxLength($value), + self::MIN_LENGTH => $this->minLength($value), + default => $this->defaultLength($value), + }; + } + + /** + * @param $value + * @return bool + * + * 效验长度是否大于最大长度 + */ + private function maxLength($value): bool + { + if (is_array($value)) { + if (count($value) > $value) { + return $this->addError('The param :attribute length overflow'); + } + } else { + if (is_numeric($value) && strlen((string)$value) > $this->value) { + return $this->addError('The param :attribute length overflow'); + } + if (strlen($value) > $this->value) { + return $this->addError('The param :attribute length overflow'); + } + } + return TRUE; + } + + /** + * @param $value + * @return bool + * + * 效验长度是否小于最小长度 + */ + private function minLength($value): bool + { + if (is_array($value)) { + if (count($value) < $value) { + return $this->addError('The param :attribute length error'); + } + } else { + if (is_numeric($value) && strlen((string)$value) < $this->value) { + return $this->addError('The param :attribute length overflow'); + } + if (strlen($value) < $this->value) { + return $this->addError('The param :attribute length error'); + } + } + return TRUE; + } + + /** + * @param $value + * @return bool + * + * 效验长度是否小于最小长度 + */ + private function defaultLength($value): bool + { + if (is_array($value)) { + if (count($value) !== $value) { + return $this->addError('The param :attribute length error'); + } + } else { + if (is_numeric($value) && strlen((string)$value) !== $this->value) { + return $this->addError('The param :attribute length overflow'); + } + if (mb_strlen($value) !== $this->value) { + return $this->addError('The param :attribute length error; ' . mb_strlen($value) . ':' . $this->value); + } + } + return TRUE; + } +} diff --git a/src/RequiredValidator.php b/src/RequiredValidator.php new file mode 100644 index 0000000..decf5ce --- /dev/null +++ b/src/RequiredValidator.php @@ -0,0 +1,33 @@ +getParams(); + if (is_numeric($param)) { + return true; + } + if (empty($param) || !isset($param[$this->field])) { + return $this->addError('The param :attribute not exists'); + } else { + return true; + } + } + +} diff --git a/src/RoundValidator.php b/src/RoundValidator.php new file mode 100644 index 0000000..66fa63f --- /dev/null +++ b/src/RoundValidator.php @@ -0,0 +1,34 @@ +model->getAttribute($this->field); + if ($value == null || round($value, $this->value) != $value) { + return $this->addError('The param :attribute length error'); + } + return true; + } + + +} diff --git a/src/TypesOfValidator.php b/src/TypesOfValidator.php new file mode 100644 index 0000000..4c3586e --- /dev/null +++ b/src/TypesOfValidator.php @@ -0,0 +1,149 @@ + 'json', + self::FLOAT => 'float', + self::ARRAY => 'array', + self::STRING => 'string', + self::INTEGER => 'integer', + self::SERIALIZE => 'serialize', + ]; + + /** @var string */ + public string $method; + + + /** + * @return bool + */ + public function trigger(): bool + { + if (!in_array($this->method, $this->types)) { + return true; + } + + $param = $this->getParams(); + if (empty($param) || !isset($param[$this->field])) { + return true; + } + + $value = $param[$this->field]; + + $method = $this->method . 'Format'; + + if ($value === null) { + return $this->addError('This ' . $this->field . ' is not an empty data.'); + } + + return $this->{$method}($value); + } + + /** + * @param $value + * @return bool + */ + public function jsonFormat($value): bool + { + if (!is_string($value) || is_numeric($value)) { + return $this->addError('The ' . $this->field . ' not is JSON data.'); + } + if (is_null(json_decode($value))) { + return $this->addError('The ' . $this->field . ' not is JSON data.'); + } + return true; + } + + /** + * @param $value + * @return bool + */ + public function serializeFormat($value): bool + { + if (!is_string($value) || is_numeric($value)) { + return $this->addError('The ' . $this->field . ' not is serialize data.'); + } + if (false === swoole_unserialize($value)) { + return $this->addError('The ' . $this->field . ' not is serialize data.'); + } + return true; + } + + /** + * @param $value + * @return bool + */ + public function arrayFormat($value): bool + { + if (!is_array($value)) { + return $this->addError('The ' . $this->field . ' not is array data.'); + } + return true; + } + + /** + * @param $value + * @return bool + */ + public function stringFormat($value): bool + { + if (is_array($value) || is_object($value) || is_bool($value)) { + return $this->addError('The ' . $this->field . ' not is string data.'); + } + return true; + } + + /** + * @param $value + * @return bool + */ + public function integerFormat($value): bool + { + if (!is_numeric($value)) { + return $this->addError('The ' . $this->field . ' not is number data.'); + } + if ((int)$value != $value) { + return $this->addError('The ' . $this->field . ' not is number data.'); + } + + return true; + } + + /** + * @param $value + * @return bool + */ + public function floatFormat($value): bool + { + $trim = (float)$value; + if ($trim != $value || !is_float($trim)) { + return $this->addError('The ' . $this->field . ' not is float data.'); + } + return true; + } + +} diff --git a/src/UniqueValidator.php b/src/UniqueValidator.php new file mode 100644 index 0000000..2e423a3 --- /dev/null +++ b/src/UniqueValidator.php @@ -0,0 +1,43 @@ +getParams(); + if (empty($param) || !isset($param[$this->field])) { + return TRUE; + } + + if (empty($this->model)) { + return $this->addError('Model error.'); + } + + $model = $this->model; + if (!$this->model->getIsCreate()) { + return true; + } + if ($model::find()->where([$this->field => $param[$this->field]])->exists()) { + return $this->addError('The :attribute \'' . $param[$this->field] . '\' is exists!'); + } + return $this->isFail = TRUE; + } + + +} diff --git a/src/Validator.php b/src/Validator.php new file mode 100644 index 0000000..b04c386 --- /dev/null +++ b/src/Validator.php @@ -0,0 +1,221 @@ + [ + 'class' => 'validator\EmptyValidator', + 'method' => EmptyValidator::CAN_NOT_EMPTY, + ], + 'not null' => [ + 'class' => 'validator\EmptyValidator', + 'method' => EmptyValidator::CAN_NOT_NULL, + ], + 'required' => [ + 'class' => 'validator\RequiredValidator', + ], + 'enums' => [ + 'class' => 'validator\EnumValidator', + ], + 'unique' => [ + 'class' => 'validator\UniqueValidator', + ], + 'datetime' => [ + 'class' => 'validator\DatetimeValidator', + 'method' => DateTimeValidator::DATE_TIME, + ], + 'date' => [ + 'class' => 'validator\DatetimeValidator', + 'method' => DateTimeValidator::DATE, + ], + 'time' => [ + 'class' => 'validator\DatetimeValidator', + 'method' => DateTimeValidator::TIME, + ], + 'timestamp' => [ + 'class' => 'validator\DatetimeValidator', + 'method' => DateTimeValidator::STR_TO_TIME, + ], + 'string' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::STRING, + ], + 'int' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::INTEGER, + ], + 'min' => [ + 'class' => IntegerValidator::class + ], + 'max' => [ + 'class' => IntegerValidator::class + ], + 'json' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::JSON, + ], + 'float' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::FLOAT, + ], + 'array' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::ARRAY, + ], + 'serialize' => [ + 'class' => 'validator\TypesOfValidator', + 'method' => TypesOfValidator::SERIALIZE, + ], + 'maxLength' => [ + 'class' => 'validator\LengthValidator', + 'method' => 'max', + ], + 'minLength' => [ + 'class' => 'validator\LengthValidator', + 'method' => 'min', + ], + 'email' => [ + 'class' => 'validator\EmailValidator', + 'method' => 'email', + ], + 'length' => [ + 'class' => 'validator\LengthValidator', + 'method' => 'default', + ], + 'round' => [ + 'class' => 'validator\RoundValidator', + ], + ]; + + /** + * @return Validator|null + */ + public static function getInstance(): ?Validator + { + if (static::$instance == null) { + static::$instance = new Validator(); + } + return static::$instance; + } + + /** + * @param $field + * @param $rules + * @return $this + * @throws Exception + */ + public function make($field, $rules): static + { + if (!is_array($field)) { + $field = [$field]; + } + + $param = $this->getParams(); + $model = $this->getModel(); + foreach ($field as $val) { + $this->createRule($val, $rules, $model, $param); + } + + return $this; + } + + /** + * @param $field + * @param $rule + * @param $model + * @param $param + * @throws Exception + * ['maxLength'=>150, 'required', 'minLength' => 100] + */ + public function createRule($field, $rule, $model, $param) + { + $define = ['field' => $field]; + foreach ($rule as $key => $val) { + + if (!is_null($model)) { + if (is_string($val) && method_exists($model, $val)) { + $this->validators[] = [$model, $val]; + continue; + } + } + + if (is_string($key)) { + $type = strtolower($key); + $define['value'] = $val; + } else { + $type = strtolower($val); + } + + if (!isset($this->classMap[$type])) { + continue; + } + $constr = array_merge($this->classMap[$type], $define); + + /** @var BaseValidator $class */ + $class = Kiri::createObject($constr); + $class->setParams($param); + $class->setModel($model); + + $this->validators[] = $class; + } + } + + /** + * @return bool + * @throws Exception + */ + public function validation(): bool + { + if (count($this->validators) < 1) { + return true; + } + + foreach ($this->validators as $val) { + if ($this->check($val)) { + continue; + } + $isTrue = false; + if ($val instanceof BaseValidator) { + $this->addError($val->getError()); + } + break; + } + $this->validators = null; + $this->validators = []; + return !isset($isTrue); + } + + /** + * @param BaseValidator|array|Closure $val + * @return mixed + * @throws Exception + */ + private function check(BaseValidator|array|Closure $val): mixed + { + if (is_callable($val, true)) { + return call_user_func($val, $this); + } + return $val->trigger(); + } + +}