Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 3 declare(strict_types=1); 4 5 namespace GeoIp2\Database; 6 7 use GeoIp2\Exception\AddressNotFoundException; 8 use GeoIp2\Model\AbstractModel; 9 use GeoIp2\Model\AnonymousIp; 10 use GeoIp2\Model\Asn; 11 use GeoIp2\Model\City; 12 use GeoIp2\Model\ConnectionType; 13 use GeoIp2\Model\Country; 14 use GeoIp2\Model\Domain; 15 use GeoIp2\Model\Enterprise; 16 use GeoIp2\Model\Isp; 17 use GeoIp2\ProviderInterface; 18 use MaxMind\Db\Reader as DbReader; 19 use MaxMind\Db\Reader\InvalidDatabaseException; 20 21 /** 22 * Instances of this class provide a reader for the GeoIP2 database format. 23 * IP addresses can be looked up using the database specific methods. 24 * 25 * ## Usage ## 26 * 27 * The basic API for this class is the same for every database. First, you 28 * create a reader object, specifying a file name. You then call the method 29 * corresponding to the specific database, passing it the IP address you want 30 * to look up. 31 * 32 * If the request succeeds, the method call will return a model class for 33 * the method you called. This model in turn contains multiple record classes, 34 * each of which represents part of the data returned by the database. If 35 * the database does not contain the requested information, the attributes 36 * on the record class will have a `null` value. 37 * 38 * If the address is not in the database, an 39 * {@link \GeoIp2\Exception\AddressNotFoundException} exception will be 40 * thrown. If an invalid IP address is passed to one of the methods, a 41 * SPL {@link \InvalidArgumentException} will be thrown. If the database is 42 * corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException} 43 * will be thrown. 44 */ 45 class Reader implements ProviderInterface 46 { 47 /** 48 * @var DbReader 49 */ 50 private $dbReader; 51 52 /** 53 * @var string 54 */ 55 private $dbType; 56 57 /** 58 * @var array<string> 59 */ 60 private $locales; 61 62 /** 63 * Constructor. 64 * 65 * @param string $filename the path to the GeoIP2 database file 66 * @param array $locales list of locale codes to use in name property 67 * from most preferred to least preferred 68 * 69 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 70 * is corrupt or invalid 71 */ 72 public function __construct( 73 string $filename, 74 array $locales = ['en'] 75 ) { 76 $this->dbReader = new DbReader($filename); 77 $this->dbType = $this->dbReader->metadata()->databaseType; 78 $this->locales = $locales; 79 } 80 81 /** 82 * This method returns a GeoIP2 City model. 83 * 84 * @param string $ipAddress an IPv4 or IPv6 address as a string 85 * 86 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 87 * not in the database 88 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 89 * is corrupt or invalid 90 */ 91 public function city(string $ipAddress): City 92 { 93 // @phpstan-ignore-next-line 94 return $this->modelFor(City::class, 'City', $ipAddress); 95 } 96 97 /** 98 * This method returns a GeoIP2 Country model. 99 * 100 * @param string $ipAddress an IPv4 or IPv6 address as a string 101 * 102 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 103 * not in the database 104 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 105 * is corrupt or invalid 106 */ 107 public function country(string $ipAddress): Country 108 { 109 // @phpstan-ignore-next-line 110 return $this->modelFor(Country::class, 'Country', $ipAddress); 111 } 112 113 /** 114 * This method returns a GeoIP2 Anonymous IP model. 115 * 116 * @param string $ipAddress an IPv4 or IPv6 address as a string 117 * 118 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 119 * not in the database 120 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 121 * is corrupt or invalid 122 */ 123 public function anonymousIp(string $ipAddress): AnonymousIp 124 { 125 // @phpstan-ignore-next-line 126 return $this->flatModelFor( 127 AnonymousIp::class, 128 'GeoIP2-Anonymous-IP', 129 $ipAddress 130 ); 131 } 132 133 /** 134 * This method returns a GeoLite2 ASN model. 135 * 136 * @param string $ipAddress an IPv4 or IPv6 address as a string 137 * 138 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 139 * not in the database 140 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 141 * is corrupt or invalid 142 */ 143 public function asn(string $ipAddress): Asn 144 { 145 // @phpstan-ignore-next-line 146 return $this->flatModelFor( 147 Asn::class, 148 'GeoLite2-ASN', 149 $ipAddress 150 ); 151 } 152 153 /** 154 * This method returns a GeoIP2 Connection Type model. 155 * 156 * @param string $ipAddress an IPv4 or IPv6 address as a string 157 * 158 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 159 * not in the database 160 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 161 * is corrupt or invalid 162 */ 163 public function connectionType(string $ipAddress): ConnectionType 164 { 165 // @phpstan-ignore-next-line 166 return $this->flatModelFor( 167 ConnectionType::class, 168 'GeoIP2-Connection-Type', 169 $ipAddress 170 ); 171 } 172 173 /** 174 * This method returns a GeoIP2 Domain model. 175 * 176 * @param string $ipAddress an IPv4 or IPv6 address as a string 177 * 178 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 179 * not in the database 180 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 181 * is corrupt or invalid 182 */ 183 public function domain(string $ipAddress): Domain 184 { 185 // @phpstan-ignore-next-line 186 return $this->flatModelFor( 187 Domain::class, 188 'GeoIP2-Domain', 189 $ipAddress 190 ); 191 } 192 193 /** 194 * This method returns a GeoIP2 Enterprise model. 195 * 196 * @param string $ipAddress an IPv4 or IPv6 address as a string 197 * 198 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 199 * not in the database 200 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 201 * is corrupt or invalid 202 */ 203 public function enterprise(string $ipAddress): Enterprise 204 { 205 // @phpstan-ignore-next-line 206 return $this->modelFor(Enterprise::class, 'Enterprise', $ipAddress); 207 } 208 209 /** 210 * This method returns a GeoIP2 ISP model. 211 * 212 * @param string $ipAddress an IPv4 or IPv6 address as a string 213 * 214 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is 215 * not in the database 216 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database 217 * is corrupt or invalid 218 */ 219 public function isp(string $ipAddress): Isp 220 { 221 // @phpstan-ignore-next-line 222 return $this->flatModelFor( 223 Isp::class, 224 'GeoIP2-ISP', 225 $ipAddress 226 ); 227 } 228 229 private function modelFor(string $class, string $type, string $ipAddress): AbstractModel 230 { 231 [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); 232 233 $record['traits']['ip_address'] = $ipAddress; 234 $record['traits']['prefix_len'] = $prefixLen; 235 236 return new $class($record, $this->locales); 237 } 238 239 private function flatModelFor(string $class, string $type, string $ipAddress): AbstractModel 240 { 241 [$record, $prefixLen] = $this->getRecord($class, $type, $ipAddress); 242 243 $record['ip_address'] = $ipAddress; 244 $record['prefix_len'] = $prefixLen; 245 246 return new $class($record); 247 } 248 249 private function getRecord(string $class, string $type, string $ipAddress): array 250 { 251 if (strpos($this->dbType, $type) === false) { 252 $method = lcfirst((new \ReflectionClass($class))->getShortName()); 253 254 throw new \BadMethodCallException( 255 "The $method method cannot be used to open a {$this->dbType} database" 256 ); 257 } 258 [$record, $prefixLen] = $this->dbReader->getWithPrefixLen($ipAddress); 259 if ($record === null) { 260 throw new AddressNotFoundException( 261 "The address $ipAddress is not in the database." 262 ); 263 } 264 if (!\is_array($record)) { 265 // This can happen on corrupt databases. Generally, 266 // MaxMind\Db\Reader will throw a 267 // MaxMind\Db\Reader\InvalidDatabaseException, but occasionally 268 // the lookup may result in a record that looks valid but is not 269 // an array. This mostly happens when the user is ignoring all 270 // exceptions and the more frequent InvalidDatabaseException 271 // exceptions go unnoticed. 272 throw new InvalidDatabaseException( 273 "Expected an array when looking up $ipAddress but received: " 274 . \gettype($record) 275 ); 276 } 277 278 return [$record, $prefixLen]; 279 } 280 281 /** 282 * @throws \InvalidArgumentException if arguments are passed to the method 283 * @throws \BadMethodCallException if the database has been closed 284 * 285 * @return \MaxMind\Db\Reader\Metadata object for the database 286 */ 287 public function metadata(): DbReader\Metadata 288 { 289 return $this->dbReader->metadata(); 290 } 291 292 /** 293 * Closes the GeoIP2 database and returns the resources to the system. 294 */ 295 public function close(): void 296 { 297 $this->dbReader->close(); 298 } 299 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body