Zum Hauptinhalt springen

Was ist der Dateispeicher?

Laravel bietet eine mächtige Abstraktionsebene über Dateisysteme, die auf dem PHP-Paket Flysystem basiert. Damit können Sie unterschiedliche Storage-Backends – lokale Disks, SFTP, Amazon S3 – über dieselbe API ansprechen. Zwischen Umgebungen umzuschalten erfordert keine Codeänderungen.
Ein Treiberwechsel erfordert keine Code-Anpassung. Eine typische Konfiguration – lokal in der Entwicklung, S3 in der Produktion – lässt sich problemlos umsetzen.

Konfiguration

Die Dateisystem-Einstellungen liegen zentral in config/filesystems.php. Dort definieren Sie „Disks”. Eine Disk ist die Kombination aus einem bestimmten Treiber und einem Speicherort. Die wichtigsten Treiber:
TreiberVerwendung
localLokales Dateisystem des Servers
publicLokale Disk für per Web abrufbare Dateien
s3Amazon S3 (oder S3-kompatible Dienste)
sftpSFTP-Server
ftpFTP-Server

local-Treiber

Der Treiber local arbeitet relativ zum in der filesystems-Konfiguration angegebenen root-Verzeichnis. Standardmäßig entspricht root dem Pfad storage/app/private.
use Illuminate\Support\Facades\Storage;

Storage::disk('local')->put('example.txt', 'Contents');
// Wird nach storage/app/private/example.txt geschrieben

Standard-Disk ändern

Über die Umgebungsvariable FILESYSTEM_DISK schalten Sie die Standard-Disk um.
FILESYSTEM_DISK=s3
Die public-Disk ist für Dateien gedacht, die über den Webserver zugänglich sein sollen. Standardmäßig werden diese Dateien unter storage/app/public gespeichert. Damit der Webserver die Dateien ausliefern kann, legen Sie einen Symlink von public/storage nach storage/app/public an.
1

Symlink anlegen

php artisan storage:link
2

Datei-URL erzeugen

Nach dem Anlegen des Symlinks können Sie URLs über den Helper asset erzeugen.
echo asset('storage/file.txt');
Zusätzliche Symlinks können Sie im Array links in config/filesystems.php konfigurieren.
'links' => [
    public_path('storage') => storage_path('app/public'),
    public_path('images') => storage_path('app/images'),
],
Zum Entfernen eines Symlinks verwenden Sie storage:unlink.
php artisan storage:unlink

Grundoperationen mit der Storage-Facade

Dateien lesen

use Illuminate\Support\Facades\Storage;

// Dateiinhalt als String laden
$contents = Storage::get('file.jpg');

// JSON-Datei laden und dekodieren
$data = Storage::json('orders.json');

// Existenz einer Datei prüfen
if (Storage::exists('file.jpg')) {
    // Datei existiert
}

// Prüfen, dass eine Datei nicht existiert
if (Storage::missing('file.jpg')) {
    // Datei existiert nicht
}

Dateien schreiben

// Datei schreiben
Storage::put('file.jpg', $contents);

// Ressource als Stream schreiben
Storage::put('file.jpg', $resource);

// Anfang oder Ende ergänzen
Storage::prepend('file.log', 'Prepended Text');
Storage::append('file.log', 'Appended Text');

// Dateien kopieren und verschieben
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');
Schlägt put fehl, gibt es standardmäßig false zurück. Mit 'throw' => true in der Disk-Konfiguration können Sie Ausnahmen auslösen lassen.

Dateien löschen

// Einzelne Datei löschen
Storage::delete('file.jpg');

// Mehrere Dateien löschen
Storage::delete(['file.jpg', 'file2.jpg']);

// Dateien auf einer bestimmten Disk löschen
Storage::disk('s3')->delete('path/file.jpg');

Dateien als Download

// Antwort, die den Browser zum Download veranlasst
return Storage::download('file.jpg');

// Mit gewünschtem Dateinamen und zusätzlichen Headern
return Storage::download('file.jpg', 'my-file.jpg', $headers);

URLs erzeugen

Reguläre URL

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file.jpg');
Für den local-Treiber ergibt das eine relative URL wie /storage/file.jpg. Für den s3-Treiber wird die vollständige Remote-URL zurückgegeben.

Temporäre URL

Für zeitlich begrenzte URLs nutzen Sie temporaryUrl. Unterstützt werden die Treiber local und s3.
use Illuminate\Support\Facades\Storage;

$url = Storage::temporaryUrl(
    'file.jpg',
    now()->plus(minutes: 5)
);
Für S3 können Sie zusätzliche Request-Parameter angeben.
$url = Storage::temporaryUrl(
    'file.jpg',
    now()->plus(minutes: 5),
    [
        'ResponseContentType' => 'application/octet-stream',
        'ResponseContentDisposition' => 'attachment; filename=file.jpg',
    ]
);
Für temporäre Upload-URLs verwenden Sie temporaryUploadUrl. Das eignet sich für serverlose Setups, in denen der Client direkt zu S3 hochlädt.
['url' => $url, 'headers' => $headers] = Storage::temporaryUploadUrl(
    'file.jpg', now()->plus(minutes: 5)
);

Datei-Uploads

Ein gängiges Muster: Formular-Uploads eines Nutzers speichern.

