Laravel的Validator验证ttf字体问题

问题描述

上传ttf后。文件mimes验证没有通过

namespace App\Http\Controllers\Test;


use Illuminate\Http\Request;

class IndexController
{
   public function index(Request $request){
       return view('test.index');
   }

   public function store(Request $request){
      $validator = \validator($request->all(),['file'=>['required','mimes:ttf']],['file.mimes'=>'文件类型不是ttf']);
      if($validator->fails()){
          dd($validator->errors());
      }
   }
}
看源码

vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
通过容器创建了一个validator工厂,通过工厂创建validator
工厂模式

if (! function_exists('validator')) {
    /**
     * Create a new Validator instance.
     *
     * @param  array  $data
     * @param  array  $rules
     * @param  array  $messages
     * @param  array  $customAttributes
     * @return \Illuminate\Contracts\Validation\Validator|\Illuminate\Contracts\Validation\Factory
     */
    function validator(array $data = [], array $rules = [], array $messages = [], array $customAttributes = [])
    {
        //通过容器实例化工厂类
        $factory = app(ValidationFactory::class);

        if (func_num_args() === 0) {
            return $factory;
        }

        //通过工厂创建验证器
        return $factory->make($data, $rules, $messages, $customAttributes);
    }
}

vendor/composer/autoload_classmap.php
这个文件存储了大部分的容器映射关系
通过这个文件我们知道了
validator工厂类 vendor/laravel/framework/src/Illuminate/Validation/Factory.php
validator类 vendor/laravel/framework/src/Illuminate/Validation/Validator.php
接下来直接看 validator类

namespace Illuminate\Validation;

use BadMethodCallException;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ImplicitRule;
use Illuminate\Contracts\Validation\Rule as RuleContract;
use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Support\Arr;
use Illuminate\Support\Fluent;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Str;
use Illuminate\Support\ValidatedInput;
use InvalidArgumentException;
use RuntimeException;
use stdClass;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class Validator implements ValidatorContract
{
    use Concerns\FormatsMessages,
        Concerns\ValidatesAttributes;

    //省略......
        /**
     * Determine if the data passes the validation rules.
     *
     * @return bool
     */
    public function passes()
    {
        $this->messages = new MessageBag;

        [$this->distinctValues, $this->failedRules] = [[], []];

        // We'll spin through each rule, validating the attributes attached to that
        // rule. Any error messages will be added to the containers with each of
        // the other error messages, returning true if we don't have messages.
        foreach ($this->rules as $attribute => $rules) {
            if ($this->shouldBeExcluded($attribute)) {
                $this->removeAttribute($attribute);

                continue;
            }

            if ($this->stopOnFirstFailure && $this->messages->isNotEmpty()) {
                break;
            }

            foreach ($rules as $rule) {

                //主要看这里的属性验证
                $this->validateAttribute($attribute, $rule);

                if ($this->shouldBeExcluded($attribute)) {
                    $this->removeAttribute($attribute);

                    break;
                }

                if ($this->shouldStopValidating($attribute)) {
                    break;
                }
            }
        }

        // Here we will spin through all of the "after" hooks on this validator and
        // fire them off. This gives the callbacks a chance to perform all kinds
        // of other validation that needs to get wrapped up in this operation.
        foreach ($this->after as $after) {
            $after();
        }

        return $this->messages->isEmpty();
    }

    /**
     * Determine if the data fails the validation rules.
     *
     * @return bool
     */
    public function fails()
    {
        return ! $this->passes();
    }

        /**
     * Validate a given attribute against a rule.
     *
     * @param  string  $attribute
     * @param  string  $rule
     * @return void
     */
    protected function validateAttribute($attribute, $rule)
    {
        $this->currentRule = $rule;

        [$rule, $parameters] = ValidationRuleParser::parse($rule);

        if ($rule === '') {
            return;
        }

        // First we will get the correct keys for the given attribute in case the field is nested in
        // an array. Then we determine if the given rule accepts other field names as parameters.
        // If so, we will replace any asterisks found in the parameters with the correct keys.
        if ($this->dependsOnOtherFields($rule)) {
            $parameters = $this->replaceDotInParameters($parameters);

            if ($keys = $this->getExplicitKeys($attribute)) {
                $parameters = $this->replaceAsterisksInParameters($parameters, $keys);
            }
        }

        $value = $this->getValue($attribute);

        // If the attribute is a file, we will verify that the file upload was actually successful
        // and if it wasn't we will add a failure for the attribute. Files may not successfully
        // upload if they are too large based on PHP's settings so we will bail in this case.
        if ($value instanceof UploadedFile && ! $value->isValid() &&
            $this->hasRule($attribute, array_merge($this->fileRules, $this->implicitRules))
        ) {
            return $this->addFailure($attribute, 'uploaded', []);
        }

        // If we have made it this far we will make sure the attribute is validatable and if it is
        // we will call the validation method with the attribute. If a method returns false the
        // attribute is invalid and we will add a failure message for this failing attribute.
        $validatable = $this->isValidatable($rule, $attribute, $value);

        if ($rule instanceof RuleContract) {
            return $validatable
                    ? $this->validateUsingCustomRule($attribute, $value, $rule)
                    : null;
        }

        //如果验证mimes,调用validateMimes方法,该方法在vendor/laravel/framework/src/Illuminate/Validation/Concerns/ValidatesAttributes.php文件中,是trait
        $method = "validate{$rule}";

        if ($validatable && ! $this->$method($attribute, $value, $parameters, $this)) {
            $this->addFailure($attribute, $rule, $parameters);
        }
    }

    //省略......
}

