src/Eccube/EventListener/RateLimiterListener.php line 39

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\EventListener;
  13. use Eccube\Common\EccubeConfig;
  14. use Eccube\Entity\Customer;
  15. use Eccube\Request\Context;
  16. use Psr\Container\ContainerInterface;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  19. use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
  20. use Symfony\Component\HttpKernel\KernelEvents;
  21. use Symfony\Component\RateLimiter\RateLimiterFactory;
  22. class RateLimiterListener implements EventSubscriberInterface
  23. {
  24.     private ContainerInterface $locator;
  25.     private EccubeConfig $eccubeConfig;
  26.     private Context $requestContext;
  27.     public function __construct(ContainerInterface $locatorEccubeConfig $eccubeConfigContext $requestContext)
  28.     {
  29.         $this->locator $locator;
  30.         $this->eccubeConfig $eccubeConfig;
  31.         $this->requestContext $requestContext;
  32.     }
  33.     public function onController(ControllerEvent $event)
  34.     {
  35.         if (!$event->isMainRequest()) {
  36.             return;
  37.         }
  38.         $request $event->getRequest();
  39.         $route $request->attributes->get('_route');
  40.         $limiterConfigs $this->eccubeConfig['eccube_rate_limiter_configs'];
  41.         if (!isset($limiterConfigs[$route])) {
  42.             return;
  43.         }
  44.         $method $request->getMethod();
  45.         foreach ($limiterConfigs[$route] as $id => $config) {
  46.             $methods array_filter($config['method'], fn ($m) => $m === $method);
  47.             if (empty($methods)) {
  48.                 // http methodが不一致であればスキップ
  49.                 continue;
  50.             }
  51.             if (!empty($config['params'])) {
  52.                 $matchParams array_filter($config['params'], function ($value$key) use ($request) {
  53.                     return $request->get($key) === $value;
  54.                 }, ARRAY_FILTER_USE_BOTH);
  55.                 if (count($config['params']) !== count($matchParams)) {
  56.                     // パラメータが不一致であればスキップ
  57.                     continue;
  58.                 }
  59.             }
  60.             $limiterId 'limiter.'.$id;
  61.             if (!$this->locator->has($limiterId)) {
  62.                 continue;
  63.             }
  64.             /** @var RateLimiterFactory $factory */
  65.             $factory $this->locator->get($limiterId);
  66.             if (in_array('customer'$config['type'])) {
  67.                 $User $this->requestContext->getCurrentUser();
  68.                 if ($User instanceof Customer) {
  69.                     $limiter $factory->create($User->getId());
  70.                     if (!$limiter->consume()->isAccepted()) {
  71.                         throw new TooManyRequestsHttpException();
  72.                     }
  73.                 }
  74.             }
  75.             if (in_array('ip'$config['type'])) {
  76.                 $limiter $factory->create($request->getClientIp());
  77.                 if (!$limiter->consume()->isAccepted()) {
  78.                     throw new TooManyRequestsHttpException();
  79.                 }
  80.             }
  81.         }
  82.     }
  83.     /**
  84.      * {@inheritdoc}
  85.      */
  86.     public static function getSubscribedEvents()
  87.     {
  88.         return [
  89.             KernelEvents::CONTROLLER => ['onController'0],
  90.         ];
  91.     }
  92. }