2016-11-16 108 views
7

在Laravel 5.3中,如果上传的文件的文件大小大于upload_max_filesize,我试图捕获该文件。上传字段不是必需的。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()); 
     } 
    } 
} 

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

所以我要检查,如果字段存在使用if (request()->hasFile($field)),但这并不对大文件的工作,因为dd(request()->hasFile('picture'))回报false

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

+2

http://stackoverflow.com /问题/ 2840755 /如何到确定最最大文件上传限制功能于PHP –

+0

看看我的答案 –

回答

4

您应该考虑使用内置的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

+1

呃... ...这种验证适用于文件之上,“最大”阈值,但低于upload_max_filesize设置,并且不适用于文件ABOVE upload_max_filesize设置... – Ivan

+4

如果你的'upload_max_files ize'设置太低 - 你需要增加这个。 – edcs

+0

正如OP所评论的,这个解决方案没有帮助,因为如果文件上传失败,“max”规则从不被检查。 – alepeino

-1

为Laravel文件验证器的默认行为是拒绝的文件,如果上传的内容是不正常,对无论原因。然后验证规则不适用,因此“最大”规则无法帮助您。 在这种情况下,您显然希望为此类错误提供自定义消息(超出最大文件大小)。我认为扩展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); 
    } 
} 

现在,你怎么告诉框架使用您的验证,而不是默认的一个吗?您可以在验证出厂设置解析器功能:

// 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郎文件“max_file_size_exceeded”的关键。

+0

呃......看起来有点复杂:我注意到有一个'Symfony \ Component \ HttpFoundation \ File \ UploadedFile'类,它有我需要的所有方法,在进行任何其他验证之前没有简单的方法来使用它,并且如果文件太大,将用户重定向到上一页? – Ivan

+0

@伊万是的,这是可能的。你如何验证?在带'$ this-> validate'的控制器中,还是你有一个带验证规则的FormRequest类? – alepeino

+0

对不起,最近10天我不在家:-(是的,我用'$ this-> validate':我刚刚看到你的答案:没有保留输入就可以重定向, d喜欢避免中间件 – Ivan

5

只有当您上传的文件大小小于php.ini中设置的限制时,Laravel Validation才有效。

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

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

1

服务器端代码(在控制器):

以下功能从Drupal的由meustrus作者在他的stack answer采取和我在这里作为例子。 开始的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' 价值刀片

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

JS验证(在刀片):

<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); 

2

My previous answer处理,其中上载的文件比在php.iniupload_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; 
}