Berkas upload adalah jenis input yang paling berbahaya untuk dibiarkan tanpa validasi: file berukuran raksasa bisa menghabiskan storage, dan berkas yang diklaim .jpg bisa saja berisi skrip berbahaya. Untuk kebutuhan itu Laravel menyediakan satu set rule khusus file: file, mimes:, mimetypes:, image, dimensions:, serta max: yang satuan pengembaliannya berbeda dari validasi string. Chapter ini menguji semuanya lewat feature test dengan berkas tiruan UploadedFile::fake().

Rules Dasar: file, mimes:, dan max: #

Kombinasi paling umum untuk satu berkas adalah file|mimes:jpg,png|max:2048:

php
$validated = $request->validate([
    'avatar' => ['required', 'file', 'mimes:jpg,png', 'max:2048'],
]);

return response()->json([
    'asli' => $validated['avatar']->getClientOriginalName(),
    'ukuran_kb' => (int) round($validated['avatar']->getSize() / 1024),
    'ekstensi' => $validated['avatar']->getClientOriginalExtension(),
]);

Rule file memastikan upload berasal dari request upload yang sah, mimes:jpg,png memeriksa ekstensi berkas terhadap daftar yang diizinkan (pemeriksaan dilakukan Laravel lewat peta ekstensi ke tipe MIME), dan max:2048 membatasi ukuran. Nilai dari validated() untuk field upload berupa instance Illuminate\Http\UploadedFile — bukan string — sehingga kita bisa langsung memanggil getClientOriginalName() dan getSize().

Pengujian upload di feature test memakai UploadedFile::fake()->image() untuk membuat berkas gambar tiruan:

php
public function test_upload_png_kecil_berhasil(): void
{
    $file = UploadedFile::fake()->image('avatar.png', 100, 100)->size(200); // 200 KB

    $response = $this->post('/foto', ['avatar' => $file]);

    $response->assertStatus(200)->assertValid('avatar');
}

Output yang Dihasilkan:

text
upload png 200KB:
{"asli":"avatar.png","ukuran_kb":200,"ekstensi":"png"}

Assertion assertValid('avatar') memastikan field tersebut lolos validasi tanpa error. Sekarang kita kirim berkas yang melampaui batas — gambar dengan size(3000) alias 3000 KB, lebih besar dari max:2048:

Output yang Dihasilkan:

text
upload 3000KB (lebih dari 2048):
  The avatar field must not be greater than 2048 kilobytes.

Pesan error-nya sendiri menyebut satuan kilobytes secara eksplisit. Pengujian berkas dengan tipe terlarang juga lugas — cukup buat PDF tiruan dengan UploadedFile::fake()->create('dokumen.pdf', 100, 'application/pdf'):

Output yang Dihasilkan:

text
upload pdf padahal mimes:jpg,png:
  The avatar field must be a file of type: jpg, png.

Rule image dan dimensions: #

Rule image adalah jalan pintas untuk mimes:jpg,jpeg,png,bmp,gif,webp,avif — cukup nyata bahwa berkas yang diupload memang gambar. Untuk menuntut ukuran piksel tertentu, rule dimensions: menerima parameter seperti min_width, max_width, width, height, dan rasio:

php
$validated = $request->validate([
    'pas_foto' => ['required', 'image', 'dimensions:min_width=200,min_height=200'],
]);

Rule di atas mensyaratkan pas foto minimal 200×200 piksel. Kita uji dengan dua gambar tiruan berbeda:

Output yang Dihasilkan:

text
gambar 150x150:
  The pas foto field has invalid image dimensions.

gambar 300x300:
{"lebar":300,"tinggi":300}

Validasi Banyak Berkas Sekaligus #

Form galeri memungkinkan beberapa berkas dikirim lewat input bernama sama dengan multiple. Data yang sampai ke Laravel berupa array, dan tanda bintak memvalidasi setiap elemennya:

php
$validated = $request->validate([
    'galeri' => ['required', 'array', 'min:1'],
    'galeri.*' => ['required', 'file', 'mimes:jpg,png', 'max:512'],
]);

return response()->json([
    'jumlah' => count($validated['galeri']),
    'nama' => collect($validated['galeri'])
        ->map(fn ($f) => $f->getClientOriginalName())->all(),
]);

Rule array menjaga input galeri benar berupa array, min:1 menolak array kosong, dan galeri.* menerapkan batas tipe serta ukuran — di sini 512 KB per berkas — pada setiap elemen. Dua berkas yang diupload bersama divalidasi terpisah; hanya elemen bermasalah yang error:

Output yang Dihasilkan:

text
galeri.1 pdf:
  The galeri.1 field must be a file of type: jpg, png.

galeri valid:
{"jumlah":2,"nama":["liburan.png","keluarga.png"]}

Rule mimes: memeriksa ekstensi terhadap peta tipe MIME internal Laravel. Bila kita ingin memeriksa MIME dari isi berkas secara lebih ketat, tersedia pula mimetypes:image/jpeg,image/png yang mencocokkan tipe MIME upload terhadap daftar yang ditulis eksplisit. Kombinasi keduanya memberi pertahanan berlapis untuk berkas yang diizinkan masuk aplikasi.

Setelah berkas dinyatakan sah, tugas validasi belum sepenuhnya selesai untuk data yang harus unik — misalnya alamat email saat pendaftaran. Chapter berikutnya membahas rule unique dan exists yang membandingkan input langsung dengan isi database. Rujukan lengkap ada di dokumentasi Validation — File Rules .