Leuchtfeuer/locate

View on GitHub
Classes/Utility/LocateUtility.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

declare(strict_types=1);

/*
 * This file is part of the "Locate" extension for TYPO3 CMS.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * Team YD <dev@Leuchtfeuer.com>, Leuchtfeuer Digital Marketing
 */

namespace Leuchtfeuer\Locate\Utility;

use Doctrine\DBAL\Exception;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class LocateUtility
{
    /**
     * Check the IP in the geoip table and returns iso 2 code for the current remote address
     *
     * @param string|null $ip
     * @return bool|string
     * @throws Exception
     */
    public function getCountryIso2FromIP(?string $ip = null): bool|string
    {
        $ip = $this->getNumericIp($ip);
        if ($ip === false) {
            return false;
        }
        $tableName = $this->getTableNameForIp($ip);
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);

        return $queryBuilder
            ->select('country_code')
            ->from($tableName)
            ->where($queryBuilder->expr()->lte('ip_from', $queryBuilder->createNamedParameter($ip)))->andWhere($queryBuilder->expr()->gte('ip_to', $queryBuilder->createNamedParameter($ip)))->executeQuery()
            ->fetchOne();
    }

    public function getNumericIp(?string $ip = null): string|bool
    {
        $ip = $ip ?? $this->getRemoteAddress();

        return str_contains($ip, '.') ? (string)ip2long($ip) : $this->convertIpv6($ip);
    }

    protected function getRemoteAddress(): ?string
    {
        $remoteAddr = $this->getHeader('X-Forwarded-For');
        if (!empty($remoteAddr)) {
            return $remoteAddr;
        }
        return (string)GeneralUtility::getIndpEnv('REMOTE_ADDR');
    }

    protected function getHeader(string $headerName): ?string
    {
        $headers = getallheaders();
        return $headers[$headerName] ?? null;
    }

    private function convertIpv6(string $ip): string|bool
    {
        $ip = inet_pton($ip);
        $bin = '';
        $binNum = '';
        $decimalIp = '0';

        if (is_bool($ip)) {
            return false;
        }

        for ($bit = strlen($ip) - 1; $bit >= 0; $bit--) {
            $bin = sprintf('%08b', ord($ip[$bit])) . $bin;
        }

        switch (true) {
            case function_exists('gmp_init'):
                $decimalIp = gmp_strval(gmp_init($bin, 2), 10);
                break;

            case function_exists('bcadd'):
                $max = strlen($bin);
                for ($i = 0; $i < $max; $i++) {
                    $decimalIp = bcmul($decimalIp, '2');
                    $decimalIp = bcadd($decimalIp, $bin[$i]);
                }
                break;

            default:
                foreach (unpack('C*', $ip) as $byte) {
                    $binNum .= str_pad(decbin($byte), 8, '0', STR_PAD_LEFT);
                }

                $decimalIp = base_convert(ltrim($binNum, '0'), 2, 10);
        }

        return $decimalIp;
    }

    public static function mainstreamValue(string &$value): void
    {
        $value = mb_strtolower(str_replace('-', '_', $value));
    }

    protected function getTableNameForIp(string $ip): string
    {
        return strlen($ip) > 10 ? 'static_ip2country_v6' : 'static_ip2country_v4';
    }
}