mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); } /** * @return array{id: int, filename: string, url: string} * @throws LocalizedException */ public function upload(array $uploadedFile): array { if (!$this->config->isEnabled()) { throw new LocalizedException(__('File Manager is disabled.')); } $validated = $this->filePolicy->validate($uploadedFile); $safeName = $this->filename->sanitize( (string) ($uploadedFile['name'] ?? ''), $validated['extension'] ); $relativeDirectory = $this->config->getUploadPath() . '/' . $this->timezone->date()->format('Y/m'); $this->assertSafeRelativePath($relativeDirectory); $this->mediaDirectory->create($relativeDirectory); $uploader = $this->uploaderFactory->create(['fileId' => $uploadedFile]); $uploader->setAllowedExtensions($this->config->getAllowedExtensions()); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); $result = $uploader->save($this->mediaDirectory->getAbsolutePath($relativeDirectory), $safeName); if (!$result || empty($result['file'])) { throw new LocalizedException(__('The file could not be saved.')); } $storedName = ltrim((string) $result['file'], '/'); $relativePath = $relativeDirectory . '/' . $storedName; $this->assertSafeRelativePath($relativePath); $url = rtrim( $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA), '/' ) . '/' . str_replace('%2F', '/', rawurlencode($relativePath)); try { $model = $this->fileFactory->create(); $model->setData([ 'filename' => $storedName, 'filepath' => $relativePath, 'url' => $url, 'extension' => $validated['extension'], 'mime_type' => $validated['mime_type'], 'size' => (int) ($uploadedFile['size'] ?? 0), ]); $this->fileResource->save($model); } catch (\Throwable $exception) { if ($this->mediaDirectory->isFile($relativePath)) { $this->mediaDirectory->delete($relativePath); } throw new LocalizedException(__('The file record could not be saved.'), $exception); } return ['id' => (int) $model->getId(), 'filename' => $storedName, 'url' => $url]; } /** * @throws LocalizedException */ private function assertSafeRelativePath(string $path): void { $normalized = str_replace('\\', '/', $path); if ($normalized !== trim($normalized, '/') || str_contains($normalized, '..') || !preg_match('#^uploads(?:/[\p{L}\p{N}._-]+)+$#u', $normalized) ) { throw new LocalizedException(__('The generated upload path is invalid.')); } } }