Documentation v1.0.0
Overview
Laravel Uploads is a secure, structured library designed to simplify database-linked file storage, dynamic image optimization, private/expiring URL routing, and on-demand streaming proxy pipelines inside Laravel projects.
Installation
Ensure your environment satisfies the minimum requirements (PHP 8.1+ and Laravel 10 through 13). Install the library via Composer:
composer require ghostcompiler/laravel-uploads
Publish configuration settings and the database migration stub:
php artisan install:laravel-uploads
Run your migrations to generate target database tables:
php artisan migrate
--force flag to overwrite already-published configuration and migration files:
php artisan install:laravel-uploads --force
Configuration Reference
The configuration file publishes to config/laravel-uploads.php. Review the technical behavior of all available options below:
| Key | Type | Default | Description |
|---|---|---|---|
| disk | string | 'local' |
Storage disk prefix configured in config/filesystems.php (e.g., 'local', 's3'). |
| base_path | string | 'LaravelUploads' |
Root directory prefix inside the storage disk where all package uploads are stored. |
| defaults.visibility | string | 'private' |
Default accessibility. 'public' uses direct filesystem URLs. 'private' generates expiring routing tokens. |
| defaults.type | string | 'private' |
Fallback visibility attribute setting for backward compatibility. |
| defaults.id | string | 'hide' |
If set to 'hide', the model trait automatically unsets raw database ID columns from JSON responses. |
| defaults.expiry | int | 60 |
Validity duration (in minutes) for dynamically generated private file route tokens. |
| defaults.expose | bool | true |
If true, serializing Eloquent models appends the resolved URL field dynamically. |
| defaults.variant | string|null | null |
Default output variant settings for uploads (e.g. 'favicon'). |
| cache.enabled | bool | true |
Enables caching of tokenized file URLs to prevent high database link generation loads during API serialization. |
| cache.registry_ttl | int | 60 |
Registry caching lifespan in minutes for mapped token references. |
| validation.max_size | int|null | 10485760 |
Maximum upload size in bytes (default 10MB). Set to null to bypass file size checks. |
| validation.allowed_mime_types | array | [] |
Restricts file uploads to specific MIME types. Keep empty to permit all non-excluded types. |
| validation.allowed_extensions | array | [] |
Restricts file uploads to specific extensions. Keep empty to permit all non-excluded extensions. |
| validation.excluded_extensions | array | [...] |
Script and system types (sh, py, cgi, etc.) blocked by default but overrideable per-upload. |
| validation.never_allowed_extensions | array | [...] |
Strict PHP script targets (php, phar, phtml) that are always blocked and can never be overridden. |
| image_optimization.enabled | bool | false |
When active, converts JPEGs, PNGs, and WEBP uploads to highly compressed AVIF or WEBP images. |
| image_optimization.quality | int | 75 |
Output quality level for compiled graphics (values from 1 to 100). |
| image_optimization.max_width | int|null | null |
Maximum width bound for resizing. Keeps original aspect ratio. |
| image_optimization.max_height | int|null | null |
Maximum height bound for resizing. Keeps original aspect ratio. |
| image_optimization.max_output_pixels | int | 4000000 |
Security boundary checking total pixel count (width * height) to prevent OOM process kills. |
| favicon.size | int | 64 |
Pixel dimensions (width/height square) for favicon compiled variants. |
| downloads.use_original_name | bool | false |
If true, serves the client-uploaded original file name instead of generic upload-{id}.ext. |
| urls.public_resolver | string|null | null |
Optional callback class name to resolve tenant-aware or CDN public asset URLs. |
| preview_mime_types | array | [...] |
MIME types allowed to render inline in browser pages (e.g. PDFs, TXT, JPEGs). Others force attachments. |
| delete_files_with_model | bool | false |
Triggers model lifecycle observers to delete physical files from storage when models delete. |
| route.prefix | string | '_laravel-uploads' |
URL path prefix for serving private files. |
| route.middleware | array | [] |
Route middleware stacks applied to the file-serving endpoint. |
Core Manager APIs
The LaravelUploadsManager class contains all methods to upload, retrieve, check, and delete files.
1. File Uploads
Store files on the destination storage disk using the upload() method.
use GhostCompiler\LaravelUploads\Facades\Uploads;
// basic upload (uses default disk and base path)
$upload = Uploads::upload($request->file('avatar'));
// upload into a specific folder sub-path
$upload = Uploads::upload('users/avatars', $request->file('avatar'));
// upload with configuration override options
$upload = Uploads::upload($request->file('avatar'), [
'visibility' => 'public',
'expiry' => 120, // override expiration to 2 hours
]);
2. Upload Multiple Files
Store an array of files in a single call using uploadMany().
// returns array of GhostCompiler\LaravelUploads\Models\Upload models
$uploads = Uploads::uploadMany($request->file('photos'), 'galleries');
3. Retrieve Uploads
Find an upload record in the database using the find() helper.
$upload = Uploads::find($uploadId); // returns ?Upload model
4. File Deletion
Delete the database record, clear the URL caches, and delete the physical storage file:
// delete by passing the Upload model, ID integer, or ID string
$success = Uploads::remove($uploadId); // returns bool
Eloquent Integration
Apply the GhostCompiler\LaravelUploads\Concerns\LaravelUploads trait to link files to your tables.
use GhostCompiler\LaravelUploads\Concerns\LaravelUploads;
use Illuminate\Database\Eloquent\Model;
class Document extends Model
{
use LaravelUploads;
protected $uploadable = [
'file_id' => [
'name' => 'file',
'type' => 'private',
'expiry' => 15,
],
];
}
Eloquent Features
- Automatic Hiding: The raw database key column (e.g.
file_id) is automatically hidden in array and JSON serialization if configured. - Virtual Attribute resolution: Accessing
$document->fileresolves to the tokenized or public URL directly. - Eloquent Relation mapping: Retrieve the model relationship directly via:
$uploadModel = $document->upload('file_id'); // returns BelongsTo relationship
Custom Hook Methods
Intercept and customize resolved URLs by declaring hook methods in the model.
Field-specific Hooks: Pattern matches set{FieldName}UploadableValue.
public function setAvatarUploadableValue($value, string $column, array $options)
{
// returns the URL customized with URL query parameters
return $value . '?size=thumbnail';
}
Model-wide Hook: Fallback hook pattern matches setUploadableValue.
public function setUploadableValue($value, string $column, array $options)
{
return [
'url' => $value,
'name' => $options['name'],
'visibility' => $options['visibility']
];
}
Dynamic URL Proxying
The package supports uploading external file URLs. Instead of downloading and saving physical files to local/S3 disks, the database stores the reference and proxies the file in real-time when accessed.
1. Storing URLs
// Store a remote image link as a reference
$upload = Uploads::upload('https://avatar.example.com/profiles/avatar.jpg');
// Storing under custom path/directory settings
$upload = Uploads::upload('avatars', 'https://avatar.example.com/avatar.jpg', [
'visibility' => 'private'
]);
2. Serving URLs
When resolving URL-based uploads, the package routes the path through the secure package route /_laravel-uploads/file/{token}. The client browser never sees the original remote URL.
- No temporary local file is saved to the hosting server.
- No local memory cache is occupied.
- If the file contents update on the remote provider under the same URL (e.g. OAuth avatar updates), the user sees the changes instantly.
Resolving URLs
Resolve file URLs using the manager instances:
// 1. Resolve URL from an Upload instance
$url = Uploads::url($upload, 30); // 30 minutes token expiration
// 2. Resolve URL from an Upload ID database column
$url = Uploads::urlFromId($uploadId, 60); // 60 minutes token expiration
// 3. Register a public URL resolver callback (useful for CDN hosting or Multi-tenant apps)
Uploads::resolvePublicUrlsUsing(function ($upload, $disk, $path) {
return "https://cdn.my-app.com/{$path}";
});
Artisan Commands
The package registers console commands for maintenance:
Prune Expired Links
Prunes all expired temporary token links from the laravel_uploads_links table:
php artisan ghost:laravel-uploads-clean
Run a dry run execution to review the count of deletable records without pruning them:
php artisan ghost:laravel-uploads-clean --dry-run
Route & Serving Mechanics
Files are served securely through the dynamic endpoint:
/_laravel-uploads/file/{token}Routing Options
Modify route attributes inside config/laravel-uploads.php:
route.prefix: Customize the serving prefix (default'_laravel-uploads').route.name: Customize the route name (default'laravel-uploads.show').route.middleware: Apply middleware checks (e.g.,'auth') to restrict file access to authenticated sessions.
Download Control
Force download disposition on previewable file types (PDFs, images) by appending the query parameter:
GET /_laravel-uploads/file/{token}?download=1
Security Defaults
The package implements multiple default security standards:
- Traversal Prevention: Path segments containing directory modifications (
..,.) are parsed and blocked immediately to prevent directory escaping. - File Type Constraints: PHP files and scripts are restricted globally via the
never_allowed_extensionslist, preventing remote code execution (RCE). - SVG Sanitization: Image files matching
image/svg+xmlare blocked from rendering inline. SVG requests are always forced to download as attachments to prevent stored Cross-Site Scripting (XSS).