File Storage: Upload dan Kelola File
Upload file dengan aman: validasi, disk public vs local, dan generate URL yang benar.
Upload file dari form
Form upload wajib punya enctype="multipart/form-data". Di controller, validasi dulu baru simpan:
<form method="POST" action="/posts" enctype="multipart/form-data">
@csrf
<input type="file" name="cover">
</form>// app/Http/Controllers/PostController.php
use Illuminate\Support\Facades\Storage;
public function store(Request $request)
{
$validated = $request->validate([
'judul' => 'required|max:255',
'cover' => 'nullable|image|mimes:jpg,png,webp|max:2048',
]);
if ($request->hasFile('cover')) {
// Simpan ke disk 'public', Laravel generate nama unik otomatis
$validated['cover'] = $request->file('cover')->store('covers', 'public');
}
Post::create($validated);
return redirect()->route('posts.index');
}Hasil store() misalnya covers/abc123.jpg, simpan string itu di database.
Disk: public vs local
Laravel punya konsep disk: local (private, di storage/app) dan public (bisa diakses browser, di storage/app/public). Untuk file yang bisa dilihat publik, jalankan sekali:
php artisan storage:linkPerintah ini membuat symlink public/storage ke storage/app/public. Tampilkan di Blade:
<img src="{{ asset('storage/' . $post->cover) }}" alt="Cover">
{{-- Atau lewat facade, lebih fleksibel kalau ganti ke S3 --}}
<img src="{{ Storage::url($post->cover) }}" alt="Cover">Hapus dan download
// Hapus file lama saat update atau delete
if ($post->cover) {
Storage::disk('public')->delete($post->cover);
}
// Download paksa (bukan tampil di browser)
return Storage::disk('public')->download($post->cover);
// Cek keberadaan
if (Storage::disk('public')->exists($post->cover)) { ... }Catatan teknis: Jangan pernah percaya nama file asli dari user.
store()otomatis membuat nama acak yang aman. Kalau kamu memakaistoreAs()dengan nama sendiri, sanitasi dulu. Dan selalu validasimimesplusmax, karena file jahat yang di-rename jadi.jpgtetap bisa lolos kalau hanya dicek ekstensinya. Validasiimagememeriksa konten aslinya.