Object Store
Server-Side Multipart
Trusted backend multipart transfers for imports, exports, migrations, and CLI jobs.
Server-Side Multipart
ServerSideMultipartUploadManagerInterface is for trusted backend-owned streams or files. It is not the public browser upload mechanism.
Use it for:
- Import jobs where the backend already owns a stream.
- Export jobs writing generated archives.
- Migration tools moving large files between systems.
- CLI maintenance where backpressure and progress reporting matter.
Do not use it for:
- Public user uploads from browsers.
- Mobile app file uploads.
- Upload proxy endpoints.
Public uploads should stay direct-to-cloud
If a browser sends a 2 GB file through PHP, PHP workers are tied up for the duration of the transfer. Use direct upload intents for public traffic.
Upload Example
use Vortos\ObjectStore\Contract\ServerSideMultipartUploadManagerInterface;
use Vortos\ObjectStore\ValueObject\ContentType;
use Vortos\ObjectStore\ValueObject\PutObjectOptions;
use Vortos\ObjectStore\ValueObject\ServerSideMultipartUploadOptions;
final class ExportArchiveUploader
{
public function __construct(
private readonly ServerSideMultipartUploadManagerInterface $uploads,
) {}
public function upload(string $path, string $exportId): void
{
$stream = fopen($path, 'rb');
try {
$this->uploads->upload(
key: sprintf('exports/%s/archive.zip', $exportId),
body: $stream,
options: new PutObjectOptions(
contentType: new ContentType('application/zip'),
metadata: ['export-id' => $exportId],
),
transferOptions: new ServerSideMultipartUploadOptions(
partSizeBytes: 32 * 1024 * 1024,
concurrency: 4,
maxAttempts: 3,
onPartUploaded: static function (int $partNumber, int $bytes): void {
// Report progress to logs or a job tracker.
},
),
);
} finally {
if (is_resource($stream)) {
fclose($stream);
}
}
}
}Safety Features
- Validates S3 multipart limits.
- Keeps memory bounded by configured part size.
- Supports bounded concurrent part upload.
- Retries retryable part failures.
- Aborts failed multipart uploads when
abortOnFailure(true). - Enforces maximum object size.
- Rejects oversized inline bodies.
- Supports optional checksum algorithm.
- Supports progress callback per uploaded part.
Configuration
$config->multipart()
->thresholdBytes(104_857_600)
->partSizeBytes(16_777_216)
->abortOnFailure(true)
->maxObjectSizeBytes(5_497_558_138_880)
->maxInlineBodyBytes(16_777_216)
->maxAttempts(3)
->concurrency(4)
->backoffBaseMilliseconds(100)
->backoffCapMilliseconds(2000)
->checksumAlgorithm(null);Maintenance Commands
List active multipart uploads:
php bin/console vortos:object-store:multipart list
php bin/console vortos:object-store:multipart list --prefix=imports/Abort one upload:
php bin/console vortos:object-store:multipart abort --key=imports/big.csv --upload-id=<id> --confirmAbort stale uploads:
php bin/console vortos:object-store:multipart abort-stale --older-than="-24 hours" --dry-run
php bin/console vortos:object-store:multipart abort-stale --older-than="-24 hours" --confirmOperational Guidance
- Keep concurrency modest until provider and network behavior is measured.
- Use larger part sizes for very large objects to stay below S3 part count limits.
- Put imports and exports under predictable prefixes.
- Run stale multipart cleanup on a schedule.
- Alert if stale multipart uploads accumulate.