2019-12-31 13:49:25 +01:00
|
|
|
<?php
|
2020-10-15 00:19:31 +02:00
|
|
|
|
2021-07-19 07:53:45 +02:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
2019-12-31 13:49:25 +01:00
|
|
|
namespace App\Service;
|
|
|
|
|
2020-01-22 11:48:02 +01:00
|
|
|
use App\Service\IpGeolocator;
|
2020-07-08 09:03:50 +02:00
|
|
|
use Exception;
|
2019-12-31 13:49:25 +01:00
|
|
|
use MaxMind\Db\Reader;
|
2021-03-02 13:32:58 +01:00
|
|
|
use Psr\Cache\CacheItemPoolInterface;
|
2022-05-08 20:05:02 +02:00
|
|
|
use RuntimeException;
|
2021-03-02 13:32:58 +01:00
|
|
|
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2022-07-01 08:06:29 +02:00
|
|
|
final class IpGeolocation
|
2019-12-31 13:49:25 +01:00
|
|
|
{
|
2022-07-01 08:06:29 +02:00
|
|
|
private bool $isInitialized = false;
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2022-07-01 08:06:29 +02:00
|
|
|
private ?Reader $reader;
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2022-07-01 08:06:29 +02:00
|
|
|
private ?string $readerShortName;
|
2021-03-02 13:32:58 +01:00
|
|
|
|
2022-07-01 08:06:29 +02:00
|
|
|
private string $attribution = '';
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2023-03-02 15:33:57 +01:00
|
|
|
private CacheItemPoolInterface $psr6Cache;
|
2021-03-02 13:32:58 +01:00
|
|
|
|
2022-02-15 06:21:56 +01:00
|
|
|
public function __construct(CacheItemPoolInterface $psr6Cache)
|
2021-03-02 13:32:58 +01:00
|
|
|
{
|
2023-03-02 15:33:57 +01:00
|
|
|
$this->psr6Cache = new ProxyAdapter($psr6Cache, 'ip_geo.');
|
2021-03-02 13:32:58 +01:00
|
|
|
}
|
|
|
|
|
2022-07-01 08:06:29 +02:00
|
|
|
private function initialize(): void
|
2020-01-08 21:37:56 +01:00
|
|
|
{
|
2020-01-22 11:48:02 +01:00
|
|
|
if ($this->isInitialized) {
|
|
|
|
return;
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
2020-01-08 21:37:56 +01:00
|
|
|
|
2020-01-22 11:48:02 +01:00
|
|
|
$this->isInitialized = true;
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2020-01-22 11:48:02 +01:00
|
|
|
$readers = [
|
|
|
|
IpGeolocator\GeoLite::class,
|
|
|
|
IpGeolocator\DbIp::class,
|
|
|
|
];
|
|
|
|
|
|
|
|
foreach ($readers as $reader) {
|
|
|
|
/** @var IpGeolocator\IpGeolocatorInterface $reader */
|
|
|
|
if ($reader::isAvailable()) {
|
|
|
|
$this->reader = $reader::getReader();
|
2021-03-02 13:32:58 +01:00
|
|
|
$this->readerShortName = $reader::getReaderShortName();
|
2020-01-22 11:48:02 +01:00
|
|
|
$this->attribution = $reader::getAttribution();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->reader = null;
|
2021-03-02 13:32:58 +01:00
|
|
|
$this->readerShortName = null;
|
2020-10-15 00:19:31 +02:00
|
|
|
$this->attribution = __(
|
|
|
|
'GeoLite database not configured for this installation. See System Administration for instructions.'
|
|
|
|
);
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
|
|
|
|
2020-01-22 11:48:02 +01:00
|
|
|
public function getAttribution(): string
|
2019-12-31 13:49:25 +01:00
|
|
|
{
|
2020-01-22 11:48:02 +01:00
|
|
|
if (!$this->isInitialized) {
|
|
|
|
$this->initialize();
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
|
|
|
|
2020-01-22 11:48:02 +01:00
|
|
|
return $this->attribution;
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
|
|
|
|
2022-04-21 08:31:23 +02:00
|
|
|
public function getLocationInfo(string $ip): IpGeolocator\IpResult
|
2019-12-31 13:49:25 +01:00
|
|
|
{
|
2020-01-22 11:48:02 +01:00
|
|
|
if (!$this->isInitialized) {
|
|
|
|
$this->initialize();
|
|
|
|
}
|
|
|
|
|
2021-07-19 07:53:45 +02:00
|
|
|
$reader = $this->reader;
|
|
|
|
if (null === $reader) {
|
2022-05-08 20:05:02 +02:00
|
|
|
throw new RuntimeException('No IP Geolocation reader available.');
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
|
|
|
|
2021-03-02 13:32:58 +01:00
|
|
|
$cacheKey = $this->readerShortName . '_' . str_replace([':', '.'], '_', $ip);
|
|
|
|
|
2023-03-02 15:33:57 +01:00
|
|
|
$cacheItem = $this->psr6Cache->getItem($cacheKey);
|
|
|
|
|
|
|
|
if (!$cacheItem->isHit()) {
|
|
|
|
try {
|
|
|
|
$ipInfo = $reader->get($ip);
|
|
|
|
if (!empty($ipInfo)) {
|
|
|
|
return $ipInfo;
|
2021-03-02 13:32:58 +01:00
|
|
|
}
|
2023-03-02 15:33:57 +01:00
|
|
|
|
|
|
|
$cacheItem->set([
|
|
|
|
'status' => 'error',
|
|
|
|
'message' => 'Internal/Reserved IP',
|
|
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
|
|
$cacheItem->set([
|
|
|
|
'status' => 'error',
|
|
|
|
'message' => $e->getMessage(),
|
|
|
|
]);
|
2021-03-02 13:32:58 +01:00
|
|
|
}
|
2023-03-02 15:33:57 +01:00
|
|
|
|
|
|
|
/** @noinspection SummerTimeUnsafeTimeManipulationInspection */
|
|
|
|
$cacheItem->expiresAfter(86400 * 7);
|
|
|
|
|
|
|
|
$this->psr6Cache->saveDeferred($cacheItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
$ipInfo = $cacheItem->get();
|
2019-12-31 13:49:25 +01:00
|
|
|
|
2022-04-21 08:31:23 +02:00
|
|
|
return IpGeolocator\IpResult::fromIpInfo($ip, $ipInfo);
|
2019-12-31 13:49:25 +01:00
|
|
|
}
|
2020-10-15 00:19:31 +02:00
|
|
|
}
|