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.

Key Highlights. Prevents path traversal attacks, blocks execution of script-based extensions, enforces secure downloads for vector graphics, performs OOM-safe image resizing, and streams external URLs directly without server-side disk caching.

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
Override Publishing. Use the --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->file resolves 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.

Direct Streaming mechanics. When a client opens the route, the server starts a dynamic stream request, buffering and printing the file bytes directly to the browser. This ensures that:
  • 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:

GET /_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_extensions list, preventing remote code execution (RCE).
  • SVG Sanitization: Image files matching image/svg+xml are blocked from rendering inline. SVG requests are always forced to download as attachments to prevent stored Cross-Site Scripting (XSS).

On This Page