2016-11-16 13 views
7

W Laravel 5.3 próbuję złapać, czy przesłany plik ma większy rozmiar pliku niż upload_max_filesize. Pole przesyłania nie jest wymagane.Laravel 5.3, sprawdź czy przesłany plik jest większy niż upload_max_filesize (opcjonalny upload)

próbowałem tej metody, ale to nie działa

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

nie mogę używać tylko if (!$file->isValid()) ponieważ pole plik jest opcjonalny i ja dostać Call to a member function isValid() on null jeśli pole jest puste.

Muszę więc sprawdzić, czy pole jest obecne przy użyciu if (request()->hasFile($field)), ale to nie działa dla dużych plików, ponieważ dd(request()->hasFile('picture')) zwraca false.

Oczywiście mogę polegać na domyślnych komunikatach Laravel Validator, ale dostaję atrapę The picture failed to upload., która nie daje żadnej wskazówki użytkownikowi.

+2

http://stackoverflow.com/questions/2840755/how-to-specify-the-max-file-upload-limit-in-php –

+0

Sprawdź moją odpowiedź –

Odpowiedz

4

Należy rozważyć użycie wbudowanego systemu sprawdzania poprawności formularza Laravel. Jest zbudowany w regule walidacji, który pozwala określić rozmiar max pliku, można sprawdzić w dokumentacji tutaj:

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

Reguła będzie wyglądać mniej więcej tak:

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

To byłoby niepowodzenie, jeśli przesłany plik był większy niż 256kb.

Wspominałeś, że nie podobały Ci się komunikaty o błędach sprawdzania poprawności Laravel. Nie ma problemu! Można je zmienić w pliku językowego resources/lang/en/validation.php, jest to linia, którą trzeba zmienić:

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

+1

uhm ... ten rodzaj sprawdzania poprawności działa dla pliku powyżej "maksymalnego" progu, ale PONIŻEJ ustawienie upload_max_filesize i nie działa dla pliku ABOVE ustawienia upload_max_filesize ... – Ivan

+4

Żadna forma sprawdzania po stronie serwera nie zadziała, jeśli twoje pliki upload_max_files Ustawienie ize' jest zbyt niskie - musisz to zwiększyć. – edcs

+0

Jak skomentował PO, to rozwiązanie nie pomaga, ponieważ reguła "maksimum" nie jest nigdy sprawdzana, jeśli nie udało się załadować pliku. – alepeino

-1

Domyślne zachowanie dla plików laravel walidator jest odrzucić plik, jeśli wysyłanie nie było ok, do jakikolwiek powód. Reguły walidacji nie są wtedy stosowane, więc reguła "maksimum" nie może ci tutaj pomóc. Oczywiście potrzebujesz w tym przypadku niestandardowego komunikatu dla tego typu błędu (maksymalny rozmiar pliku został przekroczony). Myślę, że rozszerzenie klasy Validator to eleganckie rozwiązanie.

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

Teraz, jak powiedzieć ramie, aby użyć walidatora zamiast domyślnego? Można ustawić funkcję rozpoznawania na Validator fabryczne:

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

Wreszcie ustawić odpowiedni komunikat dla klucza „max_file_size_exceeded” w pliku validation.php Lang.

+0

Uhm ... wydaje się nieco skomplikowany: zauważyłem, że istnieje klasa 'Symfony \ Component \ HttpFoundation \ File \ UploadedFile', która ma wszystkie potrzebne mi metody, czy nie istnieje prosty sposób na jego wykorzystanie PRZED każdym innym sprawdzaniem poprawności i przekierowanie użytkownika do poprzedniej strony, jeśli plik jest zbyt duży? – Ivan

+0

@Ivan tak, jest to możliwe. W jaki sposób walidujesz? W kontrolerze z '$ this-> validate' lub masz klasę FormRequest z regułami sprawdzania poprawności? – alepeino

+0

Przepraszam za spóźnioną odpowiedź, nie było mnie w domu w ciągu ostatnich 10 dni :-(Tak, używam '$ this-> validate': Właśnie widziałem twoją odpowiedź: można się przekierować bez zachowania danych wejściowych, ale ja ' Chciałbym uniknąć oprogramowania pośredniego – Ivan

5

Laravel Validation będzie działał tylko wtedy, gdy przesyłany plik będzie mniejszy niż limit ustawiony w pliku php.ini.

Jeśli spróbujesz przesłać plik większy niż limit, PHP nie przesyła żądania do Laravel, i natychmiast wyświetli błąd. Dlatego Laravel nie może nic zrobić w tym scenariuszu.

Jednym ze sposobów rozwiązania tego problemu jest ustawienie znacznie większego limitu w pliku php.ini, a następnie sprawdzenie rozmiaru pliku w Laravel.

1

kodu po stronie serwera (kontroler):

Poniżej funkcji pochodzi z Drupal przez meustrus autora na jego stack answer i wziąłem tutaj jako przykład. Zacznij 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; 

funkcję publiczną do analizowania rozmiar

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

Ustaw kompaktowy dla Prześlij wartość 'file_upload_max_size' na ostrze

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

JS Validation (W 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); 

2

My previous answer obsługiwane przypadku, gdy przesłany plik był większy niż ustawienie w php.iniupload_max_filesize. Ale nie powiodło się, gdy rozmiar pliku spowodował, że Żądanie było większe niż post_max_size (inne ustawienie php.ini). Ten przypadek jest trudniejszy w obsłudze, ponieważ dane wejściowe ($_POST globalne, jeśli mamy do czynienia z prostym PHP) zostaną wyczyszczone.

myślę, że Middleware jest dobrym miejscem, aby to zrobić "poprawności": (. Jak powiedziałem, to nie będzie zachować wejście)

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

Powiązane problemy