Laravel 5.3,检查上传文件是否大于upload_max_filesize(可选上传)


Laravel 5.3, check if uploaded file is bigger than upload_max_filesize (optional upload)

在Laravel 5.3中,我试图捕获如果上传的文件具有比upload_max_filesize更大的文件大小。上传字段不需要。

我试过这个方法,但是行不通

public function checkFile($field)
{
    if (request()->hasFile($field)){ // check if field is present
        $file = request()->file($field);
        if (!$file->isValid()){ // now check if it's valid
            return back()->with('error', $file->getErrorMessage());
        }
    }
}

我不能只使用if (!$file->isValid()),因为文件字段是可选的,如果字段为空,我得到Call to a member function isValid() on null

所以我必须检查字段是否使用if (request()->hasFile($field))存在,但这不适用于大文件,因为dd(request()->hasFile('picture'))返回false

当然我可以依赖默认的Laravel Validator消息,但是我得到一个虚拟的The picture failed to upload.,它不给用户任何线索。

Laravel Validation只有在你上传的文件小于php.ini设置的限制时才会起作用。

如果你试图上传一个大于限制的文件,PHP不会将请求转发给Laravel,并且会立即出错。因此,Laravel在这种情况下不能做任何事情。

解决这个问题的一种方法是在php.ini中设置更大的限制,然后在Laravel中验证文件大小。

你应该考虑使用内置的Laravel表单请求验证系统。有一个内置的验证规则,允许您指定max文件大小,您可以查看这里的文档:

https://laravel.com/docs/5.3/validation rule-max

你的规则看起来像这样:

[
    'video' => 'max:256'
]

如果上传的文件大于256kb,此操作将失败。

你提到你不喜欢Laravel内置的验证错误消息。没问题!您可以在resources/lang/en/validation.php语言文件中更改它们,这是您需要更改的行:

https://github.com/laravel/laravel/blob/master/resources/lang/en/validation.php L51

我之前的回答处理了在php.ini中上传的文件大于upload_max_filesize设置的情况。但是当文件的大小使请求大于post_max_size(另一个php.ini设置)时失败。这种情况更难处理,因为输入($_POST全局,如果我们处理纯PHP)被清除。

我认为中间件是做这种"验证"的好地方:

public function handle(Request $request, Closure $next)
{
    $post_max_size = ini_get('post_max_size') * 1024 * 1024;
    $content_length = $request->server('HTTP_CONTENT_LENGTH') ?: $request->server('CONTENT_LENGTH') ?: 0;
    $response = $next($request);
    if ($content_length > $post_max_size)
    {
        return redirect()->back()->with('errors', collect([trans('validation.max.file', ['max' => 2000])]));
    }
    return $response;
}

(如上所述,这不会保留输入)

服务器端代码(In Controller):

下面的函数是meustrus作者在他的堆栈回答中从drupal中提取的,我在这里作为示例。以post_max_size开头

// Returns a file size limit in bytes based on the PHP upload_max_filesize
// and post_max_size
$max_size = parse_size(ini_get('post_max_size'));
// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
$upload_max = parse_size(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
  $max_size = $upload_max;
}
//Get max upload file size limit...
$file_upload_max_size = $max_size;
解析大小的公共函数
public function parse_size($size) {
  $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
  $size = preg_replace('/[^0-9'.]/', '', $size); // Remove the non-numeric characters from the size.
  if ($unit) {
    // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
    return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
  }
  else {
    return round($size);
  }
}

为发送'file_upload_max_size'值设置compact

return view('YOURBLADEPATH',compact('file_upload_max_size'));

JS验证(In Blade):

<script type="text/javascript">
document.forms[0].addEventListener('submit', function( evt ) {
    var file = document.getElementById('file').files[0];
    if(file && file.size < '{$file_upload_max_size}') { // 10 MB (this size is in bytes)
        //Submit form        
    } else {
        //Prevent default and display error
        evt.preventDefault();
    }
}, false);

根据我的经验,我使用JavaScript来验证文件大小。

* JavaScript

function validate_size(elm) {
    var file = elm.files[0];
    var max_size = {{ env('UPLOAD_MAX_FILESIZE', 2097152) }}; // in bytes, e.g. 2 MB = 2097152 Bytes
    var size_name = {{ floor(env('UPLOAD_MAX_FILESIZE', 2097152) / 1024 / 1024) }}; // result: 2
    if (file && file.size < max_size) {
        // CONTINUE
    } else {
        // PREVENT AND DISPLAY ERROR
        alert('File size cannot be greater than ' + size_name + ' MB');
        // RESET INPUT FILE VALUE
        elm.value = '';
    }
}

* HTML/Laravel叶片

...
<input type="file" name="photo" onchange="validate_size(this)">
...

然后,如果用户选择的文件大小大于允许的大小,它将提醒用户。

Laravel文件验证器的默认行为是,无论出于何种原因,如果上传不正确,则拒绝文件。这时,验证规则就不适用了,所以"max"规则在这里也帮不上忙。在这种情况下,您显然需要针对这种类型的错误(超过最大文件大小)定制消息。我认为扩展Validator类是一个很好的解决方案。

use Illuminate'Http'UploadedFile;
use Illuminate'Validation'Validator;
class UploadSizeValidator extends Validator
{
    protected function validateAttribute($attribute, $rule)
    {
        $value = $this->getValue($attribute);
        if ($value instanceof UploadedFile && $value->getError() != UPLOAD_ERR_OK) {
            switch ($value->getError()) {
                case UPLOAD_ERR_INI_SIZE:
                    return $this->addFailure($attribute, 'max_file_size_exceeded', []);
                // check additional UPLOAD_ERR_XXX constants if you want to handle other errors
            }
        }
        return parent::validateAttribute($attribute, $rule);
    }
}

现在,您如何告诉框架使用您的验证器而不是默认的验证器?你可以在Validator Factory上设置一个解析器函数:

// do this in a 'boot' method of a ServiceProvider
use Illuminate'Support'Facades'Validator;
Validator::resolver(function($translator, $data, $rules, $messages, $customAttributes) {
    return new UploadSizeValidator($translator, $data, $rules, $messages, $customAttributes);
});

最后在validation.php lang文件中为键'max_file_size_exceeded'设置一个适当的消息