laravel-files/docs/uploading.md

3.9 KiB

Uploading Files

The package provides a complete upload API with support for single-file uploads and chunked uploads for large files.

Single File Upload

Endpoint

POST /api/files/upload

Middleware: api, auth:sanctum (configurable)

Request

Send a multipart form upload with a file field:

curl -X POST https://app.test/api/files/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@photo.jpg"

Validation

  • Max size: 50 MB (configurable via files.upload.max_size)
  • Allowed MIME types: all by default; restrict via files.upload.allowed_mimes
// config/files.php
'upload' => [
    'max_size'      => 50 * 1024, // KB
    'allowed_mimes' => ['jpg', 'png', 'pdf', 'docx'], // empty = allow all
],

Response (201)

{
    "id": "9c3a...",
    "name": "photo",
    "type": "image/jpeg",
    "extension": "jpg",
    "size": 245760,
    "size_human": "240 KB",
    "url": "https://app.test/warehouse/9c3a..."
}

Chunked Upload

For large files that exceed browser or server limits, use the chunked upload flow.

Step 1: Initialize

POST /api/files/chunk/init

Body (JSON):

{
    "filename": "video.mp4",
    "filesize": 104857600,
    "total_chunks": 100,
    "mime_type": "video/mp4",
    "extension": "mp4"
}

Response (201):

{
    "upload_id": "9c3a...",
    "file_id": "9c3a...",
    "total_chunks": 100
}

Step 2: Upload Chunks

POST /api/files/chunk/upload

Send each chunk as a multipart upload or raw body:

curl -X POST https://app.test/api/files/chunk/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "upload_id=9c3a..." \
  -F "chunk_index=0" \
  -F "chunk=@chunk_0.bin"

Response:

{
    "upload_id": "9c3a...",
    "chunk_index": 0,
    "received": 1,
    "total_chunks": 100,
    "complete": false
}

When the last chunk is received (complete: true), all chunks are automatically assembled into the final file.

Step 3: Done

No finalization call needed. The file is ready to use once complete is true. The temporary chunk files are cleaned up automatically.


Upload Sessions

Chunk upload sessions are stored in the application cache and expire after 24 hours. If a session expires before all chunks are received, the upload must be restarted.


Real-Time Progress

If laravel-websockets is installed, a ChunkUploadProgress event is broadcast after each chunk:

// Event payload
[
    'uploadId'   => '9c3a...',
    'chunkIndex' => 42,
    'totalChunks' => 100,
    'complete'   => false,
]

Listen on the client side to show upload progress bars.


Upload via the HasFiles Trait

When working with models that use HasFiles, you can upload and attach in a single call:

// From a form upload
$file = $product->uploadFile(
    $request->file('photo'),
    as: FileLinkType::Gallery,
);

// From raw content
$file = $product->uploadFileFromContents(
    contents: $csvData,
    name: 'export',
    extension: 'csv',
    as: FileLinkType::Document,
);

// From a URL
$file = $product->uploadFileFromUrl(
    url: 'https://cdn.example.com/image.jpg',
    as: FileLinkType::Banner,
    replace: true,
);

See Attaching Files for full parameter details.


Route Configuration

Customize upload route prefix and middleware in config/files.php:

'upload' => [
    'route_prefix' => 'api/files',
    'middleware'    => ['api', 'auth:sanctum'],
],

Routes registered:

Method URI Name
POST {prefix}/upload files.upload
POST {prefix}/chunk/init files.chunk.init
POST {prefix}/chunk/upload files.chunk.upload

Next: Serving Files