PHPackages                             koriym/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. koriym/file-upload

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

koriym/file-upload
==================

Type-safe file upload handling with immutable value objects

1.0.0(7mo ago)184.4k—0.4%2MITPHPPHP ^8.2CI failing

Since Nov 16Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/koriym/Koriym.FileUpload)[ Packagist](https://packagist.org/packages/koriym/file-upload)[ RSS](/packages/koriym-file-upload/feed)WikiDiscussions 1.x Synced 2d ago

READMEChangelog (3)Dependencies (2)Versions (5)Used By (2)

Koriym.FileUpload
=================

[](#koriymfileupload)

[![codecov](https://camo.githubusercontent.com/eabeb68d540c171851f1e5392eac7bd7caef7ddd550d8b03690db8748435eda4/68747470733a2f2f636f6465636f762e696f2f67682f6b6f7269796d2f4b6f7269796d2e46696c6555706c6f61642f67726170682f62616467652e7376673f746f6b656e3d70494f37463776585152)](https://codecov.io/gh/koriym/Koriym.FileUpload)[![Type Coverage](https://camo.githubusercontent.com/86ac30bd308adb186ff5471ef4290d51c37942b216ad1f76fa374e1bee1fd467/68747470733a2f2f73686570686572642e6465762f6769746875622f6b6f7269796d2f4b6f7269796d2e46696c6555706c6f61642f636f7665726167652e737667)](https://shepherd.dev/github/koriym/Koriym.FileUpload)[![Psalm Level](https://camo.githubusercontent.com/8348936e751e50d3f0d21570ae5e80cceb721871613b628590bbd75ff6d66d60/68747470733a2f2f73686570686572642e6465762f6769746875622f6b6f7269796d2f4b6f7269796d2e46696c6555706c6f61642f6c6576656c2e737667)](https://shepherd.dev/github/koriym/Koriym.FileUpload)[![Continuous Integration](https://github.com/koriym/Koriym.FileUpload/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/koriym/Koriym.FileUpload/actions/workflows/continuous-integration.yml)

Type-safe file upload handling with immutable value objects.

Motivation
----------

[](#motivation)

Testing file uploads in PHP applications is traditionally complex and time-consuming. It often requires setting up a built-in web server, making HTTP requests, and managing multipart form data. This approach leads to slow, unreliable tests that are difficult to debug and maintain, especially in CI environments.

This library simplifies both the handling of file uploads and their testing. Instead of dealing with PHP's native `$_FILES` array directly, you work with immutable value objects that provide type safety and early validation. For testing, rather than simulating HTTP file uploads, you can create test instances directly from files on your filesystem. This approach makes tests faster, more reliable, and easier to debug while still testing real-world scenarios with actual file types and contents.

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

[](#installation)

```
composer require koriym/file-upload
```

Usage
-----

[](#usage)

### From $\_FILES

[](#from-_files)

```
// Type-safe with union return type
$upload = FileUpload::create($_FILES['upload'], [
    'maxSize' => 5 * 1024 * 1024,          // 5MB
    'allowedTypes' => ['image/jpeg', 'image/png'],
    'allowedExtensions' => ['jpg', 'jpeg', 'png']
]); // Returns FileUpload|ErrorFileUpload

match (true) {
    $upload instanceof FileUpload => $upload->move('./uploads/' . $upload->name)
        ? 'Upload successful'
        : 'Failed to move file',
    $upload instanceof ErrorFileUpload => 'Error: ' . $upload->message,
};
```

### From File Path (for Testing)

[](#from-file-path-for-testing)

```
// Type-safe with union return type
$upload = FileUpload::fromFile('/path/to/image.jpg', [
    'maxSize' => 5 * 1024 * 1024,
    'allowedTypes' => ['image/jpeg', 'image/png']
]); // Returns FileUpload|ErrorFileUpload

match (true) {
    $upload instanceof FileUpload => 'File validated successfully',
    $upload instanceof ErrorFileUpload => 'Validation error: ' . $upload->message,
};
```

Properties
----------

[](#properties)

Both `FileUpload` and `ErrorFileUpload` have the following properties:

```
public string $name;        // Original filename
public string $type;        // MIME type
public int $size;          // File size in bytes
public string $tmpName;    // Temporary file path
public int $error;         // PHP upload error code
public ?string $extension; // File extension
```

Additionally, `ErrorFileUpload` has:

```
public ?string $message;   // Error message
```

Validation Options
------------------

[](#validation-options)

You can pass the following validation options to both `create()` and `fromFile()`:

- `maxSize`: Maximum file size in bytes
- `allowedTypes`: Array of allowed MIME types
- `allowedExtensions`: Array of allowed file extensions

Testing
-------

[](#testing)

### Using toArray()

[](#using-toarray)

The library provides a `toArray()` method to convert a FileUpload object back to `$_FILES` format array, which is useful for creating test stubs:

```
$upload = FileUpload::create([
    'name' => 'test.jpg',
    'type' => 'image/jpeg',
    'size' => 1024,
    'tmp_name' => '/tmp/test',
    'error' => UPLOAD_ERR_OK
]);

$fileData = $upload->toArray();  // Returns $_FILES format array
```

### Using fromFile()

[](#using-fromfile)

For more realistic testing scenarios, you can create a FileUpload instance directly from a file:

```
// Place test files in your project's tests/fixtures directory
$upload = FileUpload::fromFile(__DIR__ . '/fixtures/test-image.jpg');

// Create with validation
$upload = FileUpload::fromFile('/path/to/test/doc.pdf', [
    'maxSize' => 1024 * 1024,
    'allowedTypes' => ['application/pdf']
]);
```

This is particularly useful when you want to test with real files and MIME types.

Note: The `move()` method behaves differently in CLI and web environments:

- In web environment: Uses `move_uploaded_file()` for security
- In CLI environment (testing): Uses `rename()` for testability

Testing Tips
------------

[](#testing-tips)

### Testing Code That Depends on $\_FILES

[](#testing-code-that-depends-on-_files)

When testing code that depends on $\_FILES, you can use the combination of `fromFile()` and `toArray()` to create controlled, reproducible tests without the complexity of setting up actual HTTP file uploads:

See the working example in [tests/Example/UploadHandlerTest.php](tests/Example/UploadHandlerTest.php).

Security Considerations
-----------------------

[](#security-considerations)

### File Upload Security

[](#file-upload-security)

The `move()` method moves the uploaded file to the specified destination without additional validation. **Your application is responsible for:**

- Validating the destination path (prevent directory traversal)
- Checking for existing files (prevent unintended overwrites)
- Setting appropriate file permissions
- Sanitizing user-provided filenames

### Example: Safe file handling

[](#example-safe-file-handling)

```
$upload = FileUpload::create($_FILES['file']);

if ($upload instanceof FileUpload) {
    // Sanitize filename
    $safeName = preg_replace('/[^a-zA-Z0-9._-]/', '', $upload->name);

    // Ensure destination directory exists and is writable
    $uploadDir = '/var/www/uploads';
    $destination = $uploadDir . '/' . $safeName;

    // Check if file already exists
    if (file_exists($destination)) {
        $destination = $uploadDir . '/' . uniqid() . '_' . $safeName;
    }

    $upload->move($destination);
}
```

Similar Libraries
-----------------

[](#similar-libraries)

Both Symfony HttpFoundation and Laravel provide file upload handling as part of their frameworks. While these frameworks offer more comprehensive features including storage abstraction and integration with their ecosystems, Koriym.FileUpload takes a more focused approach by providing a lightweight, framework-independent solution that transforms PHP's native $\_FILES array into type-safe immutable objects.

Additional Information
----------------------

[](#additional-information)

PHP's `$_FILES` structure:

```
$_FILES['upload'] = [
    'name'      => 'profile.jpg',      // Original filename
    'type'      => 'image/jpeg',       // MIME type
    'size'      => 12345,              // File size in bytes
    'tmp_name'  => '/tmp/phpxxxxx',    // Temporary file path
    'error'     => 0                   // Error code (0 means success)
];
```

For multiple file uploads:

```

```

```
$_FILES['images'] = [
    'name'     => ['image1.jpg', 'image2.png'],
    'type'     => ['image/jpeg', 'image/png'],
    'size'     => [12345, 67890],
    'tmp_name' => ['/tmp/phpxxxxx', '/tmp/phpyyyyy'],
    'error'    => [0, 0]
];
```

PHP Upload Error Codes:

```
UPLOAD_ERR_OK         // 0: Success
UPLOAD_ERR_INI_SIZE   // 1: Exceeds upload_max_filesize in php.ini
UPLOAD_ERR_FORM_SIZE  // 2: Exceeds MAX_FILE_SIZE in HTML form
UPLOAD_ERR_PARTIAL    // 3: Partially uploaded
UPLOAD_ERR_NO_FILE    // 4: No file uploaded
UPLOAD_ERR_NO_TMP_DIR // 6: Missing temporary folder
UPLOAD_ERR_CANT_WRITE // 7: Failed to write to disk
UPLOAD_ERR_EXTENSION  // 8: Stopped by PHP extension
```

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance62

Regular maintenance activity

Popularity34

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity55

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

Total

4

Last Release

238d ago

Major Versions

0.2.0 → 1.0.02025-11-07

PHP version history (2 changes)0.1.0PHP ^8.1

1.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/db4fc75ffc631168d0d7143b6f2c24b1534dfb921212bd851c026c5cbbb1344d?d=identicon)[koriym](/maintainers/koriym)

---

Top Contributors

[![koriym](https://avatars.githubusercontent.com/u/529021?v=4)](https://github.com/koriym "koriym (42 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

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

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

PHPackages © 2026

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