Di episode sebelumnya kamu sudah mempelajari relasi Eloquent — sekarang saatnya menambahkan fitur yang membuat aplikasi lebih menarik: upload file. Laravel menyediakan sistem storage yang robust dan mudah digunakan, jadi kamu tidak perlu khawatir tentang masalah teknis yang rumit.
Pada artikel ini, kita akan fokus pada dua use case paling sering ditemui di project blog: upload foto profil user dan thumbnail artikel. Kamu akan belajar cara setup storage, membuat form upload, validasi file dengan ketat, menyimpan file dengan aman, dan menghapus file lama saat perlu update. Mari kita mulai!
Konfigurasi Storage di Laravel 13
Pertama-tama, mari pahami struktur storage Laravel. Setiap project Laravel memiliki folder storage/app yang digunakan untuk menyimpan file upload. Namun, folder ini secara default tidak dapat diakses langsung dari web browser karena alasan keamanan — kamu tidak mau file tersimpan di public directory dan bisa diakses sembarangan.
Untuk membuat file storage bisa diakses, Laravel menyediakan fitur symlink. Buka terminal kamu dan jalankan perintah Artisan berikut:
php artisan storage:linkPerintah ini akan membuat symbolic link dari folder storage/app/public ke folder public/storage. Setelah itu, file yang tersimpan di storage/app/public bisa diakses melalui URL /storage/nama-file. Sangat praktis!
Secara default, konfigurasi storage Laravel sudah menggunakan local driver yang menyimpan file di server lokal. Kamu bisa lihat setting ini di file config/filesystems.php. Untuk keperluan development dan testing, setup default sudah cukup. Ketika deploy ke production, kamu bisa mengubah driver ke cloud storage seperti S3 jika diperlukan.
Membuat Form Upload di Blade
Sekarang mari buat form untuk upload file. Kita akan mulai dari form upload foto profil user. Pastikan form kamu menggunakan attribute enctype="multipart/form-data" — ini penting agar browser bisa mengirim file ke server.
Berikut contoh form sederhana di Blade template:
<form action="{{ route('profile.update') }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="form-group">
<label for="avatar">Foto Profil</label>
<input type="file" id="avatar" name="avatar" class="form-control" accept="image/*" />
@error('avatar')
<span class="text-danger">{{ $message }}</span>
@enderror
</div>
<button type="submit" class="btn btn-primary">Update Profil</button>
</form>Perhatikan beberapa hal penting di sini:
enctype="multipart/form-data"— wajib ada untuk form upload file@csrf— token CSRF untuk keamananaccept="image/*"— filter file picker agar hanya tampilkan file gambar (UX improvement, bukan validasi server)- Error handling dengan
@erroruntuk menampilkan pesan validasi
Untuk fitur preview gambar sebelum upload, kamu bisa tambahkan JavaScript sederhana. Tapi artikel ini fokus pada backend, jadi kamu bisa coba kode tersebut sendiri di project kamu.
Validasi File: Tipe, Ukuran, dan Ekstensi
Validasi file adalah bagian paling krusial dari upload feature. Jangan pernah percaya input dari user — selalu validasi di server side. Laravel menyediakan validation rules yang powerful untuk file:
public function update(Request $request, User $user)
{
$validated = $request->validate([
'avatar' => 'nullable|image|mimes:jpeg,png,gif|max:2048',
'name' => 'required|string|max:255',
]);
// proses update...
}Mari kita breakdown validation rules di atas:
nullable— field ini optional, jika tidak ada file tidak akan errorimage— file harus berupa gambar (MIME type image/*)mimes:jpeg,png,gif— hanya terima file dengan ekstensi jpeg, png, atau gifmax:2048— ukuran file maksimal 2 MB (dalam kilobyte)
Untuk upload thumbnail artikel yang bisa berbentuk jpg, png, atau webp, kamu bisa tulis rule serupa:
'thumbnail' => 'required|image|mimes:jpeg,png,webp|max:5120'Rule image dan mimes bekerja sama dengan memeriksa MIME type file yang sesungguhnya, bukan hanya nama ekstensionnya. Ini berarti user tidak bisa mengakali dengan rename file .exe menjadi .jpg — Laravel akan mendeteksi dan menolak.
Menyimpan dan Mengakses File
Setelah file divalidasi, saatnya menyimpannya. Laravel menyediakan method store() pada object file yang sangat mudah digunakan:
public function update(Request $request, User $user)
{
$validated = $request->validate([
'avatar' => 'nullable|image|mimes:jpeg,png,gif|max:2048',
'name' => 'required|string|max:255',
]);
// Hapus file lama jika ada
if ($user->avatar && Storage::exists('public/avatars/' . $user->avatar)) {
Storage::delete('public/avatars/' . $user->avatar);
}
// Simpan file baru
if ($request->hasFile('avatar')) {
$filename = $request->file('avatar')->store('public/avatars');
$validated['avatar'] = basename($filename);
}
$user->update($validated);
return redirect()->route('profile.show')->with('success', 'Profil berhasil diupdate!');
}Method store() akan menyimpan file ke folder yang kamu tentukan dan return nama file (dengan path). Dengan memanfaatkan basename(), kita hanya menyimpan nama file ke database, bukan path lengkapnya.
Untuk mengakses file yang sudah disimpan, gunakan Storage::url():
<!-- Di Blade template -->
<img src="{{ Storage::url('public/avatars/' . $user->avatar) }}" alt="Foto Profil" />Atau, kamu bisa membuat accessor di model User untuk mempermudah:
protected function avatar(): Attribute
{
return Attribute::make(
get: fn ($value) => $value ? Storage::url('public/avatars/' . $value) : null,
);
}Dengan cara ini, di template kamu cukup tulis $user->avatar dan Laravel akan otomatis return URL lengkap.
Hapus File Lama Saat Update
Scenario yang sering terjadi: user upload foto profil, lalu beberapa hari kemudian upload ulang dengan foto baru. Kamu perlu menghapus file lama agar storage tidak penuh dengan file tidak terpakai.
Gunakan Storage::delete() untuk menghapus file:
// Cek apakah file ada sebelum hapus
if (Storage::exists('public/avatars/' . $oldFilename)) {
Storage::delete('public/avatars/' . $oldFilename);
}Best practice adalah selalu cek keberadaan file terlebih dahulu sebelum delete, agar tidak ada error jika file sudah dihapus sebelumnya. Kamu juga bisa membuat event listener atau middleware untuk auto-cleanup file orphaned (file yang tidak ada referensi di database lagi) secara berkala, tapi itu topik advanced yang bisa kamu pelajari lebih lanjut.
Upload Multiple File dan Batch Processing
Bagaimana jika user ingin upload beberapa file sekaligus? Laravel juga support ini. Gunakan loop foreach untuk proses multiple file:
if ($request->hasFile('attachments')) {
foreach ($request->file('attachments') as $file) {
$filename = $file->store('public/attachments');
Attachment::create([
'post_id' => $post->id,
'filename' => basename($filename),
]);
}
}Untuk form Blade, gunakan name="attachments[]" (perhatikan tanda kurung untuk array) dan tambah attribute multiple pada input file.
Kesimpulan
Upload file di Laravel 13 adalah fitur yang powerful namun mudah digunakan berkat system storage yang matang. Ingat selalu tiga pilar keamanan: validasi file di server (jangan percaya client), simpan file di storage bukan public folder, dan kelola file dengan baik (hapus yang tidak terpakai).
Di project blog kamu, kini kamu sudah bisa menambahkan fitur upload foto profil user dan thumbnail artikel dengan aman dan benar. Selanjutnya di episode #11, kita akan belajar membuat API dan JSON Response — fitur yang essential untuk membuat aplikasi modern yang terintegrasi dengan frontend atau mobile app. Sampai jumpa di episode berikutnya!