AzuraCast/src/Service/IpGeolocation.php

114 lines
2.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service;
use App\Service\IpGeolocator;
use Exception;
use MaxMind\Db\Reader;
use Psr\Cache\CacheItemPoolInterface;
use RuntimeException;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
final class IpGeolocation
{
private bool $isInitialized = false;
private ?Reader $reader;
private ?string $readerShortName;
private string $attribution = '';
private CacheItemPoolInterface $psr6Cache;
public function __construct(CacheItemPoolInterface $psr6Cache)
{
$this->psr6Cache = new ProxyAdapter($psr6Cache, 'ip_geo.');
}
private function initialize(): void
{
if ($this->isInitialized) {
return;
}
$this->isInitialized = true;
$readers = [
IpGeolocator\GeoLite::class,
IpGeolocator\DbIp::class,
];
foreach ($readers as $reader) {
/** @var IpGeolocator\IpGeolocatorInterface $reader */
if ($reader::isAvailable()) {
$this->reader = $reader::getReader();
$this->readerShortName = $reader::getReaderShortName();
$this->attribution = $reader::getAttribution();
return;
}
}
$this->reader = null;
$this->readerShortName = null;
$this->attribution = __(
'GeoLite database not configured for this installation. See System Administration for instructions.'
);
}
public function getAttribution(): string
{
if (!$this->isInitialized) {
$this->initialize();
}
return $this->attribution;
}
public function getLocationInfo(string $ip): IpGeolocator\IpResult
{
if (!$this->isInitialized) {
$this->initialize();
}
$reader = $this->reader;
if (null === $reader) {
throw new RuntimeException('No IP Geolocation reader available.');
}
$cacheKey = $this->readerShortName . '_' . str_replace([':', '.'], '_', $ip);
$cacheItem = $this->psr6Cache->getItem($cacheKey);
if (!$cacheItem->isHit()) {
try {
$ipInfo = $reader->get($ip);
if (!empty($ipInfo)) {
return $ipInfo;
}
$cacheItem->set([
'status' => 'error',
'message' => 'Internal/Reserved IP',
]);
} catch (Exception $e) {
$cacheItem->set([
'status' => 'error',
'message' => $e->getMessage(),
]);
}
/** @noinspection SummerTimeUnsafeTimeManipulationInspection */
$cacheItem->expiresAfter(86400 * 7);
$this->psr6Cache->saveDeferred($cacheItem);
}
$ipInfo = $cacheItem->get();
return IpGeolocator\IpResult::fromIpInfo($ip, $ipInfo);
}
}