Menggunakan SMB untuk Penyimpanan File di Laravel

Panduan lengkap menggunakan SMB untuk menyimpan dan mengelola file di aplikasi Laravel dengan mudah dan efektif.
Menggunakan SMB untuk Penyimpanan File di Laravel

Mount Folder SMB dari NAS

nanaan

sudo mkdir -p /mnt/nas/sandbox

Mount SMB Secara Otomatis

Agar mount tetap setelah reboot, edit sudo nano /etc/fstab

//192.168.2.8/Web/SANDBOX /mnt/nas/sandbox cifs username=USERNAME,password=YOUR_PASSWORD,vers=3.0,uid=www-data,gid=www-data,file_mode=0777,dir_mode=0777,mfsymlinks 0 0

Ubah Kepemilikan Folder

Jalankan perintah berikut agar Laravel (www-data) bisa mengakses folder NAS:

sudo chown -R www-data:www-data /mnt/nas/sandbox
sudo chmod -R 775 /mnt/nas/sandbox

chown -R www-data:www-data /mnt/nas/sandbox: Mengubah kepemilikan folder ke user www-data.

chmod -R 775 /mnt/nas/sandbox: Memberikan izin baca & tulis ke www-data, serta baca ke grup lain.

Cek kembali.

ls -ld /mnt/nas/sandbox

Seharusnya keluar seperti ini.

drwxrwxr-x 2 www-data www-data 0 Feb  5 08:54 /mnt/nas/sandbox

Uji Mounting

Setelah mengedit /etc/fstab, jalankan perintah berikut untuk memastikan mount berhasil.

sudo mount -a
ls -l /mnt/nas/sandbox

Jalankan perintah berikut untuk memastikan www-data bisa membuat folder.

sudo -u www-data mkdir /mnt/nas/sandbox/test-folder

Konfigurasi Laravel

Edit config/filesystems.php, tambahkan disk baru.

'disks' => [
    'nas' => [
        'driver' => 'local',
        'root' => '/mnt/nas/sandbox',
    ],
],

Lalu di .env, ubah.

FILESYSTEM_DISK=nas

Jalankan perintah.

php artisan config:clear
php artisan config:cache

Uji Coba Upload File ke NAS

Cara mengunggah file dari aplikasi Laravel ke SMB.

Route::get('/files', [SMBController::class, 'index'])->name('files.index');
Route::get('/files/view/{filename}', [SMBController::class, 'show'])->name('files.show');
Route::get('/upload', [SMBController::class, 'create'])->name('files.create');
Route::post('/upload', [SMBController::class, 'store'])->name('files.store');
Route::delete('/files/{filename}', [SMBController::class, 'delete'])
    ->where('filename', '.*')
    ->name('files.delete');
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class SMBController extends Controller
{
    public function index()
    {
        $files = Storage::disk('nas')->files('test-folder');
        return view('files.index', compact('files'));
    }

    public function create()
    {
        return view('files.create');
    }

    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|file',
            'id' => 'required|string' // ID manual yang digunakan sebagai nama file
        ]);

        $file = $request->file('file');
        $fileName = $request->id . '.' . $file->getClientOriginalExtension(); // Gunakan ID sebagai nama file

        // Simpan file ke dalam 'test-folder' dengan nama berdasarkan ID
        Storage::disk('nas')->putFileAs('test-folder', $file, $fileName);

        return redirect()->route('files.index')->with('success', 'File berhasil diupload atau diperbarui.');
    }

    public function show($filename)
    {
        $filePath = "test-folder/$filename";

        if (Storage::disk('nas')->exists($filePath)) {
            $file = Storage::disk('nas')->get($filePath);
            $mimeType = Storage::disk('nas')->mimeType($filePath);

            return response($file)->header('Content-Type', $mimeType);
        } else {
            abort(404);
        }
    }

    public function delete($filename)
    {
        $filePath = "test-folder/$filename";

        if (Storage::disk('nas')->exists($filePath)) {
            Storage::disk('nas')->delete($filePath);
            return redirect()->route('files.index')->with('success', 'File berhasil dihapus.');
        } else {
            return redirect()->route('files.index')->with('error', 'File tidak ditemukan.');
        }
    }
}
<!DOCTYPE html>
<html lang="id">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Daftar File di NAS</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    </head>

    <body class="bg-light">
        <div class="container mt-5">
            <h1 class="text-center mb-4">Daftar File di NAS</h1>

            <a href="{{ route('files.create') }}" class="btn btn-success mb-3">Upload File</a>

            <table class="table table-striped table-bordered">
                <thead class="table-dark">
                    <tr>
                        <th>#</th>
                        <th>Gambar</th>
                        <th>Nama File</th>
                        <th>Aksi</th>
                    </tr>
                </thead>
                <tbody>
                    @forelse($files as $index => $file)
                    <tr>
                        <td>{{ $index + 1 }}</td>
                        <td>
                            <img src="{{ route('files.show', ['filename' => basename($file)]) }}"
                                alt="{{ basename($file) }}" class="img-thumbnail" width="100">
                        </td>
                        <td>{{ basename($file) }}</td>
                        <td>
                            <form action="{{ route('files.delete', ['filename' => basename($file)]) }}" method="POST">
                                @csrf
                                @method('DELETE')
                                <button type="submit" class="btn btn-danger btn-sm"
                                    onclick="return confirm('Yakin ingin menghapus file ini?')">Hapus</button>
                            </form>
                        </td>
                    </tr>
                    @empty
                    <tr>
                        <td colspan="4" class="text-center">Tidak ada file yang tersedia.</td>
                    </tr>
                    @endforelse
                </tbody>
            </table>
        </div>

        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    </body>
</html>
<!DOCTYPE html>
<html lang="id">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Upload atau Edit File</title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    </head>

    <body class="bg-light">
        <div class="container mt-5">
            <h1 class="text-center mb-4">Upload atau Edit File</h1>

            @if(session('success'))
            <div class="alert alert-success">{{ session('success') }}</div>
            @endif
            @if(session('error'))
            <div class="alert alert-danger">{{ session('error') }}</div>
            @endif

            <div class="card shadow-sm p-4">
                <form action="{{ route('files.store') }}" method="POST" enctype="multipart/form-data">
                    @csrf
                    <div class="mb-3">
                        <label for="id" class="form-label">ID (Nama File)</label>
                        <input type="text" class="form-control" name="id" required placeholder="Masukkan ID file (misal: 123)">
                    </div>

                    <div class="mb-3">
                        <label for="file" class="form-label">Pilih File</label>
                        <input type="file" class="form-control" name="file" required>
                    </div>

                    <button type="submit" class="btn btn-primary">Upload / Edit</button>
                    <a href="{{ route('files.index') }}" class="btn btn-secondary">Kembali</a>
                </form>
            </div>
        </div>

        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    </body>
</html>

About the author

Zulfadli Rizal
Make it Simple but Significant!

Posting Komentar