vendor/laravel/framework/src/Illuminate/Validation/Concerns/ValidatesAttributes.php

namespace Illuminate\Validation\Concerns;

use Countable;
use DateTime;
use DateTimeInterface;
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\DNSCheckValidation;
use Egulias\EmailValidator\Validation\MultipleValidationWithAnd;
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
use Egulias\EmailValidator\Validation\RFCValidation;
use Egulias\EmailValidator\Validation\SpoofCheckValidation;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules\Exists;
use Illuminate\Validation\Rules\Unique;
use Illuminate\Validation\ValidationData;
use InvalidArgumentException;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;

trait ValidatesAttributes
{
        /**
     * Validate the guessed extension of a file upload is in a set of file extensions.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @param  array  $parameters
     * @return bool
     */
    public function validateMimes($attribute, $value, $parameters)
    {
        if (! $this->isValidFileInstance($value)) {
            return false;
        }

        if ($this->shouldBlockPhpUpload($value, $parameters)) {
            return false;
        }

        if (in_array('jpg', $parameters) || in_array('jpeg', $parameters)) {
            $parameters = array_unique(array_merge($parameters, ['jpg', 'jpeg']));
        }

        //文件选择了,且mimes在指定mimes中
        //$value 是 vendor/laravel/framework/src/Illuminate/Http/UploadedFile.php
        return $value->getPath() !== '' && in_array($value->guessExtension(), $parameters);
    }
}

vendor/laravel/framework/src/Illuminate/Http/UploadedFile.php
extend
Symfony\Component\HttpFoundation\File\UploadedFile

Symfony\Component\HttpFoundation\File\UploadedFile
extend
mponent\HttpFoundation\File

看Symfony\Component\HttpFoundation\File

    public function guessExtension()
    {
        if (!class_exists(MimeTypes::class)) {
            throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".');
        }
        //vendor/symfony/mime/MimeTypes.php
        return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null;
    }

看vendor/symfony/mime/MimeTypes.php

    public function getExtensions(string $mimeType): array
    {
        if ($this->extensions) {
            $extensions = $this->extensions[$mimeType] ?? $this->extensions[$lcMimeType = strtolower($mimeType)] ?? null;
        }
        //通过mimetype来判断mime类型
        //self::MAP维护了mime与mimetype的映射关系
        //其中维护类三种对应关系,认为是ttf
        //'font/ttf' => ['ttf'],'pplication/x-font-ttf'>['ttf'],'application/x-font-truetype' => ['ttf']
        //由于没有维护application/font-sfnt,导致认为mime是null,所以mime验证无法通过
        return $extensions ?? self::MAP[$mimeType] ?? self::MAP[$lcMimeType ?? strtolower($mimeType)] ?? [];
    }
解决

namespace App\Http\Controllers\Test;


use Illuminate\Http\Request;

class IndexController
{
   public function index(Request $request){
       return view('test.index');
   }

   public function store(Request $request){
      //不验证mimes,验证mimetypes
      $validator = \validator($request->all(),['file'=>['required','mimetypes:application/font-sfnt,application/x-font-truetype,application/x-font-ttf,font/ttf']],['file.mimetypes'=>'文件类型不是ttf']);
      if($validator->fails()){
          dd($validator->errors());
      }
      dd('ok');
   }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值