파일 저장소

번역일: 2026년 6월 25일

파일 저장소

소개

Laravel은 Frank de Jonge가 만든 Flysystem PHP 패키지를 기반으로 강력한 파일시스템 추상화 레이어를 제공합니다. 로컬 파일시스템, SFTP, Amazon S3 등 다양한 저장소를 동일한 API로 다룰 수 있기 때문에, 로컬 개발 환경과 운영 서버 간에 드라이버를 전환할 때도 코드를 거의 수정할 필요가 없습니다.

설정

파일시스템 설정 파일은 config/filesystems.php에 위치합니다. 이 파일에서 "디스크(disk)"라고 부르는 저장소 단위를 여러 개 정의할 수 있습니다. 각 디스크는 특정 드라이버와 저장 위치를 나타내며, 지원되는 드라이버별 예시 설정이 파일에 이미 포함되어 있습니다. 필요에 맞게 수정해서 사용하면 됩니다.

local 드라이버는 Laravel 애플리케이션이 실행되는 서버의 로컬 파일을 다루고, s3 드라이버는 Amazon S3 클라우드 저장소에 파일을 읽고 씁니다.

NOTE

같은 드라이버를 사용하는 디스크를 여러 개 정의하는 것도 가능합니다. 프로젝트 요구에 따라 디스크를 자유롭게 구성하세요.

로컬 드라이버

local 드라이버를 사용하면 모든 파일 작업은 filesystems 설정 파일에 정의된 root 디렉터리를 기준으로 수행됩니다. 기본값은 storage/app입니다. 따라서 아래 코드는 storage/app/example.txt에 파일을 씁니다.

use Illuminate\Support\Facades\Storage; Storage::disk('local')->put('example.txt', '파일 내용');

퍼블릭 디스크

public 디스크는 외부에서 접근 가능한 파일을 저장하기 위한 디스크입니다. 기본 설정으로는 local 드라이버를 사용하며, 파일은 storage/app/public 디렉터리에 저장됩니다.

웹에서 이 파일들에 접근하려면 public/storage에서 storage/app/public으로 심볼릭 링크를 생성해야 합니다. 이 방식은 Envoyer 같은 무중단 배포 도구를 사용할 때도 공개 파일을 하나의 디렉터리에서 일관되게 관리할 수 있어 편리합니다.

심볼릭 링크는 다음 Artisan 명령으로 생성합니다.

php artisan storage:link

링크를 생성한 뒤에는 asset 헬퍼로 파일의 URL을 만들 수 있습니다.

echo asset('storage/file.txt');

filesystems 설정 파일에서 추가 심볼릭 링크를 더 정의할 수도 있습니다. storage:link 명령 실행 시 설정된 모든 링크가 함께 생성됩니다.

'links' => [ public_path('storage') => storage_path('app/public'), public_path('images') => storage_path('app/images'), ],

심볼릭 링크를 제거하려면 storage:unlink 명령을 사용합니다.

php artisan storage:unlink

드라이버 사전 준비

S3 드라이버 설정

S3 드라이버를 사용하기 전에 Composer로 Flysystem S3 패키지를 설치해야 합니다.

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

S3 드라이버 설정은 config/filesystems.php에 예시 배열이 포함되어 있습니다. 이 배열을 자신의 S3 자격 증명과 설정에 맞게 수정하면 됩니다. 환경 변수 이름은 AWS CLI의 명명 규칙을 따릅니다.

FTP 드라이버 설정

FTP 드라이버를 사용하기 전에 Composer로 Flysystem FTP 패키지를 설치해야 합니다.

composer require league/flysystem-ftp "^3.0"

Laravel의 기본 filesystems.php에는 FTP 예시 설정이 포함되어 있지 않습니다. 아래 예시를 참고해 직접 추가하세요.