store (Dateiname automatisch)

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserAvatarController extends Controller
{
    public function update(Request $request): string
    {
        // Der Dateiname wird auf Basis des MIME-Typs automatisch erzeugt
        $path = $request->file('avatar')->store('avatars');

        return $path;
    }
}

storeAs (Dateiname angeben)

$path = $request->file('avatar')->storeAs(
    'avatars',
    $request->user()->id
);

Upload auf einer bestimmten Disk

// Auf der s3-Disk ablegen
$path = $request->file('avatar')->store(
    'avatars/' . $request->user()->id,
    's3'
);

Upload über die Storage-Facade

use Illuminate\Support\Facades\Storage;

// Dateiname automatisch
$path = Storage::putFile('avatars', $request->file('avatar'));

// Dateiname angeben
$path = Storage::putFileAs(
    'avatars',
    $request->file('avatar'),
    $request->user()->id
);
getClientOriginalName() und getClientOriginalExtension() sind vom Nutzer beeinflussbar und daher nicht sicher. Nutzen Sie stattdessen hashName() für den Dateinamen und extension() für die Endung.
$file = $request->file('avatar');

$name = $file->hashName();   // Eindeutiger, zufälliger Name
$extension = $file->extension(); // Endung aus MIME-Typ

Sichtbarkeit (Visibility)

In Flysystem wird die Sichtbarkeit einer Datei über visibility gesteuert.
use Illuminate\Support\Facades\Storage;

// Sichtbarkeit beim Schreiben angeben
Storage::put('file.jpg', $contents, 'public');

// Sichtbarkeit lesen und setzen
$visibility = Storage::getVisibility('file.jpg');
Storage::setVisibility('file.jpg', 'public');
Um Uploads direkt öffentlich zu speichern, verwenden Sie storePublicly.
$path = $request->file('avatar')->storePublicly('avatars', 's3');

Mehrere Disks nutzen

Mit disk wechseln Sie zwischen den Zielen.
// Auf der Standard-Disk speichern
Storage::put('avatars/1', $content);

// Auf der s3-Disk speichern
Storage::disk('s3')->put('avatars/1', $content);

// Ad-hoc-Disk erstellen
$disk = Storage::build([
    'driver' => 'local',
    'root' => '/path/to/root',
]);
$disk->put('image.jpg', $content);

Cloud-Speicher (S3) konfigurieren

Paket installieren

composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies

Umgebungsvariablen setzen

Legen Sie die Zugangsdaten in Ihrer .env-Datei ab.
AWS_ACCESS_KEY_ID=your-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your-bucket-name
AWS_USE_PATH_STYLE_ENDPOINT=false
Auch S3-kompatible Dienste wie DigitalOcean Spaces, Cloudflare R2 oder Vultr Object Storage lassen sich mit dem s3-Treiber verwenden. Geben Sie in der Option endpoint die URL des Dienstes an.
'endpoint' => env('AWS_ENDPOINT', 'https://your-endpoint.example.com'),

Metadaten von Dateien abfragen

use Illuminate\Support\Facades\Storage;

// Dateigröße (Bytes)
$size = Storage::size('file.jpg');

// Zeitpunkt der letzten Änderung (UNIX-Timestamp)
$time = Storage::lastModified('file.jpg');

// MIME-Typ
$mime = Storage::mimeType('file.jpg');

// Absoluter Pfad (local-Treiber)
$path = Storage::path('file.jpg');

Verzeichnisoperationen

use Illuminate\Support\Facades\Storage;

// Dateien eines Verzeichnisses auflisten
$files = Storage::files($directory);

// Dateien inklusive Unterverzeichnisse
$files = Storage::allFiles($directory);

// Unterverzeichnisse auflisten
$directories = Storage::directories($directory);

// Verzeichnis anlegen
Storage::makeDirectory($directory);

// Verzeichnis inklusive Inhalt löschen
Storage::deleteDirectory($directory);

Testen

Mit Storage::fake() schreiben Sie Tests, ohne echte Dateien anzufassen.
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

test('Avatar kann hochgeladen werden', function () {
    Storage::fake('avatars');

    $file = UploadedFile::fake()->image('avatar.jpg');

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

    // Prüfen, dass die Datei gespeichert wurde
    Storage::disk('avatars')->assertExists('avatar.jpg');

    // Prüfen, dass eine bestimmte Datei nicht gespeichert wurde
    Storage::disk('avatars')->assertMissing('other.jpg');
});
Für UploadedFile::fake()->image() benötigen Sie die GD-Erweiterung von PHP.

Praxisbeispiel: Profilbild hochladen

Ein praxisnaher Controller, der Validierung, Speicherung und das Ablegen des Pfads in der Datenbank kombiniert.
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Storage;

class ProfileController extends Controller
{
    public function updateAvatar(Request $request): RedirectResponse
    {
        $request->validate([
            'avatar' => ['required', 'image', 'max:2048'],
        ]);

        $user = $request->user();

        // Bestehendes Avatar löschen
        if ($user->avatar_path) {
            Storage::disk('public')->delete($user->avatar_path);
        }

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

        // Pfad in der Datenbank ablegen
        $user->update(['avatar_path' => $path]);

        return back()->with('status', 'avatar-updated');
    }
}
Im Template erzeugen Sie die URL über Storage::url().
<img src="{{ Storage::disk('public')->url($user->avatar_path) }}" alt="Avatar">
Zuletzt geändert am 13. Juli 2026