|
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
|
|
|
public function __construct(string $datFile, int $openFlag = null) |
|
46
|
|
|
{ |
|
47
|
|
|
if (false === function_exists('geoip_open')) { |
|
48
|
|
|
throw new FunctionNotFound( |
|
49
|
|
|
'geoip_open', |
|
50
|
|
|
'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoip.inc file?' |
|
51
|
|
|
); |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
if (false === function_exists('GeoIP_record_by_addr')) { |
|
55
|
|
|
throw new FunctionNotFound( |
|
56
|
|
|
'GeoIP_record_by_addr', |
|
57
|
|
|
'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoipcity.inc file?' |
|
58
|
|
|
); |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
if (false === is_file($datFile)) { |
|
62
|
|
|
throw new InvalidArgument(sprintf('Given MaxMind dat file "%s" does not exist.', $datFile)); |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
if (false === is_readable($datFile)) { |
|
66
|
|
|
throw new InvalidArgument(sprintf('Given MaxMind dat file "%s" does not readable.', $datFile)); |
|
67
|
|
|
} |
|
68
|
|
|
|
|
69
|
|
|
$this->datFile = $datFile; |
|
70
|
|
|
$this->openFlag = null === $openFlag ? GEOIP_STANDARD : $openFlag; |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* {@inheritdoc} |
|
75
|
|
|
*/ |
|
76
|
|
|
public function geocodeQuery(GeocodeQuery $query): Collection |
|
77
|
|
|
{ |
|
78
|
|
|
$address = $query->getText(); |
|
79
|
|
|
if (false === filter_var($address, FILTER_VALIDATE_IP)) { |
|
80
|
|
|
throw new UnsupportedOperation('The MaxMindBinary provider does not support street addresses.'); |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
// This API does not support IPv6 |
|
84
|
|
|
if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { |
|
85
|
|
|
throw new UnsupportedOperation('The MaxMindBinary provider does not support IPv6 addresses.'); |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
$geoIp = geoip_open($this->datFile, $this->openFlag); |
|
89
|
|
|
$geoIpRecord = GeoIP_record_by_addr($geoIp, $address); |
|
90
|
|
|
|
|
91
|
|
|
geoip_close($geoIp); |
|
92
|
|
|
|
|
93
|
|
|
if (false === $geoIpRecord instanceof \GeoIpRecord) { |
|
|
|
|
|
|
94
|
|
|
return new AddressCollection([]); |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
$adminLevels = []; |
|
98
|
|
|
|
|
99
|
|
|
if ($geoIpRecord->region) { |
|
100
|
|
|
$adminLevels[] = ['name' => $geoIpRecord->region, 'level' => 1]; |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
return new AddressCollection([ |
|
104
|
|
|
Address::createFromArray([ |
|
105
|
|
|
'providedBy' => $this->getName(), |
|
106
|
|
|
'countryCode' => $geoIpRecord->country_code, |
|
107
|
|
|
'country' => utf8_encode($geoIpRecord->country_name), |
|
108
|
|
|
'adminLevels' => $adminLevels, |
|
109
|
|
|
'locality' => utf8_encode($geoIpRecord->city), |
|
110
|
|
|
'latitude' => $geoIpRecord->latitude, |
|
111
|
|
|
'longitude' => $geoIpRecord->longitude, |
|
112
|
|
|
'postalCode' => $geoIpRecord->postal_code, |
|
113
|
|
|
]), |
|
114
|
|
|
]); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
/** |
|
118
|
|
|
* {@inheritdoc} |
|
119
|
|
|
*/ |
|
120
|
|
|
public function reverseQuery(ReverseQuery $query): Collection |
|
121
|
|
|
{ |
|
122
|
|
|
throw new UnsupportedOperation('The MaxMindBinary is not able to do reverse geocoding.'); |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
/** |
|
126
|
|
|
* {@inheritdoc} |
|
127
|
|
|
*/ |
|
128
|
|
|
public function getName(): string |
|
129
|
|
|
{ |
|
130
|
|
|
return 'maxmind_binary'; |
|
131
|
|
|
} |
|
132
|
|
|
} |
|
133
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.