QrCodeAction.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php
  2. declare(strict_types=1);
  3. namespace Shlinkio\Shlink\Core\Action;
  4. use Endroid\QrCode\QrCode;
  5. use Mezzio\Router\Exception\RuntimeException;
  6. use Mezzio\Router\RouterInterface;
  7. use Psr\Http\Message\ResponseInterface as Response;
  8. use Psr\Http\Message\ServerRequestInterface as Request;
  9. use Psr\Http\Server\MiddlewareInterface;
  10. use Psr\Http\Server\RequestHandlerInterface;
  11. use Psr\Log\LoggerInterface;
  12. use Psr\Log\NullLogger;
  13. use Shlinkio\Shlink\Common\Response\QrCodeResponse;
  14. use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
  15. use Shlinkio\Shlink\Core\Service\UrlShortenerInterface;
  16. class QrCodeAction implements MiddlewareInterface
  17. {
  18. private const DEFAULT_SIZE = 300;
  19. private const MIN_SIZE = 50;
  20. private const MAX_SIZE = 1000;
  21. private RouterInterface $router;
  22. private UrlShortenerInterface $urlShortener;
  23. private LoggerInterface $logger;
  24. public function __construct(
  25. RouterInterface $router,
  26. UrlShortenerInterface $urlShortener,
  27. ?LoggerInterface $logger = null
  28. ) {
  29. $this->router = $router;
  30. $this->urlShortener = $urlShortener;
  31. $this->logger = $logger ?: new NullLogger();
  32. }
  33. /**
  34. * Process an incoming server request and return a response, optionally delegating
  35. * to the next middleware component to create the response.
  36. *
  37. *
  38. * @throws \InvalidArgumentException
  39. * @throws RuntimeException
  40. */
  41. public function process(Request $request, RequestHandlerInterface $handler): Response
  42. {
  43. // Make sure the short URL exists for this short code
  44. $shortCode = $request->getAttribute('shortCode');
  45. $domain = $request->getUri()->getAuthority();
  46. try {
  47. $this->urlShortener->shortCodeToUrl($shortCode, $domain);
  48. } catch (ShortUrlNotFoundException $e) {
  49. $this->logger->warning('An error occurred while creating QR code. {e}', ['e' => $e]);
  50. return $handler->handle($request);
  51. }
  52. $path = $this->router->generateUri(RedirectAction::class, ['shortCode' => $shortCode]);
  53. $size = $this->getSizeParam($request);
  54. $qrCode = new QrCode((string) $request->getUri()->withPath($path)->withQuery(''));
  55. $qrCode->setSize($size);
  56. $qrCode->setMargin(0);
  57. return new QrCodeResponse($qrCode);
  58. }
  59. /**
  60. */
  61. private function getSizeParam(Request $request): int
  62. {
  63. $size = (int) $request->getAttribute('size', self::DEFAULT_SIZE);
  64. if ($size < self::MIN_SIZE) {
  65. return self::MIN_SIZE;
  66. }
  67. return $size > self::MAX_SIZE ? self::MAX_SIZE : $size;
  68. }
  69. }