Files

Upload

Upload service flow, file validation boundaries, storage strategies y ejemplos de procesamiento de archivos.

Overview

Upload module handles file and image uploads from PSR-7 requests. It resolves uploaded payloads, validates input, stores files into upload storage, and returns typed results (UploadedFile / UploadedImage).

Registered services

UploadServiceProvider registers only typed service IDs (no string aliases): FileUploadValidator, ImageUploadValidator, UploadStorage, MimeTypeDetector, GdImageProcessor, UploadService, and UploadFactory.

Configuration

Upload profiles are configured in app/Config/Upload.yaml. YAML is validated and mapped into typed UploadConfigDefinition before runtime validators and upload services are created.

example.php
module: upload
config:
  files:
    documents:
      target_directory: uploads/documents
      max_bytes: 10485760
      allowed_mime_types:
        - application/pdf
        - text/plain
      allowed_extensions:
        - pdf
        - txt
  images:
    avatar:
      target_directory: uploads/avatars
      max_bytes: 2097152
      allowed_mime_types:
        - image/jpeg
        - image/png
        - image/webp
      allowed_extensions:
        - jpg
        - jpeg
        - png
        - webp
      reencode: true
      min_width: 128
      max_width: 2048
      min_height: 128
      max_height: 2048

Uploaded files in controllers

Controller exposes uploaded file access helper file() and upload helper upload() (UploadFactory).

example.php
$raw = $this->file('avatar'); // UploadedFileInterface|array|null

$image = $this->upload()->uploadImage('avatar', 'avatar');
$document = $this->upload()->upload('document', 'documents');

Upload service

Use dependency injection for application services. UploadFactory is the high-level entrypoint and supports profile-based or explicit-options workflows.

example.php
final class ProfileImageUploader
{
    public function __construct(
        private readonly UploadFactory $uploads,
    ) {
    }

    public function uploadAvatar(ServerRequestInterface $request): UploadedImage
    {
        return $this->uploads
            ->image('avatar')
            ->uploadFromRequest($request, 'avatar');
    }
}

Validation

FileUploadValidator validates upload payload presence, PHP upload error, temporary file path, size, MIME type and extension. ImageUploadValidator adds image readability and optional width/height constraints. Validation failures throw UploadValidationException.

Storage paths

Upload options are resolved through ApplicationContext. target_directory from config is transformed to absolute storage path via resolveUploadPath() and to portable relative path via uploadRelativePath().

example.php
$absolute = $context->resolveUploadPath('uploads/avatars');
// .../storage/uploads/avatars

$relative = $context->uploadRelativePath('uploads/avatars');
// uploads/avatars

Security notes

Do not trust client filenames. Validate size/type/extension through profile rules. Prefer generated storage filenames (UploadStorage::generateFilename()) and persist only stored metadata (storedRelativePath, mime, size). Keep executable files out of publicly executable directories.

Example

Typical safe workflow: read file from request, validate via profile, store upload, persist only resulting metadata.

example.php
public function uploadAvatarAction(): ResponseInterface
{
    $uploaded = $this->upload()->uploadImage('avatar', 'avatar');

    // Persist only stable metadata, not original client filename.
    $payload = [
        'path' => $uploaded->storedRelativePath(),
        'mime' => $uploaded->mimeType(),
        'size' => $uploaded->sizeBytes(),
        'width' => $uploaded->width(),
        'height' => $uploaded->height(),
    ];

    return $this->json($payload, 201);
}