Code

< 40 %
40-60 %
> 60 %
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Geocoder package.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT License
11
 */
12
13
namespace Geocoder\Provider\MaxMindBinary;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\FunctionNotFound;
17
use Geocoder\Exception\InvalidArgument;
18
use Geocoder\Exception\UnsupportedOperation;
19
use Geocoder\Model\Address;
20
use Geocoder\Model\AddressCollection;
21
use Geocoder\Query\GeocodeQuery;
22
use Geocoder\Query\ReverseQuery;
23
use Geocoder\Provider\AbstractProvider;
24
use Geocoder\Provider\Provider;
25
26
final class MaxMindBinary extends AbstractProvider implements Provider
27
{
28
    /**
29
     * @var string
30
     */
31
    private $datFile;
32
33
    /**
34
     * @var int|null
35
     */
36
    private $openFlag;
37
38
    /**
39
     * @param string   $datFile
40
     * @param int|null $openFlag
41
     *
42
     * @throws FunctionNotFound if maxmind's lib not installed
43
     * @throws InvalidArgument  if dat file is not correct (optional)
44
     */
45 12
    public function __construct(string $datFile, int $openFlag = null)
46
    {
47 12
        if (false === function_exists('geoip_open')) {
48
            throw new FunctionNotFound('geoip_open', 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoip.inc file?');
49
        }
50
51 12
        if (false === function_exists('GeoIP_record_by_addr')) {
52
            throw new FunctionNotFound('GeoIP_record_by_addr', 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoipcity.inc file?');
53
        }
54
55 12
        if (false === is_file($datFile)) {
56 1
            throw new InvalidArgument(sprintf('Given MaxMind dat file "%s" does not exist.', $datFile));
57
        }
58
59 11
        if (false === is_readable($datFile)) {
60
            throw new InvalidArgument(sprintf('Given MaxMind dat file "%s" does not readable.', $datFile));
61
        }
62
63 11
        $this->datFile = $datFile;
64 11
        $this->openFlag = null === $openFlag ? GEOIP_STANDARD : $openFlag;
65 11
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70 9
    public function geocodeQuery(GeocodeQuery $query): Collection
71
    {
72 9
        $address = $query->getText();
73 9
        if (false === filter_var($address, FILTER_VALIDATE_IP)) {
74 1
            throw new UnsupportedOperation('The MaxMindBinary provider does not support street addresses.');
75
        }
76
77
        // This API does not support IPv6
78 8
        if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
79 1
            throw new UnsupportedOperation('The MaxMindBinary provider does not support IPv6 addresses.');
80
        }
81
82 7
        $geoIp = geoip_open($this->datFile, $this->openFlag);
83 7
        $geoIpRecord = GeoIP_record_by_addr($geoIp, $address);
84
85 7
        geoip_close($geoIp);
86
87 7
        if (false === $geoIpRecord instanceof \GeoIpRecord) {
88 1
            return new AddressCollection([]);
89
        }
90
91 6
        $adminLevels = [];
92
93 6
        if ($geoIpRecord->region) {
94 6
            $adminLevels[] = ['name' => $geoIpRecord->region, 'level' => 1];
95
        }
96
97 6
        return new AddressCollection([
98 6
            Address::createFromArray([
99 6
                'providedBy' => $this->getName(),
100 6
                'countryCode' => $geoIpRecord->country_code,
101 6
                'country' => null === $geoIpRecord->country_name ? null : utf8_encode($geoIpRecord->country_name),
102 6
                'adminLevels' => $adminLevels,
103 6
                'locality' => null === $geoIpRecord->city ? null : utf8_encode($geoIpRecord->city),
104 6
                'latitude' => $geoIpRecord->latitude,
105 6
                'longitude' => $geoIpRecord->longitude,
106 6
                'postalCode' => $geoIpRecord->postal_code,
107
            ]),
108
        ]);
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114 1
    public function reverseQuery(ReverseQuery $query): Collection
115
    {
116 1
        throw new UnsupportedOperation('The MaxMindBinary is not able to do reverse geocoding.');
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 7
    public function getName(): string
123
    {
124 7
        return 'maxmind_binary';
125
    }
126
}
127