Sulu 3.x: Configuring a maximum upload size for chunked media uploads
0 reputation · 23 Aug 2020, 21:34 UTC
0 reputation · 23 Aug 2020, 21:34 UTC
Sulu 3.x introduces chunked media uploads with a default 1 MB chunk size configurable via sulu_media.upload_chunk_size. However, the bundle offers no explicit setting to cap the overall file size. This can lead to large uploads that consume server resources, and the UI provides no built‑in cancellation or timeout handling.
The goal is to identify a clean, documented way to impose a per‑upload limit and expose a graceful cancellation mechanism. Constraints include preserving the existing chunked workflow, compatibility with PHP’s upload_max_filesize and post_max_size, and ensuring orphaned temporary files are cleaned up promptly.
Unresolved questions:
To cap the overall size of a chunked upload in Sulu 3.x you can add a custom configuration option, validate it in the upload controller, and abort the upload when the limit is exceeded. The bundle already fires a sulu_media.upload_chunk event for each chunk, so a listener can keep a running total and trigger MediaUploadManager::abortUpload($uploadId) when the configured maximum is reached. Cleanup of orphaned temporary files is handled by that abort method. For graceful cancellation and per request timeouts you can rely on Symfony 6’s Messenger component to schedule a delayed abort after a configurable threshold.
// config/packages/sulu_media.yaml
sulu_media:
max_file_size: 104857600 # 100 MiB, adjust as needed
// src/Controller/MediaUploadController.php
public function __construct(private int $maxFileSize) {}
public function upload(Request $request): JsonResponse
{
$uploadId = $request->request->get('uploadId');
$chunkSize = $request->request->getInt('chunkSize');
$totalSize = $request->request->getInt('totalSize');
if ($totalSize > $this->maxFileSize) {
throw new BadRequestHttpException('Upload exceeds maximum allowed size');
}
// ... existing chunk handling logic
}sulu_media.upload_chunk
// src/EventListener/UploadChunkListener.php
public function onUploadChunk(UploadChunkEvent $event): void
{
$uploadId = $event->getUploadId();
$size = $event->getChunkSize();
$total = $this->session->get("upload_{$uploadId}_total", 0) + $size;
if ($total > $this->maxFileSize) {
$this->mediaUploadManager->abortUpload($uploadId);
throw new BadRequestHttpException('Upload aborted: size limit exceeded');
}
$this->session->set("upload_{$uploadId}_total", $total);
}// src/Controller/MediaUploadController.php
public function cancel(string $uploadId): JsonResponse
{
$this->mediaUploadManager->abortUpload($uploadId);
return new JsonResponse(['status' => 'canceled']);
}// config/services.yaml
services:
App\MessageHandler\UploadTimeoutHandler:
tags:
- { name: messenger.message_handler, on_error: 'retry' }
// src/Message/UploadTimeout.php
class UploadTimeout
{
public function __construct(private string $uploadId, private int $delaySeconds){ }
}
// src/MessageHandler/UploadTimeoutHandler.php
public function __invoke(UploadTimeout $message): void
{
$this->mediaUploadManager->abortUpload($message->uploadId);
}
// In the upload controller, after receiving the first chunk
$delay = 3600; // 1 hour
$dispatcher->dispatch(new UploadTimeout($uploadId, $delay));
To fine tune the timeout strategy, could you share the typical maximum upload duration you expect in your environment? This will help decide whether a Messenger delay or PHP’s max_execution_time is more appropriate.
sulu_media.upload_chunk event to track cumulative size.MediaUploadManager::abortUpload() for immediate cleanup.Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.