1: <?php
2:
3: namespace GeoIp2\Database;
4:
5: use GeoIp2\Exception\AddressNotFoundException;
6: use GeoIp2\ProviderInterface;
7: use MaxMind\Db\Reader as DbReader;
8:
9: /**
10: * Instances of this class provide a reader for the GeoIP2 database format.
11: * IP addresses can be looked up using the <code>country</code>
12: * and <code>city</code> methods. We also provide <code>cityIspOrg</code>
13: * and <code>omni</code> methods to ease compatibility with the web service
14: * client, although we may offer the ability to specify additional databases
15: * to replicate these web services in the future (e.g., the ISP/Org database).
16: *
17: * **Usage**
18: *
19: * The basic API for this class is the same for every database. First, you
20: * create a reader object, specifying a file name. You then call the method
21: * corresponding to the specific database, passing it the IP address you want
22: * to look up.
23: *
24: * If the request succeeds, the method call will return a model class for
25: * the method you called. This model in turn contains multiple record classes,
26: * each of which represents part of the data returned by the database. If
27: * the database does not contain the requested information, the attributes
28: * on the record class will have a <code>null</code> value.
29: *
30: * If the address is not in the database, an
31: * {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
32: * thrown. If an invalid IP address is passed to one of the methods, a
33: * SPL {@link \InvalidArgumentException} will be thrown. If the database is
34: * corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
35: * will be thrown.
36: *
37: */
38: class Reader implements ProviderInterface
39: {
40: private $dbReader;
41: private $locales;
42:
43: /**
44: * Constructor.
45: *
46: * @param string $filename The path to the GeoIP2 database file.
47: * @param array $locales List of locale codes to use in name property
48: * from most preferred to least preferred.
49: * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
50: * is corrupt or invalid
51: */
52: public function __construct(
53: $filename,
54: $locales = array('en')
55: ) {
56: $this->dbReader = new DbReader($filename);
57: $this->locales = $locales;
58: }
59:
60: /**
61: * This method returns a GeoIP2 City model.
62: *
63: * @param string $ipAddress IPv4 or IPv6 address as a string.
64: *
65: * @return \GeoIp2\Model\City
66: *
67: * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
68: * not in the database.
69: * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
70: * is corrupt or invalid
71: */
72: public function city($ipAddress)
73: {
74: return $this->modelFor(
75: 'City',
76: array('GeoLite2-City', 'GeoIP2-City'),
77: $ipAddress
78: );
79: }
80:
81: /**
82: * This method returns a GeoIP2 Country model.
83: *
84: * @param string $ipAddress IPv4 or IPv6 address as a string.
85: *
86: * @return \GeoIp2\Model\Country
87: *
88: * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
89: * not in the database.
90: * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
91: * is corrupt or invalid
92: */
93: public function country($ipAddress)
94: {
95: return $this->modelFor(
96: 'Country',
97: array('GeoLite2-Country', 'GeoIP2-Country'),
98: $ipAddress
99: );
100: }
101:
102: public function connectionType($ipAddress)
103: {
104: return $this->flatModelFor(
105: 'ConnectionType',
106: 'GeoIP2-Connection-Type',
107: $ipAddress
108: );
109: }
110:
111: public function domain($ipAddress)
112: {
113: return $this->flatModelFor(
114: 'Domain',
115: 'GeoIP2-Domain',
116: $ipAddress
117: );
118: }
119:
120: public function isp($ipAddress)
121: {
122: return $this->flatModelFor(
123: 'Isp',
124: 'GeoIP2-ISP',
125: $ipAddress
126: );
127: }
128:
129: private function modelFor($class, $types, $ipAddress)
130: {
131: if (!in_array($this->metadata()->databaseType, $types)) {
132: $method = lcfirst($class);
133: throw new \BadMethodCallException(
134: "The $method method cannot be used to open a "
135: . $this->metadata()->databaseType . " database"
136: );
137: }
138: $record = $this->getRecord($ipAddress);
139:
140: $record['traits']['ip_address'] = $ipAddress;
141: $class = "GeoIp2\\Model\\" . $class;
142:
143: return new $class($record, $this->locales);
144: }
145:
146: private function flatModelFor($class, $type, $ipAddress)
147: {
148: if ($this->metadata()->databaseType !== $type) {
149: $method = lcfirst($class);
150: throw new \BadMethodCallException(
151: "The $method method cannot be used to open a "
152: . $this->metadata()->databaseType . " database"
153: );
154: }
155:
156: $record = $this->getRecord($ipAddress);
157:
158: $record['ip_address'] = $ipAddress;
159: $class = "GeoIp2\\Model\\" . $class;
160:
161: return new $class($record);
162: }
163:
164: private function getRecord($ipAddress)
165: {
166: $record = $this->dbReader->get($ipAddress);
167: if ($record === null) {
168: throw new AddressNotFoundException(
169: "The address $ipAddress is not in the database."
170: );
171: }
172: return $record;
173: }
174:
175: /**
176: * @throws \InvalidArgumentException if arguments are passed to the method.
177: * @throws \BadMethodCallException if the database has been closed.
178: * @return \MaxMind\Db\Reader\Metadata object for the database.
179: */
180: public function metadata()
181: {
182: return $this->dbReader->metadata();
183: }
184:
185: /**
186: * Closes the GeoIP2 database and returns the resources to the system.
187: */
188: public function close()
189: {
190: $this->dbReader->close();
191: }
192: }
193: