PHP MVCDOCUMENTAÇÃO
v2.0.0

Uploads

Validação e armazenamento de arquivos enviados pela classe Upload.

Construir e processar

Framework\Support\Upload recebe o array de arquivo e oferece configuração fluente por MIME, extensão, tamanho máximo, diretório, nome aleatório, prefixo e entidade/ID. Presets forImages($maxMb,$entity,$entityId=null) e forDocuments($maxMb, $entity, $entityId = null) apoiam políticas comuns; process() valida e move o arquivo.

$upload = (new Upload($_FILES['avatar'] ?? []))
    ->forImages(3, 'users', $userId)
    ->setRandomName(true);

if (!$upload->process()) {
    $errors = $upload->getErrors();
} else {
    $filename = $upload->getFilename();
}

API de resultado

getFilename(), getErrors(), hasErrors(), getFirstError(). Upload::resolvePath($entity,$filename,$entityId=null) retorna o caminho relativo entity[/id]/filename sob o armazenamento; helper uploadUrl() forma a URL correspondente.

Práticas seguras

  • Validar extensão e MIME real; limitar tamanho.
  • Não confiar em nome fornecido pelo browser; nomes aleatórios reduzem colisões/exposição.
  • Guardar apenas o nome/caminho relativo no banco e construir URL por helper.
  • Evitar armazenar uploads executáveis dentro do document root.

O código usa Fileinfo para identificar MIME e armazenamento sob storage/; verifique permissões do processo PHP.

Fluxo de formulário a storage

Cenário: atualizar avatar do usuário autenticado. O formulário precisa de multipart/form-data; obtenha o array `$_FILES` (ou Request::file()), configure a política e só persista o nome depois que process() retornar true.

$upload = (new \Framework\Support\Upload($_FILES['avatar'] ?? []))
    ->forImages(3, 'users', $this->userId());

if (!$upload->process()) {
    $message = $upload->getFirstError();
    // Preserve o avatar atual; não atualize o Model.
} else {
    $filename = $upload->getFilename();
    // Armazene apenas esse nome no campo avatar.
}

`forImages($maxMb,$entity,$entityId=null)` e `forDocuments($maxMb,$entity,$entityId=null)` exigem tamanho máximo e entity. O nome é aleatório por padrão; `setRandomName()` existe, mas não é preciso chamá-lo para o padrão seguro. process() retorna bool; filename só é preenchido em sucesso.

PresetMIME/extensões permitidosParâmetros
forImagesJPEG/JPG, PNG, GIF e WebPMB, entity, entityId opcional
forDocumentsPDF, DOC, DOCX, XLS e XLSXMB, entity, entityId opcional

Armazenar caminho relativo, não confiar no browser

Uploads vão para storage/uploads e são organizados como entity/ ou entity/id/. Guarde o nome retornado, Upload::resolvePath() devolve caminho relativo, não URL pública; para URL, use uploadUrl(). O arquivo passa por is_uploaded_file(), limite em bytes, MIME real via Fileinfo e whitelist de extensão.

O preset de imagem não aceita SVG, embora outras ferramentas possam reconhecer SVG. Evite uploads executáveis e confira permissões. Quando substituir arquivo existente, remova o antigo somente depois de confirmar o novo; BaseController::replaceUploadedFile() segue esse padrão.

Upload: pré-requisitos, resultado e segurança de caminho

process(): bool exige arquivo no formato PHP de $_FILES, uma configuração de entidade e um preset/configuração de tipos permitidos, por exemplo forImages() ou forDocuments(). O upload precisa ser uma transferência HTTP real; um caminho local arbitrário não satisfaz is_uploaded_file(). Antes de processar, confira Request::hasFile('avatar') e use Request::file('avatar'); não construa a classe com [] para representar campo ausente, pois o processamento espera chaves como error, tmp_name, name e size.

if (!$this->request->hasFile('avatar')) {
    $this->jsonError('Envie um avatar.', 422);
}
$upload = (new \Framework\Support\Upload($this->request->file('avatar')))
    ->forImages(5, 'users', $this->userId());
if (!$upload->process()) {
    $this->jsonError('Upload inválido.', 422, ['errors' => $upload->getErrors()]);
}
$filename = $upload->getFilename();

Sucesso retorna true e disponibiliza o nome final em getFilename(); falha retorna false e acumula mensagens em getErrors(). O caminho final combina entidade, ID opcional e nome gerado.

Segurança: setEntity()/setEntityId() apenas apararam barras externas; resolvePath() concatena componentes. Entidade deve vir de allowlist constante do desenvolvedor; ID deve ser validado (preferencialmente inteiro); filename deve ser exclusivamente o nome devolvido por getFilename(). Nunca aceite esses valores do usuário nem os encaminhe sem validação a resolvePath(), uploadUrl() ou exclusão de arquivo.

Setters fluentes

Configuração programática disponível: setAllowedTypes(array $types): static, setAllowedExtensions(array $extensions): static, setMaxSize(int $bytes): static (bytes), setUploadDir(string $dir): static, setRandomName(bool $random): static, setPrefix(string $prefix): static, setEntity(string $entity): static e setEntityId(int|string|null $id): static. O prefixo compõe o nome quando a geração aleatória é escolhida; presets também definem tipos, limite e destino.