<?php declare(strict_types=1);
namespace UploadsBundle\Subscriber;
use InvalidArgumentException;
use Oneup\UploaderBundle\Event\PostUploadEvent;
use Oneup\UploaderBundle\Uploader\Response\AbstractResponse;
use Oneup\UploaderBundle\UploadEvents;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Sindrive\ContentBundle\Resizer\Resizer;
use Sindrive\ContentBundle\Thumbs\ThumbsManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use UploadsBundle\FileHandler\FileHandlerFactory;
use UploadsBundle\FileHandler\ImageHandler;
use UploadsBundle\FileHandler\LocalPathMapper;
use UploadsBundle\Model\File as FileModel;
use const PATHINFO_BASENAME;
class UploadSubscriber implements EventSubscriberInterface
{
private FileHandlerFactory $fileHandlerFactory;
private string $uploadsWebRoot;
private string $uploadsRealRoot;
private Resizer $resizer;
private LocalPathMapper $pathMapper;
private ThumbsManager $thumbsManager;
private LoggerInterface $logger;
/**
* @var string[]
*/
private array $dbDomains;
/**
* @param string[] $dbDomains
*/
public function __construct(FileHandlerFactory $fileHandlerFactory, Resizer $resizer, LocalPathMapper $pathMapper, ThumbsManager $thumbsManager, string $uploadsWebRoot, string $uploadsRealRoot, array $dbDomains, LoggerInterface $logger)
{
$this->fileHandlerFactory = $fileHandlerFactory;
$this->resizer = $resizer;
$this->pathMapper = $pathMapper;
$this->thumbsManager = $thumbsManager;
$this->uploadsWebRoot = $uploadsWebRoot;
$this->uploadsRealRoot = $uploadsRealRoot;
$this->dbDomains = $dbDomains;
$this->logger = $logger;
}
public function onPostUpload(PostUploadEvent $event): void
{
$request = $event->getRequest();
if ((null === $uploadToken = $request->get('uploadToken')) || (null === $domain = $request->get('domain'))) {
return;
}
if (!is_string($uploadToken) || !is_string($domain)) {
return;
}
$requestedWidth = $request->get('requestedWidth');
$requestedHeight = $request->get('requestedHeight');
if (!is_scalar($requestedWidth) || !is_scalar($requestedHeight)) {
return;
}
$requestedWidth = $this->fixJavascriptBug($requestedWidth);
$requestedHeight = $this->fixJavascriptBug($requestedHeight);
$processingType = ((int) $requestedWidth > 0 || (int) $requestedHeight > 0)
? FileHandlerFactory::PROCESS_COPY_SOURCE
: FileHandlerFactory::PROCESS_COPY;
$imageHandler = $this->fileHandlerFactory->createFileHandler(
$domain,
$processingType,
FileHandlerFactory::TYPE_LOCAL_TO_LOCAL
);
$this->logger->debug('Created file handler with domain ' . $domain . ' and processingType ' . $processingType);
/** @var File $file */
$file = $event->getFile();
if (is_a($imageHandler, ImageHandler::class)) {
$file = new File($this->thumbsManager->convertOriginal($domain, $file->getPathname()));
}
/** @var string|null $coordsString */
$coordsString = $request->get('coords');
if (null !== $coordsString && '' !== $coordsString) {
/** @var array<string> $coords */
$coords = json_decode($coordsString, true, 512, JSON_THROW_ON_ERROR);
$this->resizer->crop($file->getPathname(), $coords['x'], $coords['y'], $coords['width'], $coords['height']);
}
$extension = $file->guessExtension() ?? $file->getExtension();
if (in_array($extension, ['asf', '3gp'], true)) {
$extension = $file->getExtension();
}
// workaround when .jpeg is above .jpg in mime.type
if ($extension === 'jpeg' && $file->getExtension() === 'jpg') {
$extension = 'jpg';
}
$finalFilename = $file->getBasename('.' . $file->getExtension()) . '.' . $extension;
$path = sprintf('%s/%s/%s', $this->uploadsRealRoot, $uploadToken, $finalFilename);
$moveStatus = $imageHandler->move($file->getPathname(), $path);
$this->logger->debug('Moved ' . $file->getPathname() . ' to ' . $path . ' status ' . ($moveStatus ? 'true' : 'false'));
/** @var AbstractResponse $response */
$response = $event->getResponse();
$response['name'] = $finalFilename;
$response['webRoot'] = sprintf('%s/%s', $this->uploadsWebRoot, $uploadToken);
$response['status'] = FileModel::STATUS_NEW;
if ($this->isDbFile($domain)) {
$requestFiles = $request->files;
if ($requestFiles->has('file')) {
$requestFile = $requestFiles->get('file');
if (!$requestFile instanceof UploadedFile) {
throw new RuntimeException('Request should contain UploadedFile instances.');
}
$originalName = pathinfo($requestFile->getClientOriginalName(), PATHINFO_BASENAME);
} elseif ($requestFiles->has('files')) {
$originalName = pathinfo($requestFiles->all('files')[0]->getClientOriginalName(), PATHINFO_BASENAME);
} else {
throw new InvalidArgumentException('Can not file file or files[] argument');
}
$response['originalName'] = $originalName;
}
if ($processingType !== FileHandlerFactory::PROCESS_COPY_SOURCE) {
return;
}
$absolutePath = $this->pathMapper->toAbsolute($path);
$this->resizer->resize(
$absolutePath,
$requestedWidth,
$requestedHeight
);
}
private function isDbFile(string $domain): bool
{
return in_array($domain, $this->dbDomains, true);
}
/**
* @param bool|float|int|string $value
*/
private function fixJavascriptBug($value): ?int
{
if ($value === '' || $value === 'null') {
return null;
}
return (int) $value;
}
/**
* @return array<string, array<int|string, array<int|string, int|string>|int|string>|string>
*/
public static function getSubscribedEvents(): array
{
return [
UploadEvents::POST_UPLOAD => 'onPostUpload',
];
}
}