TechTopia Casing SSD NVMe NGFF USB 3.1 Type-C Enclosure Eksternal M.2 SATA & NVMe High Speed

Laravel Storage: File Upload, Public Disk, dan Symbolic Link

Laravel menyediakan sistem filesystem yang memudahkan developer untuk mengelola file, mulai dari upload gambar, dokumen, dan avatar pengguna hingga penyimpanan file pada server atau layanan cloud. Fitur ini dikenal sebagai Laravel Storage.

Bagi developer yang baru menggunakan Laravel, konsep seperti Storage, disk, public, storage:link, dan symbolic link terkadang membingungkan.

Secara sederhana, Laravel Storage adalah lapisan abstraksi untuk mengelola file tanpa harus bergantung langsung pada struktur folder atau jenis media penyimpanan tertentu. Dengan konfigurasi yang tepat, aplikasi dapat menyimpan file pada local filesystem, public disk, Amazon S3, atau filesystem lainnya menggunakan API yang konsisten.

Artikel ini membahas cara kerja Laravel Storage, file upload, public disk, symbolic link, URL file, validasi upload, serta praktik terbaik agar pengelolaan file di aplikasi Laravel tetap aman dan mudah dirawat.

Apa Itu Laravel Storage?

Laravel Storage merupakan filesystem abstraction yang disediakan Laravel untuk berinteraksi dengan file.

Alih-alih menggunakan fungsi PHP seperti move_uploaded_file() atau file_put_contents() secara langsung, Laravel menyediakan facade Storage yang dapat digunakan untuk membuat, membaca, menghapus, dan mengecek file.

Contoh sederhana:

use Illuminate\Support\Facades\Storage;

Storage::put('documents/example.txt', 'Isi file');

Kode tersebut menyimpan file example.txt pada filesystem yang dikonfigurasi oleh disk yang digunakan.

Laravel menggunakan konsep disk untuk menentukan di mana file disimpan dan bagaimana aplikasi berinteraksi dengan media penyimpanan tersebut.

Memahami Konsep Disk pada Laravel

Disk adalah konfigurasi filesystem yang digunakan Laravel untuk menentukan lokasi penyimpanan file dan driver yang digunakan.

Konfigurasi filesystem Laravel biasanya berada pada:

config/filesystems.php

Contoh konfigurasi disk:

'disks' => [

    'local' => [
        'driver' => 'local',
        'root' => storage_path('app/private'),
    ],

    'public' => [
        'driver' => 'local',
        'root' => storage_path('app/public'),
        'url' => env('APP_URL').'/storage',
        'visibility' => 'public',
    ],

],

Perbedaan penting antara disk terletak pada root directory, driver, URL, dan visibility.

Disk local biasanya digunakan untuk file yang tidak perlu diakses secara langsung oleh publik. Sementara itu, disk public digunakan untuk file yang memang perlu dapat diakses melalui browser.

Apa Itu Public Disk di Laravel?

Public disk adalah filesystem yang digunakan untuk menyimpan file yang boleh diakses secara publik.

Pada konfigurasi Laravel, public disk secara umum mengarah ke:

storage/app/public

Misalnya aplikasi menyimpan gambar menggunakan:

$path = $request->file('image')->store('images', 'public');

Jika upload berhasil, Laravel dapat menghasilkan path seperti:

images/example.jpg

File sebenarnya berada di:

storage/app/public/images/example.jpg

Namun, file tersebut belum otomatis dapat diakses melalui URL seperti:

https://example.com/storage/images/example.jpg

Untuk membuat file pada public disk dapat diakses melalui URL, diperlukan symbolic link.

Apa Itu Symbolic Link pada Laravel?

Symbolic link atau symlink adalah sebuah link pada filesystem yang mengarahkan satu lokasi folder ke lokasi lainnya.

Laravel menggunakan symbolic link agar folder:

public/storage

mengarah ke:

storage/app/public

