PHPackages                             xakki/file-uploader - 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. xakki/file-uploader

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

xakki/file-uploader
===================

Framework-agnostic chunked file uploader core (Upload Protocol v1).

0.3.1(today)20GPL-3.0-or-laterTypeScriptPHP ^8.3|^8.4|^8.5

Since Dec 13Pushed todayCompare

[ Source](https://github.com/Xakki/file-uploader)[ Packagist](https://packagist.org/packages/xakki/file-uploader)[ RSS](/packages/xakki-file-uploader/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (6)Versions (3)Used By (0)

File Uploader
=============

[](#file-uploader)

> Universal **chunked file uploader**: one wire contract — **[Upload Protocol v1](protocol/SPEC.md)** — with conforming implementations for **Laravel**, **Symfony**, **any PHP** project, and the **browser**.

[![License](https://camo.githubusercontent.com/59fe4b1a01196fa2651f175248f2f2a44b9d432296750344413d53375291d87f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c2d2d332e302d677265656e)](LICENSE)[![PHP](https://camo.githubusercontent.com/ec7d8160a4d399e7b82d1bad16b1a8977048f905838f87483fefc3cbd5d0085f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d373737)](https://camo.githubusercontent.com/ec7d8160a4d399e7b82d1bad16b1a8977048f905838f87483fefc3cbd5d0085f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d373737)[![Node](https://camo.githubusercontent.com/f9f84e6ad3e29c95c40e4935060e0e098625842f75abb73121be3215b04d8b47/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4e6f64652d31382532422d333933)](https://camo.githubusercontent.com/f9f84e6ad3e29c95c40e4935060e0e098625842f75abb73121be3215b04d8b47/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4e6f64652d31382532422d333933)

Chunked uploads (configurable chunk size, default 1 MB), Drag &amp; Drop widget, file list with public-link copy, soft-delete to trash with TTL auto-cleanup, role-based access, works with any `league/flysystem` disk (local, **S3/CloudFront**, …).

**This repository is the base package** [`xakki/file-uploader`](https://packagist.org/packages/xakki/file-uploader)— the framework-agnostic PHP **core** — and also hosts the shared **[protocol](protocol/)** spec and the **[JS client + widget](js/)** (`@xakki/file-uploader`). The framework bindings live in their own repos.

The protocol
------------

[](#the-protocol)

The upload behaviour (chunk fields, `uploadId` format, the `{success, data, message}` envelope, retry-not-on-4xx) is a **wire contract**, not framework code. It lives once in [`protocol/`](protocol/)as a language-neutral spec + OpenAPI + JSON Schemas + **conformance fixtures** that every implementation runs, so the implementations cannot drift apart. Topology rationale: [ADR 0002](docs/adr/0002-base-repo-plus-binding-repos.md) (supersedes [ADR 0001](docs/adr/0001-repo-topology.md)).

Pick your stack
---------------

[](#pick-your-stack)

Your stackPackageInstall**Any PHP** (Slim, Mezzio, plain)[`xakki/file-uploader`](https://packagist.org/packages/xakki/file-uploader) (this repo, core)`composer require xakki/file-uploader`**Laravel** 10–12[`xakki/laravel-file-uploader`](https://github.com/Xakki/file-uploader-laravel)`composer require xakki/laravel-file-uploader`**Symfony** 6.4 / 7[`xakki/symfony-file-uploader`](https://github.com/Xakki/file-uploader-symfony)`composer require xakki/symfony-file-uploader`**Browser / SPA**[`@xakki/file-uploader`](js)`npm i @xakki/file-uploader`**No Node build**vendored UMD widgetships inside the PHP bindings — no npm neededThe browser side is split: a **headless core** (`@xakki/file-uploader/core`, tree-shakeable, no DOM) and a **DOM widget** (`@xakki/file-uploader/widget`). PHP projects without a Node toolchain get the same widget as a pre-built UMD bundle in the bindings' assets.

Core — use it directly
----------------------

[](#core--use-it-directly)

```
composer require xakki/file-uploader
```

The core depends on four seams a host wires up:

SeamInterfaceProvidedStorage`Contracts\Storage``Storage\FlysystemStorage` over any `league/flysystem` adapterIdentity`Contracts\UserResolver``Auth\NullUserResolver` (guest) or your ownClock`Psr\Clock\ClockInterface``Clock\SystemClock`Logger`Psr\Log\LoggerInterface`any PSR-3, e.g. `Psr\Log\NullLogger`A request adapts to `Contracts\ChunkPayload` (one chunk = a readable stream + scalars).

```
use League\Flysystem\Filesystem;
use League\Flysystem\Local\LocalFilesystemAdapter;
use Psr\Log\NullLogger;
use Xakki\FileUploader\Auth\NullUserResolver;
use Xakki\FileUploader\Clock\SystemClock;
use Xakki\FileUploader\FileManager;
use Xakki\FileUploader\Storage\FlysystemStorage;

$manager = new FileManager(
    config: [
        'disk' => 'local',
        'directory' => 'uploads',
        'max_size' => 50 * 1024 * 1024,
        'max_files' => 0,             // 0 = unlimited; caps active (non-deleted) files
        'allowed_extensions' => [],   // empty = allow any
        'soft_delete' => true,
        'trash_ttl_days' => 30,
    ],
    storage: new FlysystemStorage(new Filesystem(new LocalFilesystemAdapter('/var/uploads'))),
    users: new NullUserResolver(),
    logger: new NullLogger(),
    clock: new SystemClock(),
);
```

Adapt your request to `ChunkPayload`, then call the core; build the response with the shared `Protocol\ResponseFactory` and validate scalar fields with `Protocol\ChunkValidator`:

```
use Xakki\FileUploader\Dto\FileMetadata;
use Xakki\FileUploader\Protocol\ChunkValidator;
use Xakki\FileUploader\Protocol\ResponseFactory;

$errors = ChunkValidator::validate($_POST);
if ($errors !== []) {
    http_response_code(422);
    echo json_encode(ResponseFactory::error('Validation failed.', $errors));
    return;
}

$result = $manager->handleChunk($payload);          // $payload implements ChunkPayload
$completed = $result instanceof FileMetadata;
$data = ['completed' => $completed];
if ($completed) {
    $data['metadata'] = $manager->formatFileForResponse($result);
}
echo json_encode(ResponseFactory::success($data, 'ok'));
```

`FileManager` also provides `list()`, `delete($id)`, `restore($id)`, `cleanupTrash()` and `syncMetadata()`. A complete runnable example (plain-PHP, filesystem **and** S3, serving the widget) is the **[demo repo](https://github.com/Xakki/file-uploader-demo)**.

### Per-user / per-session isolation

[](#per-user--per-session-isolation)

The core has no notion of HTTP, cookies or sessions — identity is the host's job. But all four storage directories are plain per-instance config, so to keep every user's files under their own folder you just construct the manager with those keys scoped to the user/session id. For example, to land everything under `uploads//`:

```
$sid = preg_replace('/[^A-Za-z0-9_-]/', '', $sessionId);   // REQUIRED: a path segment, sanitize it
if ($sid === '') {
    throw new RuntimeException('Invalid session id.');
}

config: [
    'disk'                => 'local',
    'directory'           => "uploads/$sid",          // → uploads//
    'metadata_directory'  => "uploads/$sid/.meta",
    'temporary_directory' => "uploads/$sid/.chunks",
    'trash_directory'     => "uploads/$sid/.trash",
    // …rest unchanged
],
```

Because `list()`, dedup and `cleanupTrash()` all scan the configured metadata/trash dirs, scoping them per session gives full isolation for free — each session only ever sees its own files.

> **Sanitize the id.** It becomes a filesystem path segment; an unsanitized value like `../../etc`is path traversal. Allow only a safe charset (e.g. `[A-Za-z0-9_-]`) and reject empties.

Where the `$sessionId` comes from — an auth user id, or a cookie auto-issued to guests — is the host's concern: wire it through `Contracts\UserResolver` (so ownership checks line up) and set the cookie in your controller/framework. The **[demo](https://github.com/Xakki/file-uploader-demo)**shows the guest-cookie variant end to end.

Layout
------

[](#layout)

```
file-uploader/                  ← this repo = xakki/file-uploader (core) + protocol + js
├── src/         Xakki\FileUploader\   framework-agnostic PHP core
├── tests/       core test suite
├── protocol/    Upload Protocol v1 — SPEC.md, openapi.yaml, schemas/, fixtures/   ← source of truth
├── js/          @xakki/file-uploader  headless TS client + DOM widget (ESM/CJS/UMD)
├── go/ python/  conformance-target stubs (planned)
└── docs/        ADRs + roadmap

Bindings (separate repos, consume the published core):
  Laravel  → github.com/Xakki/file-uploader-laravel   (xakki/laravel-file-uploader)
  Symfony  → github.com/Xakki/file-uploader-symfony    (xakki/symfony-file-uploader)
  Demo     → github.com/Xakki/file-uploader-demo

```

Develop
-------

[](#develop)

```
make install        # core (root) + js deps
make test           # core + js suites
make test-core      # phpunit + phpstan at the repo root
make test-js        # js unit + conformance
make conformance    # js client against protocol/fixtures
make phpstan        # static analysis · make pint / pint-fix
```

Bindings are developed in their own repos and consume the published core; they run the same `protocol/fixtures` (vendored via the core package) as their conformance gate.

Documentation
-------------

[](#documentation)

- **[Upload Protocol v1](protocol/SPEC.md)** — the wire contract (fields, envelope, endpoints, errors).
- **[docs/RELEASING.md](docs/RELEASING.md)** — tagging + publishing (core, js, bindings).
- **[docs/adr/](docs/adr/)** — architecture decisions. **[docs/TODO.md](docs/TODO.md)** — roadmap.
- Binding repos: [Laravel](https://github.com/Xakki/file-uploader-laravel) · [Symfony](https://github.com/Xakki/file-uploader-symfony) · [demo](https://github.com/Xakki/file-uploader-demo).

License
-------

[](#license)

[GPL-3.0-or-later](LICENSE).

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance100

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

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 ~182 days

Total

2

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/426468?v=4)[Xakki](/maintainers/Xakki)[@Xakki](https://github.com/Xakki)

---

Tags

chunked-uploaddrag-and-dropfile-uploadflysystemjavascriptlaravelphps3symfonytypescriptupload-protocolwidget

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/xakki-file-uploader/health.svg)

```
[![Health](https://phpackages.com/badges/xakki-file-uploader/health.svg)](https://phpackages.com/packages/xakki-file-uploader)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k12](/packages/tempest-framework)[symfony/symfony

The Symfony PHP framework

31.4k86.9M2.2k](/packages/symfony-symfony)[laravel/framework

The Laravel Framework.

34.7k532.1M19.3k](/packages/laravel-framework)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

562565.8k42](/packages/ecotone-ecotone)[web-auth/webauthn-lib

FIDO2/Webauthn Support For PHP

1237.8M118](/packages/web-auth-webauthn-lib)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M195](/packages/sulu-sulu)

PHPackages © 2026

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