Master secure file uploads in Laravel REST APIs. Learn to validate binary data, use the Filesystem abstraction, and associate files with your Eloquent models.
Previously in this course, we explored Handling API Validation and Form Requests. While that lesson focused on standard request payloads, today we’re moving into binary data. We’ll cover how to securely accept, store, and link files to your project board entities.
In a production environment, you should never hardcode file paths or manipulate the local disk directly. Laravel provides the Illuminate\Support\Facades\Storage facade, which acts as a filesystem abstraction layer. Whether you are storing files on your local server, an S3 bucket, or an SFTP server, your code remains identical.
When building a REST API, files arrive as multipart/form-data. Because these requests are inherently larger and potentially malicious, we treat them with higher scrutiny than standard JSON payloads.
Before storing a file, validation is non-negotiable. You must enforce constraints on file size and MIME types to prevent users from uploading executable scripts or exhausting your server’s disk space.
Building upon our project board, let’s add a feature to attach files to tasks. First, create a StoreTaskAttachmentRequest:
PHP#6A9955">// app/Http/Requests/StoreTaskAttachmentRequest.php public function rules(): array { return [ 'attachment' => [ 'required', 'file', 'mimes:jpg,png,pdf', 'max:2048' #6A9955">// 2MB limit ], ]; }
Once validated, we use the store method. This method handles filename hashing (to prevent collisions) and returns the relative path to the file.
PHP#6A9955">// Inside your TaskService public function addAttachment(Task $task, UploadedFile $file): Attachment { #6A9955">// Store in the 'attachments' directory on the 'public' disk $path = $file->store('attachments', 'public'); return $task->attachments()->create([ 'path' => $path, 'original_name' => $file->getClientOriginalName(), 'mime_type' => $file->getClientMimeType(), ]); }
In a relational database, you shouldn't store the file itself in a BLOB column. Instead, store the metadata (path, original name, size) in a dedicated attachments table.
task_id, path, and original_name.hasMany relationship on your Task model.public disk if the files need to be accessible via URL, or the local disk for private, server-only files.attachments table with a task_id foreign key and a path string column.TaskAttachmentController and inject your TaskService.POST /tasks/{task}/attachments.store method to save the file and persist the metadata to the database.storage/app/public/attachments.storage/ directory is writable by the web server (usually www-data).store() method automatically generates a unique hash, which is exactly what you want to prevent directory traversal attacks.Storage::url($path) to generate links. If you switch to S3 later, this method will automatically generate the correct signed URL without you changing a single line of business logic.php.ini (upload_max_filesize and post_max_size) matches your validation rules.We’ve moved from simple JSON requests to handling binary data securely. By utilizing Laravel’s Storage facade, we've decoupled our application from the underlying storage mechanism. We ensure security through strict FormRequest validation and maintain database integrity by storing metadata rather than raw binary data.
Up next: We will implement Job Chaining and Batching to handle post-processing (like image resizing) for these file uploads in the background.
Master scalable file uploads in Laravel. Learn to stream directly to S3 and process heavy files asynchronously to keep your application fast and memory-efficient.
Read moreLearn to build production-ready integrations by validating webhook signatures and offloading processing to queues to ensure security and system reliability.
Handling File Uploads in REST APIs