Dengan begitu, file yang disimpan pada public disk dapat diakses melalui web server menggunakan URL /storage.

Untuk membuat symbolic link, jalankan perintah Artisan berikut:

php artisan storage:link

Setelah perintah tersebut dijalankan, Laravel akan membuat hubungan antara:

public/storage

dan:

storage/app/public

Mengapa storage:link Diperlukan?

Secara umum, web server menjadikan folder public sebagai document root aplikasi Laravel.

Artinya, browser dapat mengakses file yang berada di dalam:

public/

Sementara file pada:

storage/app/public/

berada di luar document root tersebut.

Tanpa symbolic link, browser tidak dapat mengakses file tersebut secara langsung melalui URL /storage.

Setelah menjalankan php artisan storage:link, struktur sederhananya menjadi:

project/
├── app/
├── public/
│   └── storage -> ../storage/app/public
├── storage/
│   └── app/
│       └── public/
│           └── images/
└── ...

Tanda -> menunjukkan bahwa public/storage merupakan symbolic link menuju storage/app/public.

Cara Upload File ke Public Disk

Laravel menyediakan cara yang sederhana untuk melakukan upload file.

Misalnya terdapat form upload gambar berikut:

<form action="/profile" method="POST" enctype="multipart/form-data">
    @csrf

    <input type="file" name="avatar">

    <button type="submit">Upload</button>
</form>

Pada controller, file dapat disimpan menggunakan:

use Illuminate\Http\Request;

public function update(Request $request)
{
    $request->validate([
        'avatar' => ['required', 'image', 'max:2048'],
    ]);

    $path = $request->file('avatar')->store('avatars', 'public');

    return $path;
}

Jika upload berhasil, Laravel dapat menghasilkan path seperti:

avatars/abc123.jpg

File tersebut disimpan pada:

storage/app/public/avatars/abc123.jpg

dan dapat diakses melalui:

/storage/avatars/abc123.jpg

Cara Menampilkan File dari Public Disk

Setelah file disimpan pada public disk dan symbolic link sudah dibuat, URL file dapat dibuat menggunakan Storage::url().

use Illuminate\Support\Facades\Storage;

$url = Storage::disk('public')->url($path);

Jika $path berisi:

avatars/abc123.jpg

URL yang dihasilkan dapat berupa:

/storage/avatars/abc123.jpg

Pada Blade, URL tersebut dapat digunakan untuk menampilkan gambar:

<img
    src="{{ Storage::disk('public')->url($user->avatar) }}"
    alt="Avatar"
>

Pendekatan ini lebih baik daripada menulis path secara manual di banyak tempat karena URL mengikuti konfigurasi filesystem Laravel.

Upload File dengan Nama yang Unik

Salah satu keuntungan menggunakan metode store() adalah Laravel dapat menghasilkan nama file secara otomatis.

$path = $request->file('avatar')->store('avatars', 'public');

Laravel akan menghasilkan nama file yang unik sehingga aplikasi tidak perlu bergantung pada nama file asli dari pengguna.

Nama file asli dapat diambil menggunakan metode tertentu jika memang diperlukan. Namun, untuk penyimpanan, menggunakan nama yang dibuat oleh aplikasi biasanya merupakan pilihan yang lebih aman dan konsisten.

Validasi File Upload

File upload sebaiknya selalu divalidasi sebelum disimpan.

Contoh untuk dokumen:

$request->validate([
    'document' => [
        'required',
        'file',
        'mimes:pdf,doc,docx',
        'max:5120',
    ],
]);

Validasi tersebut membatasi file yang diterima berdasarkan tipe dan ukuran.

Untuk upload gambar, contohnya:

$request->validate([
    'image' => [
        'required',
        'image',
        'mimes:jpg,jpeg,png,webp',
        'max:2048',
    ],
]);

Validasi file penting karena file yang diunggah pengguna merupakan input yang tidak boleh langsung dipercaya.

