<?php
namespace Plugin\NZRecaptcha42\Event;
use Plugin\NZRecaptcha42\Service\RecaptchaService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class RecaptchaEventSubscriber implements EventSubscriberInterface
{
/**
* @var RecaptchaService
*/
private $recaptchaService;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var UrlGeneratorInterface
*/
private $urlGenerator;
public function __construct(
RecaptchaService $recaptchaService,
RequestStack $requestStack,
UrlGeneratorInterface $urlGenerator
) {
$this->recaptchaService = $recaptchaService;
$this->requestStack = $requestStack;
$this->urlGenerator = $urlGenerator;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 9],
];
}
public function onKernelRequest(RequestEvent $event)
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
// POSTリクエストのみ検証
if ($request->getMethod() !== 'POST') {
return;
}
$route = $request->attributes->get('_route');
$pathInfo = $request->getPathInfo();
// 対象ルートとアクションの対応
$routeConfig = [
'entry' => ['action' => 'entry', 'check' => 'isEnabledForEntry', 'redirect' => 'entry'],
'mypage_login' => ['action' => 'login', 'check' => 'isEnabledForLogin', 'redirect' => 'mypage_login'],
'contact' => ['action' => 'contact', 'check' => 'isEnabledForContact', 'redirect' => 'contact'],
];
// カスタムルート/URLをチェック
$isCustomTarget = $this->recaptchaService->isEnabledForCustomRoute($route, $pathInfo);
if (!isset($routeConfig[$route]) && !$isCustomTarget) {
return;
}
// カスタムルート/URLの場合
if ($isCustomTarget && !isset($routeConfig[$route])) {
$token = $request->request->get('g-recaptcha-response');
$action = $route ?: str_replace('/', '_', trim($pathInfo, '/'));
if (!$this->recaptchaService->verify($token, $action)) {
log_warning('[NZRecaptcha] Blocked custom request', [
'route' => $route,
'path' => $pathInfo,
'ip' => $request->getClientIp(),
]);
$session = $request->getSession();
$session->getFlashBag()->add('eccube.front.error', 'セキュリティ検証に失敗しました。もう一度お試しください。');
$redirectUrl = $request->getUri();
$event->setResponse(new RedirectResponse($redirectUrl));
}
return;
}
$config = $routeConfig[$route];
$checkMethod = $config['check'];
// この機能が有効かチェック
if (!$this->recaptchaService->$checkMethod()) {
return;
}
// reCAPTCHAトークンを取得
$token = $request->request->get('g-recaptcha-response');
// トークン検証
if (!$this->recaptchaService->verify($token, $config['action'])) {
log_warning('[NZRecaptcha] Blocked request', [
'route' => $route,
'ip' => $request->getClientIp(),
]);
$session = $request->getSession();
$session->getFlashBag()->add('eccube.front.error', 'セキュリティ検証に失敗しました。もう一度お試しください。');
$redirectUrl = $this->urlGenerator->generate($config['redirect']);
$event->setResponse(new RedirectResponse($redirectUrl));
}
}
}