. */ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Exceptions\FileUploadException; use Fisharebest\Webtrees\FlashMessages; use Fisharebest\Webtrees\Html; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Log; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Services\MediaFileService; use Fisharebest\Webtrees\Validator; use League\Flysystem\FilesystemException; use League\Flysystem\UnableToCheckFileExistence; use League\Flysystem\UnableToWriteFile; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use function e; use function preg_match; use function redirect; use function route; use function str_replace; use function substr; use function trim; use const UPLOAD_ERR_NO_FILE; use const UPLOAD_ERR_OK; final class UploadMediaAction implements RequestHandlerInterface { public function __construct( private readonly MediaFileService $media_file_service, ) { } public function handle(ServerRequestInterface $request): ResponseInterface { $data_filesystem = Registry::filesystem()->data(); $all_folders = $this->media_file_service->allMediaFolders($data_filesystem); foreach ($request->getUploadedFiles() as $key => $uploaded_file) { if ($uploaded_file->getError() === UPLOAD_ERR_NO_FILE) { continue; } if ($uploaded_file->getError() !== UPLOAD_ERR_OK) { throw new FileUploadException($uploaded_file); } $key = substr($key, 9); // "mediafile1", "mediafile2", ... $folder = Validator::parsedBody($request)->string('folder' . $key); $filename = Validator::parsedBody($request)->string('filename' . $key); // If no filename specified, use the original filename. if ($filename === '') { $filename = $uploaded_file->getClientFilename(); } // Validate the folder if (!$all_folders->contains($folder)) { break; } // Validate the filename. $filename = str_replace('\\', '/', $filename); $filename = trim($filename, '/'); $tmp = strpbrk($filename, MediaFileService::BLOCKED_CHARACTERS); if ($tmp !== false) { $message = I18N::translate('Filenames are not allowed to contain the character ā€œ%sā€.', $tmp[0]); FlashMessages::addMessage($message); continue; } $extension = pathinfo($filename, PATHINFO_EXTENSION); if (in_array(strtolower($extension), MediaFileService::BLOCKED_EXTENSIONS, true)) { $message = I18N::translate('Filenames are not allowed to have the extension ā€œ%sā€.', $extension); FlashMessages::addMessage($message); continue; } $path = $folder . $filename; try { $file_exists = $data_filesystem->fileExists($path); } catch (FilesystemException | UnableToCheckFileExistence) { $file_exists = false; } if ($file_exists) { FlashMessages::addMessage(I18N::translate('The file %s already exists. Use another filename.', $path, 'error')); continue; } // Now copy the file to the correct location. try { $data_filesystem->writeStream($path, $uploaded_file->getStream()->detach()); FlashMessages::addMessage(I18N::translate('The file %s has been uploaded.', Html::filename($path)), 'success'); Log::addMediaLog('Media file ' . $path . ' uploaded'); } catch (FilesystemException | UnableToWriteFile $ex) { FlashMessages::addMessage(I18N::translate('There was an error uploading your file.') . '
' . e($ex->getMessage()), 'danger'); } } $url = route(UploadMediaPage::class); return redirect($url); } }