Jangan Hanya Mengandalkan Ekstensi File

Ekstensi file bukan satu-satunya faktor yang menentukan apakah file aman atau benar-benar sesuai dengan jenis yang diharapkan.

File bernama image.jpg belum tentu merupakan gambar yang valid.

Karena itu, gunakan validation rule Laravel seperti:

'image' => ['required', 'image']

Untuk aplikasi yang menangani file sensitif, validasi juga sebaiknya disertai pembatasan ukuran, jenis file, hak akses, dan strategi penyimpanan yang sesuai.

Perbedaan File Public dan Private

Tidak semua file seharusnya disimpan pada public disk.

Contoh file yang umumnya memang perlu diakses oleh browser antara lain:

  • avatar pengguna;
  • gambar artikel;
  • thumbnail produk;
  • gambar banner;
  • aset publik lainnya.

Sementara itu, file seperti dokumen identitas, invoice pribadi, kontrak, atau laporan internal sebaiknya tidak langsung diletakkan pada lokasi yang dapat diakses publik.

Secara sederhana, alur public file adalah:

Public File
    ↓
storage/app/public
    ↓
public/storage
    ↓
URL /storage
    ↓
Browser

Untuk file private, aplikasi sebaiknya mengatur akses melalui controller atau mekanisme authorization sebelum file diberikan kepada pengguna.

Menghapus File dari Laravel Storage

File dapat dihapus menggunakan facade Storage.

use Illuminate\Support\Facades\Storage;

Storage::disk('public')->delete($path);

Untuk menghapus beberapa file sekaligus:

Storage::disk('public')->delete([
    'avatars/avatar-1.jpg',
    'avatars/avatar-2.jpg',
]);

Contoh tersebut berguna ketika aplikasi perlu membersihkan file yang sudah tidak digunakan.

Mengecek Apakah File Ada

Sebelum melakukan operasi tertentu, aplikasi dapat memeriksa keberadaan file menggunakan exists().

if (Storage::disk('public')->exists($path)) {
    // File tersedia
}

Contohnya ketika pengguna mengganti avatar:

if ($user->avatar && Storage::disk('public')->exists($user->avatar)) {
    Storage::disk('public')->delete($user->avatar);
}

Dengan cara ini, file lama dapat dibersihkan sebelum atau setelah file baru digunakan.

Perbedaan Path dan URL pada Laravel Storage

Salah satu hal yang sering membingungkan adalah perbedaan antara filesystem path dan URL.

Untuk mendapatkan filesystem path:

$path = Storage::disk('public')->path($filename);

Hasilnya dapat berupa path seperti:

/var/www/app/storage/app/public/avatars/avatar.jpg

Sedangkan untuk mendapatkan URL:

$url = Storage::disk('public')->url($filename);

Hasilnya dapat berupa:

https://example.com/storage/avatars/avatar.jpg

Jadi, gunakan path() ketika membutuhkan lokasi file pada filesystem server dan gunakan url() ketika membutuhkan alamat file yang akan diakses oleh browser.

Kesalahan Umum Laravel Storage

1. Gambar Tidak Bisa Dibuka

Jika gambar sudah berhasil di-upload tetapi URL menghasilkan 404 Not Found, periksa apakah symbolic link sudah dibuat:

php artisan storage:link

Kemudian pastikan file memang berada di dalam:

storage/app/public

2. Menggunakan Disk yang Berbeda

Pastikan disk yang digunakan saat menyimpan file sama dengan disk yang digunakan ketika membuat URL atau menghapus file.

Contohnya:

$path = $request->file('image')->store('images', 'public');

$url = Storage::disk('public')->url($path);

3. Symbolic Link Belum Dibuat di Production

Pada local development, developer mungkin sudah menjalankan:

php artisan storage:link

Namun ketika aplikasi dipindahkan ke server production, symbolic link perlu dipastikan tersedia pada environment tersebut.

