diff --git a/module/Core/functions/functions.php b/module/Core/functions/functions.php index f26cb84f..586195da 100644 --- a/module/Core/functions/functions.php +++ b/module/Core/functions/functions.php @@ -26,7 +26,9 @@ use function print_r; use function Shlinkio\Shlink\Common\buildDateRange; use function sprintf; use function str_repeat; +use function str_replace; use function strtolower; +use function trim; use function ucfirst; function generateRandomShortCode(int $length, ShortUrlMode $mode = ShortUrlMode::STRICT): string @@ -74,6 +76,11 @@ function normalizeDate(string|DateTimeInterface|Chronos $date): Chronos return normalizeOptionalDate($date); } +function normalizeLocale(string $locale): string +{ + return trim(strtolower(str_replace('_', '-', $locale))); +} + function getOptionalIntFromInputFilter(InputFilter $inputFilter, string $fieldName): ?int { $value = $inputFilter->getValue($fieldName); diff --git a/module/Core/src/RedirectRule/Entity/RedirectCondition.php b/module/Core/src/RedirectRule/Entity/RedirectCondition.php index 367d96d9..72960d82 100644 --- a/module/Core/src/RedirectRule/Entity/RedirectCondition.php +++ b/module/Core/src/RedirectRule/Entity/RedirectCondition.php @@ -2,9 +2,14 @@ namespace Shlinkio\Shlink\Core\RedirectRule\Entity; +use Psr\Http\Message\ServerRequestInterface; use Shlinkio\Shlink\Common\Entity\AbstractEntity; use Shlinkio\Shlink\Core\RedirectRule\Model\RedirectConditionType; +use function explode; +use function Shlinkio\Shlink\Core\ArrayUtils\some; +use function Shlinkio\Shlink\Core\normalizeLocale; + class RedirectCondition extends AbstractEntity { public function __construct( @@ -14,4 +19,28 @@ class RedirectCondition extends AbstractEntity public readonly ?string $matchKey = null, ) { } + + /** + * Tells if this condition matches provided request + */ + public function matchesRequest(ServerRequestInterface $request): bool + { + if ($this->type === RedirectConditionType::QUERY_PARAM && $this->matchKey !== null) { + $query = $request->getQueryParams(); + $queryValue = $query[$this->matchKey] ?? null; + return $queryValue === $this->matchValue; + } + + if ($this->type === RedirectConditionType::LANGUAGE && $request->hasHeader('Accept-Language')) { + $acceptedLanguages = explode(',', $request->getHeaderLine('Accept-Language')); + $normalizedLanguage = normalizeLocale($this->matchValue); + + return some( + $acceptedLanguages, + static fn (string $lang) => normalizeLocale($lang) === $normalizedLanguage, + ); + } + + return false; + } } diff --git a/module/Core/src/RedirectRule/Model/RedirectConditionType.php b/module/Core/src/RedirectRule/Model/RedirectConditionType.php index 6e6b8113..764c5a2b 100644 --- a/module/Core/src/RedirectRule/Model/RedirectConditionType.php +++ b/module/Core/src/RedirectRule/Model/RedirectConditionType.php @@ -4,7 +4,7 @@ namespace Shlinkio\Shlink\Core\RedirectRule\Model; enum RedirectConditionType: string { - case DEVICE = 'device'; -// case LANGUAGE = 'language'; -// case QUERY_PARAM = 'query'; +// case DEVICE = 'device'; + case LANGUAGE = 'language'; + case QUERY_PARAM = 'query'; }