-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start
Five minutes from composer require to a stored, validated upload.
<form method="post" action="/upload.php" enctype="multipart/form-data">
<input type="file" name="photos[]" multiple>
<button type="submit">Upload</button>
</form>The enctype="multipart/form-data" is required for file uploads. The [] and
multiple make this a multi-file field — but the PHP side is identical for a
single-file name="photo" field.
An adapter knows where files go (credentials) and what is allowed
(options, optional):
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use InitPHP\Upload\Upload;
use InitPHP\Upload\File;
use InitPHP\Upload\Adapters\LocalAdapter;
$adapter = new LocalAdapter(
[ // credentials — where files go
'dir' => __DIR__ . '/uploads/',
'url' => 'https://example.com/uploads/',
],
[ // options — what is allowed (optional)
'allowed_extensions' => ['jpg', 'jpeg', 'png', 'webp'],
'allowed_max_size' => 2 * 1024 * 1024, // 2 MB, in bytes
]
);
$upload = new Upload($adapter);File::setPost() reads a $_FILES key and always returns a File[], so one
loop handles both single- and multi-file fields:
$files = File::setPost('photos'); // File[]Empty file inputs are skipped automatically. See
The File Object for the details.
$results = [];
foreach (File::setPost('photos') as $file) {
try {
$stored = $upload->setFile($file)->to();
if ($stored === false) {
$results[] = ['name' => $file->getName(), 'error' => 'write failed'];
continue;
}
$results[] = ['name' => $file->getName(), 'url' => $stored->getURL()];
} catch (\InitPHP\Upload\Exceptions\UploadException $e) {
// validation failed (extension, MIME, size) or a backend error
$results[] = ['name' => $file->getName(), 'error' => $e->getMessage()];
}
}
header('Content-Type: application/json');
echo json_encode($results);to() returns the stored File (with its public URL set)
on success, or false if the underlying write failed. Validation problems are
thrown as an UploadException, not returned as false.
The optional $target is a destination path/key prefix:
$upload->setFile($file)->to('2026/06');
// stored at <dir>/2026/06/<name>
// URL: https://example.com/uploads/2026/06/<name>Missing directories are created for you. $target means the same thing in
every adapter — see Core Concepts.
Only the adapter changes; steps 3–5 stay exactly the same.
use InitPHP\Upload\Adapters\FTPAdapter;
$upload = new Upload(new FTPAdapter([
'host' => 'ftp.example.com',
'username' => 'user',
'password' => 'secret',
'url' => 'https://cdn.example.com/',
]));-
File::setPost('photos')normalized$_FILES['photos']intoFileobjects, skipping empty inputs and taking the original file name (and therefore the extension) from each upload. -
to()validated the file against your options — checking the extension, the real MIME type (viafinfo), and the size — then moved the upload into place and set its public URL. - You got back the stored
File, or a thrownUploadExceptionexplaining what went wrong.
-
Core Concepts —
File, adapters, theUploaddecorator, and$target - Validation — the full rules for extensions, MIME types and size
- Security Best Practices — before you go live
- Recipes — avatars, galleries, unique names, framework glue
initphp/upload · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Reference
Adapters
Practical Guides
Other