4. Permission Folder Bermasalah

Jika Laravel tidak dapat menulis file ke storage dan muncul error seperti Permission denied, periksa permission filesystem serta user yang menjalankan PHP atau web server.

Hindari memberikan permission terbuka ke seluruh filesystem hanya untuk mengatasi masalah permission. Sesuaikan permission dengan konfigurasi server.

Laravel Storage untuk Aplikasi Production

Untuk aplikasi dengan jumlah file yang besar, local filesystem bukan satu-satunya pilihan.

Laravel juga dapat digunakan dengan object storage seperti Amazon S3 dan layanan lain yang kompatibel dengan S3.

Pendekatan tersebut dapat membantu ketika aplikasi membutuhkan:

  • penyimpanan file dalam jumlah besar;
  • pemisahan storage dan application server;
  • deployment yang lebih fleksibel;
  • skalabilitas penyimpanan;
  • distribusi file melalui infrastruktur cloud.

Karena Laravel menggunakan konsep disk, logika aplikasi dapat tetap menggunakan API Storage meskipun media penyimpanannya berubah.

Contoh penggunaan S3:

Storage::disk('s3')->put(
    'documents/example.pdf',
    $contents
);

Hal ini merupakan salah satu kelebihan abstraction layer pada Laravel Storage.

Praktik Terbaik Menggunakan Laravel Storage

Agar pengelolaan file lebih rapi dan aman, beberapa praktik berikut dapat diterapkan.

Gunakan Disk Secara Eksplisit

Jika aplikasi memiliki beberapa jenis penyimpanan, gunakan disk secara eksplisit agar kode lebih mudah dipahami.

Storage::disk('public')

Validasi Setiap File Upload

Jangan menyimpan file dari pengguna tanpa melakukan validasi ukuran dan jenis file.

Pisahkan File Public dan Private

File yang tidak seharusnya dapat diakses langsung melalui URL jangan diletakkan pada public disk.

Gunakan Nama File yang Aman

Hindari menjadikan nama file asli pengguna sebagai satu-satunya strategi penamaan file. Gunakan nama yang dibuat aplikasi atau mekanisme penamaan yang sesuai dengan kebutuhan.

Hapus File yang Sudah Tidak Digunakan

Ketika pengguna mengganti avatar atau gambar, pertimbangkan untuk menghapus file lama agar storage tidak terus dipenuhi file yang sudah tidak digunakan.

Pertimbangkan Object Storage

Jika aplikasi mulai memiliki banyak file atau membutuhkan arsitektur deployment yang lebih kompleks, object storage dapat menjadi pilihan yang lebih tepat dibandingkan hanya mengandalkan filesystem lokal server aplikasi.

Kesimpulan

Laravel Storage menyediakan cara yang terstruktur untuk menangani file dalam aplikasi Laravel. Konsep terpenting yang perlu dipahami adalah disk, public disk, file upload, dan symbolic link.

Alur sederhana untuk public file adalah:

User Upload
    ↓
Laravel Request
    ↓
Validasi File
    ↓
Storage::store()
    ↓
storage/app/public
    ↓
public/storage
    ↓
URL File
    ↓
Browser

Untuk menyimpan file pada public disk, aplikasi dapat menggunakan:

$path = $request->file('image')->store('images', 'public');

Kemudian buat symbolic link dengan:

php artisan storage:link

URL file dapat dibuat menggunakan:

$url = Storage::disk('public')->url($path);

Sementara itu, file yang bersifat sensitif sebaiknya tidak diekspos melalui public disk. Aksesnya perlu dilindungi dengan authorization dan mekanisme penyajian file yang sesuai.

Dengan memahami hubungan antara Laravel Storage, disk, public storage, file upload, dan symbolic link, pengelolaan file pada aplikasi Laravel akan menjadi lebih mudah, aman, dan siap dikembangkan untuk kebutuhan production.