| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- <?php
- namespace App\Module\Transfer\Validators;
- use UCore\Validation\ValidatorCore;
- /**
- * 金额验证器
- */
- class AmountValidator extends ValidatorCore
- {
- private string $amount;
- private int $maxDecimalPlaces;
- private string $minAmount;
- private string $maxAmount;
- public function __construct(
- string $amount,
- int $maxDecimalPlaces = 10,
- string $minAmount = '0.0000000001',
- string $maxAmount = '999999999.9999999999'
- ) {
- $this->amount = $amount;
- $this->maxDecimalPlaces = $maxDecimalPlaces;
- $this->minAmount = $minAmount;
- $this->maxAmount = $maxAmount;
- }
- /**
- * 执行验证
- */
- public function validate(): bool
- {
- // 验证基本格式
- if (!$this->validateFormat()) {
- return false;
- }
- // 验证数值范围
- if (!$this->validateRange()) {
- return false;
- }
- // 验证小数位数
- if (!$this->validateDecimalPlaces()) {
- return false;
- }
- // 验证特殊值
- if (!$this->validateSpecialValues()) {
- return false;
- }
- return true;
- }
- /**
- * 验证基本格式
- */
- private function validateFormat(): bool
- {
- // 检查是否为空
- if (empty($this->amount)) {
- $this->addError('金额不能为空');
- return false;
- }
- // 检查是否为数字格式
- if (!is_numeric($this->amount)) {
- $this->addError('金额格式无效');
- return false;
- }
- // 检查是否包含非法字符
- if (!preg_match('/^-?\d+(\.\d+)?$/', $this->amount)) {
- $this->addError('金额只能包含数字和小数点');
- return false;
- }
- return true;
- }
- /**
- * 验证数值范围
- */
- private function validateRange(): bool
- {
- // 检查是否为负数
- if (bccomp($this->amount, '0', $this->maxDecimalPlaces) < 0) {
- $this->addError('金额不能为负数');
- return false;
- }
- // 检查最小值
- if (bccomp($this->amount, $this->minAmount, $this->maxDecimalPlaces) < 0) {
- $this->addError("金额不能小于 {$this->minAmount}");
- return false;
- }
- // 检查最大值
- if (bccomp($this->amount, $this->maxAmount, $this->maxDecimalPlaces) > 0) {
- $this->addError("金额不能大于 {$this->maxAmount}");
- return false;
- }
- return true;
- }
- /**
- * 验证小数位数
- */
- private function validateDecimalPlaces(): bool
- {
- // 检查小数位数
- $parts = explode('.', $this->amount);
- if (count($parts) > 2) {
- $this->addError('金额格式无效');
- return false;
- }
- if (count($parts) === 2) {
- $decimalPart = $parts[1];
- if (strlen($decimalPart) > $this->maxDecimalPlaces) {
- $this->addError("金额小数位数不能超过 {$this->maxDecimalPlaces} 位");
- return false;
- }
- // 检查小数部分是否全为0(如果是,建议使用整数格式)
- if (preg_match('/^0+$/', $decimalPart)) {
- // 这不是错误,但可以优化
- }
- }
- return true;
- }
- /**
- * 验证特殊值
- */
- private function validateSpecialValues(): bool
- {
- // 检查是否为0
- if (bccomp($this->amount, '0', $this->maxDecimalPlaces) === 0) {
- $this->addError('金额不能为0');
- return false;
- }
- // 检查是否为无穷大或NaN
- if (!is_finite((float) $this->amount)) {
- $this->addError('金额值无效');
- return false;
- }
- // 检查科学计数法
- if (strpos(strtolower($this->amount), 'e') !== false) {
- $this->addError('金额不支持科学计数法格式');
- return false;
- }
- return true;
- }
- /**
- * 格式化金额
- */
- public function format(): string
- {
- // 移除前导零和尾随零
- $formatted = rtrim(rtrim($this->amount, '0'), '.');
-
- // 如果结果为空,返回0
- if (empty($formatted) || $formatted === '.') {
- return '0';
- }
- return $formatted;
- }
- /**
- * 转换为标准格式
- */
- public function toStandardFormat(): string
- {
- return number_format((float) $this->amount, $this->maxDecimalPlaces, '.', '');
- }
- /**
- * 验证金额是否足够支付手续费
- */
- public function validateWithFee(string $feeAmount): bool
- {
- if (bccomp($this->amount, $feeAmount, $this->maxDecimalPlaces) <= 0) {
- $this->addError("金额必须大于手续费 {$feeAmount}");
- return false;
- }
- return true;
- }
- /**
- * 静态验证方法
- */
- public static function isValid(string $amount, int $maxDecimalPlaces = 10): bool
- {
- $validator = new self($amount, $maxDecimalPlaces);
- return $validator->validate();
- }
- /**
- * 比较两个金额
- */
- public static function compare(string $amount1, string $amount2, int $precision = 10): int
- {
- return bccomp($amount1, $amount2, $precision);
- }
- /**
- * 金额加法
- */
- public static function add(string $amount1, string $amount2, int $precision = 10): string
- {
- return bcadd($amount1, $amount2, $precision);
- }
- /**
- * 金额减法
- */
- public static function subtract(string $amount1, string $amount2, int $precision = 10): string
- {
- return bcsub($amount1, $amount2, $precision);
- }
- /**
- * 金额乘法
- */
- public static function multiply(string $amount, string $multiplier, int $precision = 10): string
- {
- return bcmul($amount, $multiplier, $precision);
- }
- /**
- * 金额除法
- */
- public static function divide(string $amount, string $divisor, int $precision = 10): string
- {
- if (bccomp($divisor, '0', $precision) === 0) {
- throw new \InvalidArgumentException('除数不能为0');
- }
-
- return bcdiv($amount, $divisor, $precision);
- }
- }
|