'ftp' => [ 'driver' => 'ftp', 'host' => env('FTP_HOST'), 'username' => env('FTP_USERNAME'), 'password' => env('FTP_PASSWORD'), // 선택적 FTP 설정... // 'port' => env('FTP_PORT', 21), // 'root' => env('FTP_ROOT'), // 'passive' => true, // 'ssl' => true, // 'timeout' => 30, ],

SFTP 드라이버 설정

SFTP 드라이버를 사용하기 전에 Composer로 Flysystem SFTP 패키지를 설치해야 합니다.

composer require league/flysystem-sftp-v3 "^3.0"

마찬가지로 기본 filesystems.php에는 SFTP 예시가 없습니다. 아래 예시를 참고해 추가하세요.

'sftp' => [ 'driver' => 'sftp', 'host' => env('SFTP_HOST'), // 기본 인증 설정... 'username' => env('SFTP_USERNAME'), 'password' => env('SFTP_PASSWORD'), // SSH 키 기반 인증 설정... 'privateKey' => env('SFTP_PRIVATE_KEY'), 'passphrase' => env('SFTP_PASSPHRASE'), // 파일/디렉터리 권한 설정... 'visibility' => 'private', // `private` = 0600, `public` = 0644 'directory_visibility' => 'private', // `private` = 0700, `public` = 0755 // 선택적 SFTP 설정... // 'hostFingerprint' => env('SFTP_HOST_FINGERPRINT'), // 'maxTries' => 4, // 'port' => env('SFTP_PORT', 22), // 'root' => env('SFTP_ROOT', ''), // 'timeout' => 30, // 'useAgent' => true, ],

범위 지정 및 읽기 전용 파일시스템

범위 지정 디스크(Scoped Disk) 를 사용하면 모든 경로 앞에 지정한 접두사가 자동으로 붙습니다. 이 기능을 사용하려면 먼저 아래 패키지를 설치하세요.

composer require league/flysystem-path-prefixing "^3.0"

scoped 드라이버를 사용해 기존 디스크에 경로 접두사를 지정한 새 디스크를 정의할 수 있습니다. 예를 들어 기존 s3 디스크의 특정 경로만을 사용하는 디스크를 만들 수 있습니다.

's3-videos' => [ 'driver' => 'scoped', 'disk' => 's3', 'prefix' => 'path/to/videos', ],

읽기 전용 디스크(Read-Only Disk) 는 쓰기 작업을 허용하지 않는 디스크입니다. 이 기능을 사용하려면 아래 패키지를 먼저 설치하세요.

composer require league/flysystem-read-only "^3.0"

그런 다음 디스크 설정 배열에 read-only 옵션을 추가합니다.

's3-videos' => [ 'driver' => 's3', // ... 'read-only' => true, ],

Amazon S3 호환 파일시스템

기본 filesystems 설정에는 s3 디스크 설정이 포함되어 있습니다. 이 디스크는 Amazon S3 외에도 MinIO, DigitalOcean Spaces 등 S3 호환 저장 서비스와도 함께 사용할 수 있습니다.

보통은 서비스의 자격 증명에 맞게 값을 변경하고, endpoint 옵션만 수정하면 됩니다. 이 값은 보통 AWS_ENDPOINT 환경 변수로 지정합니다.

'endpoint' => env('AWS_ENDPOINT', 'https://minio:9000'),

MinIO

MinIO 사용 시 Laravel Flysystem이 올바른 URL을 생성하려면 AWS_URL 환경 변수를 애플리케이션 로컬 URL과 버킷 이름이 포함된 경로로 설정해야 합니다.

AWS_URL=http://localhost:9000/local

WARNING

MinIO를 사용할 경우 temporaryUrl 메서드를 통한 임시 저장 URL 생성은 지원되지 않습니다.

디스크 인스턴스 가져오기

Storage 파사드를 통해 설정된 디스크와 상호작용할 수 있습니다. disk 메서드를 호출하지 않으면 기본 디스크가 자동으로 사용됩니다.

use Illuminate\Support\Facades\Storage; Storage::put('avatars/1', $content); // 기본 디스크 사용

여러 디스크를 사용하는 애플리케이션이라면 disk 메서드로 특정 디스크를 명시할 수 있습니다.

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

온디맨드 디스크

설정 파일에 미리 정의하지 않고 런타임에 동적으로 디스크를 생성하고 싶다면, Storage 파사드의 build 메서드에 설정 배열을 전달하면 됩니다.

use Illuminate\Support\Facades\Storage; $disk = Storage::build([ 'driver' => 'local', 'root' => '/path/to/root', ]); $disk->put('image.jpg', $content);

파일 조회

get 메서드로 파일의 내용을 문자열로 가져올 수 있습니다. 모든 파일 경로는 디스크의 root를 기준으로 한 상대 경로로 지정합니다.

$contents = Storage::get('file.jpg');

JSON 파일을 읽고 바로 디코딩하려면 json 메서드를 사용하세요.

$orders = Storage::json('orders.json');

파일의 존재 여부는 existsmissing 메서드로 확인할 수 있습니다.

if (Storage::disk('s3')->exists('file.jpg')) { // 파일이 존재하는 경우... } if (Storage::disk('s3')->missing('file.jpg')) { // 파일이 없는 경우... }

파일 다운로드

download 메서드는 브라우저가 지정한 경로의 파일을 즉시 다운로드하도록 응답을 반환합니다. 두 번째 인수로 다운로드 시 사용자에게 보일 파일명, 세 번째 인수로 HTTP 헤더 배열을 전달할 수 있습니다.

return Storage::download('file.jpg'); return Storage::download('file.jpg', $name, $headers);

파일 URL

url 메서드로 파일의 URL을 가져올 수 있습니다. local 드라이버를 사용하면 경로 앞에 /storage가 붙은 상대 URL이 반환되고, s3 드라이버를 사용하면 원격 파일의 전체 URL이 반환됩니다.

use Illuminate\Support\Facades\Storage; $url = Storage::url('file.jpg');

local 드라이버를 사용할 때 외부에 공개해야 하는 파일은 반드시 storage/app/public 디렉터리에 저장하고, 심볼릭 링크가 생성되어 있어야 합니다.

WARNING

local 드라이버에서 url의 반환값은 URL 인코딩이 적용되지 않습니다. 따라서 유효한 URL을 구성할 수 있는 파일명으로 저장하는 것을 권장합니다.

URL 호스트 커스터마이징

Storage 파사드로 생성되는 URL의 호스트를 미리 지정하고 싶다면 디스크 설정 배열에 url 옵션을 추가하세요.

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

임시 URL

s3 드라이버로 저장된 파일에 대해 temporaryUrl 메서드를 사용하면 일정 시간 후 만료되는 임시 URL을 생성할 수 있습니다. 경로와 만료 시각(DateTime 인스턴스)을 인수로 전달합니다.

use Illuminate\Support\Facades\Storage; $url = Storage::temporaryUrl( 'file.jpg', now()->addMinutes(5) );

추가적인 S3 요청 파라미터가 필요하다면 세 번째 인수로 배열을 전달하세요.

$url = Storage::temporaryUrl( 'file.jpg', now()->addMinutes(5), [ 'ResponseContentType' => 'application/octet-stream', 'ResponseContentDisposition' => 'attachment; filename=file2.jpg', ] );

임시 URL 생성 방식을 특정 디스크에 맞게 커스터마이징해야 한다면 buildTemporaryUrlsUsing 메서드를 사용할 수 있습니다. 예를 들어 임시 URL을 기본적으로 지원하지 않는 디스크에서 파일을 다운로드하는 컨트롤러가 있을 때 유용합니다. 보통 서비스 프로바이더의 boot 메서드에서 호출합니다.

<?php namespace App\Providers; use DateTime; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Storage::disk('local')->buildTemporaryUrlsUsing( function (string $path, DateTime $expiration, array $options) { return URL::temporarySignedRoute( 'files.download', $expiration, array_merge($options, ['path' => $path]) ); } ); } }

임시 업로드 URL

WARNING

임시 업로드 URL 생성은 s3 드라이버에서만 지원됩니다.

클라이언트 측 애플리케이션에서 클라우드 저장소(예: Amazon S3)에 직접 파일을 업로드할 수 있는 임시 URL이 필요하다면 temporaryUploadUrl 메서드를 사용하세요. 이 메서드는 경로와 만료 시각을 인수로 받아 업로드 URL과 함께 요청 시 포함해야 할 헤더를 연관 배열로 반환합니다.

use Illuminate\Support\Facades\Storage; ['url' => $url, 'headers' => $headers] = Storage::temporaryUploadUrl( 'file.jpg', now()->addMinutes(5) );

이 방식은 서버리스 환경에서 클라이언트가 클라우드 저장소에 직접 업로드해야 할 때 주로 활용됩니다.

파일 메타데이터

파일 내용 외에도 파일 자체에 대한 정보를 조회할 수 있습니다.

use Illuminate\Support\Facades\Storage; $size = Storage::size('file.jpg'); // 파일 크기 (바이트) $time = Storage::lastModified('file.jpg'); // 마지막 수정 시각 (UNIX 타임스탬프) $mime = Storage::mimeType('file.jpg'); // MIME 타입

파일 경로

path 메서드는 파일의 경로를 반환합니다. local 드라이버에서는 절대 경로를, s3 드라이버에서는 버킷 내 상대 경로를 반환합니다.

use Illuminate\Support\Facades\Storage; $path = Storage::path('file.jpg');

파일 저장

put 메서드로 파일 내용을 디스크에 저장할 수 있습니다. PHP resource를 전달하면 Flysystem의 스트림 기능을 활용합니다. 경로는 디스크의 root를 기준으로 한 상대 경로로 지정합니다.

use Illuminate\Support\Facades\Storage; Storage::put('file.jpg', $contents); Storage::put('file.jpg', $resource);

쓰기 실패 처리

파일 쓰기에 실패하면 put 메서드는 false를 반환합니다.

if (! Storage::put('file.jpg', $contents)) { // 파일을 디스크에 쓸 수 없는 경우... }

쓰기 실패 시 예외를 발생시키고 싶다면 디스크 설정 배열에 throw 옵션을 true로 지정하세요. 이 경우 쓰기 실패 시 League\Flysystem\UnableToWriteFile 예외가 던져집니다.

'public' => [ 'driver' => 'local', // ... 'throw' => true, ],

파일 앞/뒤에 내용 추가

prependappend 메서드로 파일의 처음 또는 끝에 내용을 추가할 수 있습니다.

Storage::prepend('file.log', '파일 앞에 추가할 내용'); Storage::append('file.log', '파일 뒤에 추가할 내용');

파일 복사 및 이동

copy 메서드는 기존 파일을 새 위치에 복사하고, move 메서드는 파일을 새 위치로 이동하거나 이름을 변경합니다.

Storage::copy('old/file.jpg', 'new/file.jpg'); Storage::move('old/file.jpg', 'new/file.jpg');

자동 스트리밍

파일을 스트리밍 방식으로 저장하면 메모리 사용량을 크게 줄일 수 있습니다. putFile 또는 putFileAs 메서드를 사용하면 Laravel이 자동으로 스트리밍을 처리합니다. 이 메서드는 Illuminate\Http\File 또는 Illuminate\Http\UploadedFile 인스턴스를 받아 지정한 위치에 파일을 저장합니다.

use Illuminate\Http\File; use Illuminate\Support\Facades\Storage; // 파일명을 자동으로 고유한 ID로 생성... $path = Storage::putFile('photos', new File('/path/to/photo')); // 파일명을 직접 지정... $path = Storage::putFileAs('photos', new File('/path/to/photo'), 'photo.jpg');

putFile 메서드는 디렉터리명만 지정하면 되며, 파일명은 자동으로 고유한 ID로 생성됩니다. 확장자는 파일의 MIME 타입을 기반으로 결정됩니다. 메서드는 생성된 파일명을 포함한 전체 경로를 반환하므로, 데이터베이스에 저장할 수 있습니다.

putFileputFileAs 모두 파일의 공개 범위(visibility)를 세 번째 인수로 지정할 수 있습니다. Amazon S3 같은 클라우드 디스크에 공개 접근 가능한 파일로 저장할 때 유용합니다.

Storage::putFile('photos', new File('/path/to/photo'), 'public');

파일 업로드

웹 애플리케이션에서 파일 업로드는 가장 흔한 파일 저장 사례입니다. Laravel은 업로드된 파일 인스턴스의 store 메서드를 통해 파일을 간단하게 저장할 수 있습니다.

<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class UserAvatarController extends Controller { /** * 사용자의 아바타 이미지를 업데이트합니다. */ public function update(Request $request): string { $path = $request->file('avatar')->store('avatars'); return $path; } }

여기서도 putFile과 마찬가지로 디렉터리명만 지정하면 파일명은 자동으로 고유한 ID로 생성됩니다. Storage 파사드의 putFile 메서드로도 동일한 동작을 수행할 수 있습니다.

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

파일명 직접 지정

파일명을 자동 생성하지 않고 직접 지정하려면 storeAs 메서드를 사용하세요. 인수로 경로, 파일명, (선택적으로) 디스크명을 전달합니다.

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

Storage 파사드의 putFileAs 메서드도 동일한 기능을 합니다.

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

WARNING

출력 불가능한 문자나 잘못된 유니코드 문자는 파일 경로에서 자동으로 제거됩니다. 따라서 파일 경로를 Laravel의 파일 저장 메서드에 전달하기 전에 직접 정제(sanitize)하는 것을 권장합니다. 경로 정규화는 League\Flysystem\WhitespacePathNormalizer::normalizePath 메서드로 처리됩니다.

디스크 지정

업로드 파일의 store 메서드는 기본적으로 기본 디스크를 사용합니다. 다른 디스크를 사용하려면 두 번째 인수로 디스크명을 전달하세요.

$path = $request->file('avatar')->store( 'avatars/'

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 25일