PHPackages                             mohamedsamy902/advanced-file-upload - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [File &amp; Storage](/categories/file-storage)
4. /
5. mohamedsamy902/advanced-file-upload

ActiveLibrary[File &amp; Storage](/categories/file-storage)

mohamedsamy902/advanced-file-upload
===================================

A production-grade, security-hardened media management &amp; chunked file upload package for Laravel.

v5.1.0(1w ago)7963MITPHPPHP ^8.1CI passing

Since Apr 7Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/MohamedSamy902/upload-file-chunk)[ Packagist](https://packagist.org/packages/mohamedsamy902/advanced-file-upload)[ Docs](https://github.com/MohamedSamy902/laravel-media-vault)[ RSS](/packages/mohamedsamy902-advanced-file-upload/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (20)Versions (9)Used By (0)

Advanced File Upload
====================

[](#advanced-file-upload)

A production-ready Laravel package for chunked uploads, image processing, URL downloads, multi-cloud storage, and resumable file transfers.

[![PHP](https://camo.githubusercontent.com/7535257ca228724c93658bd52583d4e47a9bab02c356abf6e54c1d575f2151e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c75652e737667)](https://php.net)[![Laravel](https://camo.githubusercontent.com/57b3a863c6bd691c3566277f0e9aaa31fdb411989eaf71edfb4249e03303e535/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31302532302537432532303131253230253743253230313225323025374325323031332d7265642e737667)](https://laravel.com)[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](https://opensource.org/licenses/MIT)[![Tests](https://github.com/MohamedSamy902/upload-file-chunk/actions/workflows/tests.yml/badge.svg)](https://github.com/MohamedSamy902/upload-file-chunk/actions)

Contents
--------

[](#contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
    - [Single File Upload](#single-file-upload)
    - [Batch Upload](#batch-upload)
    - [URL Download and Upload](#url-download-and-upload)
    - [Resumable Chunked Upload](#resumable-chunked-upload)
    - [Image Processing](#image-processing)
    - [CDN URL Rewriting](#cdn-url-rewriting)
    - [Deleting Files](#deleting-files)
    - [HasUploads Trait](#hasuploads-trait)
- [Media Manager Dashboard (SPA)](#media-manager-dashboard-spa)
- [Security](#security)
- [Events](#events)
- [Testing](#testing)
- [Changelog](#changelog)
- [Contributing](#contributing)
- [License](#license)

---

Requirements
------------

[](#requirements)

RequirementVersionPHP^8.1Laravel&gt;=10.0Intervention Image^3.0GD or ImagickRequired for image processing---

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require mohamedsamy902/advanced-file-upload
```

Publish the configuration file:

```
php artisan vendor:publish --provider="MohamedSamy902\AdvancedFileUpload\AdvancedFileUploadServiceProvider" --tag=config
```

Publish and run the database migrations (required for file tracking or resumable uploads):

```
php artisan vendor:publish --provider="MohamedSamy902\AdvancedFileUpload\AdvancedFileUploadServiceProvider" --tag=migrations
php artisan migrate
```

For cloud storage, install the appropriate adapter:

```
# Amazon S3
composer require league/flysystem-aws-s3-v3

# Google Cloud Storage
composer require spatie/laravel-google-cloud-storage
```

---

Configuration
-------------

[](#configuration)

After publishing, the configuration file is located at `config/file-upload.php`.

The key sections are:

```
return [
    'storage' => [
        'disk'           => env('FILE_UPLOAD_DISK', 'public'),
        'path'           => env('FILE_UPLOAD_PATH', 'uploads'),
        'default_folder' => null,
        'cdn' => [
            'enabled' => env('FILE_UPLOAD_CDN_ENABLED', false),
            'url'     => env('FILE_UPLOAD_CDN_URL', ''),
        ],
    ],

    'url_upload' => [
        'allowed_domains' => [],        // empty = allow all public domains
        'timeout_seconds' => 10,
        'max_size_bytes'  => 52428800,  // 50 MB
    ],

    'image_driver' => env('FILE_UPLOAD_IMAGE_DRIVER', 'gd'),  // 'gd' or 'imagick'

    'processing' => [
        'image' => [
            'enabled'    => false,
            'convert_to' => null,       // 'webp', 'jpg', 'png'
            'quality'    => 85,
            'max_width'  => 1920,
            'max_height' => null,
            'upsize'     => false,
        ],
    ],

    'thumbnails' => [
        'enabled' => false,
        'sizes'   => [
            'sm' => ['width' => 150, 'height' => 150, 'crop' => true],
            'md' => ['width' => 400, 'height' => 400, 'crop' => false],
        ],
    ],

    'quota' => [
        'enabled'   => false,
        'per_user'  => 1073741824, // 1 GB
    ],

    'chunked' => [
        'session_ttl_hours' => 24,
    ],

    'database' => [
        'enabled' => false,
        'model'   => \MohamedSamy902\AdvancedFileUpload\Models\FileUpload::class,
    ],
];
```

---

Usage
-----

[](#usage)

### Single File Upload

[](#single-file-upload)

```
use MohamedSamy902\AdvancedFileUpload\Facades\FileUpload;

public function store(Request $request)
{
    $result = FileUpload::upload($request->file('avatar'));

    // $result is a typed value object
    return response()->json([
        'path' => $result->path,
        'url'  => $result->url,
        'type' => $result->type, // image | video | audio | pdf | document | other
    ]);
}
```

The return value is an `UploadResult` object with these properties:

PropertyTypeDescription`status``bool`Whether the upload succeeded`path``string`Storage path relative to the disk root`url``string`Public URL (with CDN rewriting if enabled)`originalName``string`The original client filename`mimeType``string`The detected MIME type`type``string`Logical category: image, video, audio, pdf, document, other`size``intnull``thumbnailUrls``array`Map of thumbnail size name to URL`databaseId``intnull``UploadResult` also implements `ArrayAccess`, so existing code using array syntax continues to work:

```
$result = FileUpload::upload($file);
$path = $result['path'];    // still works
$url  = $result['url'];     // still works
```

---

### Batch Upload

[](#batch-upload)

Pass an array of files. Failed items return an error array without interrupting the batch.

```
use MohamedSamy902\AdvancedFileUpload\ValueObjects\UploadResult;

$files   = $request->file('documents');
$results = FileUpload::upload($files, [
    'folder_name'      => 'reports',
    'validation_rules' => ['file' => 'required|file|mimes:pdf,docx|max:10240'],
]);

foreach ($results as $result) {
    if ($result instanceof UploadResult) {
        // success
        echo $result->url;
    } else {
        // failure — $result is an array with 'status', 'error', 'original_name'
        echo $result['error'];
    }
}
```

---

### URL Download and Upload

[](#url-download-and-upload)

Download a remote file and store it, with SSRF protection applied before any HTTP request.

```
$result = FileUpload::uploadFromUrl('https://cdn.example.com/photo.jpg', [
    'folder_name' => 'avatars',
]);
```

Multiple URLs in a single call:

```
$results = FileUpload::uploadFromUrl([
    'https://cdn.example.com/image1.jpg',
    'https://cdn.example.com/image2.jpg',
    'https://cdn.example.com/image3.jpg',
], [
    'folder_name' => 'gallery',
]);
```

**Restricting permitted domains:**

```
// config/file-upload.php
'url_upload' => [
    'allowed_domains' => ['cdn.myapp.com', 'assets.partner.com'],
],
```

---

### Resumable Chunked Upload

[](#resumable-chunked-upload)

When a client uploads a large file and the connection is interrupted, the upload can resume from the last successful chunk without starting over.

**Step 1 — Start a session on your backend:**

```
use MohamedSamy902\AdvancedFileUpload\Services\ResumableUploadService;

public function startUpload(Request $request, ResumableUploadService $service)
{
    $session = $service->startSession(
        originalName: $request->input('filename'),
        mimeType:     $request->input('mime_type'),
        totalSize:    (int) $request->input('total_size'),
        totalChunks:  (int) $request->input('total_chunks'),
        folder:       'uploads',
    );

    return response()->json(['session_id' => $session->session_id]);
}
```

**Step 2 — Send each chunk:**

```
public function uploadChunk(Request $request, ResumableUploadService $service)
{
    $state = $service->uploadChunk(
        sessionId:  $request->input('session_id'),
        chunkIndex: (int) $request->input('chunk_index'),
        chunk:      $request->file('chunk'),
    );

    return response()->json($state);
    // {"received": 3, "total": 10, "missing": [3, 4, 5, 6, 7, 8, 9]}
}
```

**Step 3 — Resume after a failure:**

The client queries which chunks are still missing:

```
public function sessionStatus(string $sessionId, ResumableUploadService $service)
{
    return response()->json($service->getSession($sessionId));
    // {"session_id": "...", "status": "pending", "received": 3, "total": 10, "missing": [3, 4, ...]}
}
```

The client re-sends only the missing chunks, then calls complete.

**Step 4 — Assemble and store:**

```
public function completeUpload(Request $request, ResumableUploadService $service)
{
    $result = $service->completeSession($request->input('session_id'));

    return response()->json([
        'path' => $result->path,
        'url'  => $result->url,
    ]);
}
```

---

### Image Processing

[](#image-processing)

Enable image processing in the configuration:

```
'processing' => [
    'image' => [
        'enabled'    => true,
        'convert_to' => 'webp',   // convert all uploads to WebP
        'quality'    => 85,
        'max_width'  => 1920,
        'upsize'     => false,    // never enlarge images smaller than max_width
    ],
],
```

Override per request:

```
$result = FileUpload::upload($file, [
    'convert_to' => 'jpg',
    'quality'    => 75,
]);
```

**Watermark:**

```
// config/file-upload.php
'processing' => [
    'image' => [
        'enabled'    => true,
        'watermark'  => [
            'enabled'   => true,
            'path'      => storage_path('app/watermark.png'),
            'position'  => 'bottom-right',
            'opacity'   => 50,
        ],
    ],
],
```

**Thumbnails:**

```
'thumbnails' => [
    'enabled' => true,
    'sizes'   => [
        'sm' => ['width' => 150, 'height' => 150, 'crop' => true],
        'md' => ['width' => 400, 'height' => 400, 'crop' => false],
        'lg' => ['width' => 800, 'height' => null, 'crop' => false],
    ],
],
```

The thumbnail URLs are available in the result:

```
$result = FileUpload::upload($imageFile);
echo $result->thumbnailUrls['sm']; // https://cdn.myapp.com/uploads/thumbs/sm_uuid.webp
echo $result->thumbnailUrls['md'];
```

---

### CDN URL Rewriting

[](#cdn-url-rewriting)

When a CDN is configured, all generated URLs are automatically rewritten:

```
// config/file-upload.php
'storage' => [
    'cdn' => [
        'enabled' => true,
        'url'     => 'https://cdn.myapp.com',
    ],
],
```

```
$result = FileUpload::upload($file);
echo $result->url;
// https://cdn.myapp.com/uploads/uuid.jpg
```

---

### Deleting Files

[](#deleting-files)

By storage path (when database tracking is disabled):

```
FileUpload::delete('uploads/uuid.jpg');
```

By database record ID (when tracking is enabled):

```
FileUpload::delete(42);
```

Delete multiple files. Partial failures do not abort the batch:

```
$results = FileUpload::delete([
    'uploads/file1.jpg',
    'uploads/file2.pdf',
    'uploads/file3.mp4',
]);

foreach ($results as $result) {
    if (!$result['status']) {
        logger()->error($result['error']);
    }
}
```

---

### HasUploads Trait

[](#hasuploads-trait)

You can attach the `HasUploads` trait to any Eloquent model to automatically retrieve its linked media.

```
use Illuminate\Database\Eloquent\Model;
use MohamedSamy902\AdvancedFileUpload\Traits\HasUploads;

class Article extends Model
{
    use HasUploads;
}
```

Then, quickly retrieve the image URL directly from your model:

```
$article = Article::find(1);

// Get original image URL
echo $article->getMediaUrl('image', 'original');

// Get thumbnail size (must be enabled in config)
echo $article->getMediaUrl('image', 'sm');

// Get an array of all thumbnails for the model's latest image
$thumbs = $article->getThumbnails();
```

---

Media Manager Dashboard (SPA)
-----------------------------

[](#media-manager-dashboard-spa)

[![Media Manager UI Dashboard](https://raw.githubusercontent.com/MohamedSamy902/upload-file-chunk/main/art/dashboard-preview.png)](https://raw.githubusercontent.com/MohamedSamy902/upload-file-chunk/main/art/dashboard-preview.png)

The package ships with a **Production-Ready, Enterprise-grade Single Page Application (SPA)** dashboard for tracking uploads, checking disk space, identifying unused orphaned files, and configuring settings safely.

Once installed and the config `database.enabled` is `true`, simply navigate to: **`your-app.com/advanced-file-upload`**

> **Note on Security:** By default, the dashboard uses the `web` middleware. To secure it, add your authentication middleware (e.g., `auth`, `admin`) to the `ui.middleware` array in `config/file-upload.php`.

### Features:

[](#features)

- ⚡ **PJAX Powered:** Blazing fast, zero-reload navigation. Search inputs and filters preserve your cursor focus instantly.
- 🎨 **Premium UI/UX:** Built with modern Glassmorphism, smooth animations, and high-quality UI components.
- 📊 **Filter-Aware Stats:** The summary dashboard instantly updates metrics (Storage Used, Active/Unused Files) to match your search and filter parameters dynamically.
- 🧹 **Bulk Actions &amp; Orphan Scanning:** Select multiple files to force-delete them from disk, or scan for missing database records easily.

---

Security
--------

[](#security)

### SSRF Protection

[](#ssrf-protection)

All URL downloads are validated before any HTTP request is issued. The following are blocked automatically:

**Private IP address ranges (RFC 1918 and related):**

RangeDescription`127.0.0.0/8`IPv4 loopback`10.0.0.0/8`Private network`172.16.0.0/12`Private network`192.168.0.0/16`Private network`169.254.0.0/16`Link-local (AWS Metadata endpoint)`100.64.0.0/10`Shared address space (RFC 6598)`::1/128`IPv6 loopback`fc00::/7`IPv6 unique local`fe80::/10`IPv6 link-local**Disallowed URL schemes:**

Only `http` and `https` are permitted. The following are blocked: `file://`, `ftp://`, `gopher://`, `data:`, and all others.

**Domain allowlist:**

To restrict URL downloads to specific domains:

```
// config/file-upload.php
'url_upload' => [
    'allowed_domains' => ['cdn.myapp.com', 'assets.partner.com'],
],
```

An empty array permits any public domain.

### Replacing Security Components

[](#replacing-security-components)

Every service is bound to a contract interface. To replace the SSRF validator with your own implementation:

```
// In AppServiceProvider::register()
use MohamedSamy902\AdvancedFileUpload\Contracts\SsrfValidatorContract;

$this->app->bind(SsrfValidatorContract::class, MyCustomSsrfValidator::class);
```

The same applies to `ImageProcessorContract`, `QuotaManagerContract`, and `FileUploadContract`.

---

Testing
-------

[](#testing)

Run the full test suite:

```
composer test
```

Run static analysis:

```
composer analyse
```

The package ships with 140 tests covering:

- Security attack simulation (SSRF, disguised files, DoS)
- Performance benchmarks (single file, batch of 50, memory usage)
- Error handling and edge cases
- Image processing with Intervention Image v3
- Resumable upload session management
- All public API surface

---

Changelog
---------

[](#changelog)

### v2.0.0

[](#v200)

- Upgraded Intervention Image from v2 to v3
- Minimum PHP version raised to 8.1
- Minimum Laravel version raised to 10
- Moved cloud storage packages (`league/flysystem-aws-s3-v3`, `spatie/laravel-google-cloud-storage`) to `suggest`
- Implemented comprehensive SSRF protection for URL downloads
- Added `UploadResult` typed value object (implements `ArrayAccess` for backward compatibility)
- Added resumable chunked upload system with session management
- Refactored monolithic service into focused, contract-based components
- Added 107 new tests (total: 140 tests, 345 assertions)
- Added GitHub Actions CI matrix for PHP 8.1–8.4 and Laravel 10–13

### v1.0.0

[](#v100)

- Initial release

---

Contributing
------------

[](#contributing)

Contributions are welcome. Please open an issue first to discuss the change you intend to make.

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/your-feature`
3. Write tests for your change
4. Run the test suite: `composer test`
5. Submit a pull request

---

License
-------

[](#license)

The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance95

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~17 days

Recently: every ~6 days

Total

8

Last Release

10d ago

Major Versions

v1.0.0 → v2.0.02026-06-03

v2.0.1 → v3.0.02026-08-07

v3.1.0 → v5.0.02026-08-09

PHP version history (2 changes)v1.0.0PHP ^8.0

v2.0.0PHP ^8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/37915355?v=4)[Mohamed Samy](/maintainers/MohamedSamy902)[@MohamedSamy902](https://github.com/MohamedSamy902)

---

Top Contributors

[![MohamedSamy902](https://avatars.githubusercontent.com/u/37915355?v=4)](https://github.com/MohamedSamy902 "MohamedSamy902 (26 commits)")

---

Tags

laravelthumbnails3imagestoragechunkcdnresumablessrfmedia-vault

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/mohamedsamy902-advanced-file-upload/health.svg)

```
[![Health](https://phpackages.com/badges/mohamedsamy902-advanced-file-upload/health.svg)](https://phpackages.com/packages/mohamedsamy902-advanced-file-upload)
```

###  Alternatives

[unopim/unopim

UnoPim Laravel PIM

10.8k2.5k](/packages/unopim-unopim)[bagisto/bagisto

Bagisto Laravel E-Commerce

28.0k175.2k9](/packages/bagisto-bagisto)[code16/sharp

Laravel Content Management Framework

79466.1k10](/packages/code16-sharp)[mostafaznv/larupload

Larupload is a ORM based file uploader for laravel to upload image, video, audio and other known files.

75487.1k6](/packages/mostafaznv-larupload)[typicms/base

A modular multilingual CMS built with Laravel, enabling developers to manage structured content like pages, news, events, and more.

1.6k20.4k](/packages/typicms-base)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
