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 database specific methods.
12 *
13 * ## Usage ##
14 *
15 * The basic API for this class is the same for every database. First, you
16 * create a reader object, specifying a file name. You then call the method
17 * corresponding to the specific database, passing it the IP address you want
18 * to look up.
19 *
20 * If the request succeeds, the method call will return a model class for
21 * the method you called. This model in turn contains multiple record classes,
22 * each of which represents part of the data returned by the database. If
23 * the database does not contain the requested information, the attributes
24 * on the record class will have a `null` value.
25 *
26 * If the address is not in the database, an
27 * {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
28 * thrown. If an invalid IP address is passed to one of the methods, a
29 * SPL {@link \InvalidArgumentException} will be thrown. If the database is
30 * corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
31 * will be thrown.
32 *
33 */
34 class Reader implements ProviderInterface
35 {
36 private $dbReader;
37 private $locales;
38
39 /**
40 * Constructor.
41 *
42 * @param string $filename The path to the GeoIP2 database file.
43 * @param array $locales List of locale codes to use in name property
44 * from most preferred to least preferred.
45 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
46 * is corrupt or invalid
47 */
48 public function __construct(
49 $filename,
50 $locales = array('en')
51 ) {
52 $this->dbReader = new DbReader($filename);
53 $this->locales = $locales;
54 }
55
56 /**
57 * This method returns a GeoIP2 City model.
58 *
59 * @param string $ipAddress IPv4 or IPv6 address as a string.
60 *
61 * @return \GeoIp2\Model\City
62 *
63 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
64 * not in the database.
65 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
66 * is corrupt or invalid
67 */
68 public function city($ipAddress)
69 {
70 return $this->modelFor('City', 'City', $ipAddress);
71 }
72
73 /**
74 * This method returns a GeoIP2 Country model.
75 *
76 * @param string $ipAddress IPv4 or IPv6 address as a string.
77 *
78 * @return \GeoIp2\Model\Country
79 *
80 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
81 * not in the database.
82 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
83 * is corrupt or invalid
84 */
85 public function country($ipAddress)
86 {
87 return $this->modelFor('Country', 'Country', $ipAddress);
88 }
89
90 /**
91 * This method returns a GeoIP2 Anonymous IP model.
92 *
93 * @param string $ipAddress IPv4 or IPv6 address as a string.
94 *
95 * @return \GeoIp2\Model\AnonymousIp
96 *
97 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
98 * not in the database.
99 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
100 * is corrupt or invalid
101 */
102 public function anonymousIp($ipAddress)
103 {
104 return $this->flatModelFor(
105 'AnonymousIp',
106 'GeoIP2-Anonymous-IP',
107 $ipAddress
108 );
109 }
110
111 /**
112 * This method returns a GeoIP2 Connection Type model.
113 *
114 * @param string $ipAddress IPv4 or IPv6 address as a string.
115 *
116 * @return \GeoIp2\Model\ConnectionType
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 connectionType($ipAddress)
124 {
125 return $this->flatModelFor(
126 'ConnectionType',
127 'GeoIP2-Connection-Type',
128 $ipAddress
129 );
130 }
131
132 /**
133 * This method returns a GeoIP2 Domain model.
134 *
135 * @param string $ipAddress IPv4 or IPv6 address as a string.
136 *
137 * @return \GeoIp2\Model\Domain
138 *
139 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
140 * not in the database.
141 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
142 * is corrupt or invalid
143 */
144 public function domain($ipAddress)
145 {
146 return $this->flatModelFor(
147 'Domain',
148 'GeoIP2-Domain',
149 $ipAddress
150 );
151 }
152
153 /**
154 * This method returns a GeoIP2 Enterprise model.
155 *
156 * @param string $ipAddress IPv4 or IPv6 address as a string.
157 *
158 * @return \GeoIp2\Model\Enterprise
159 *
160 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
161 * not in the database.
162 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
163 * is corrupt or invalid
164 */
165 public function enterprise($ipAddress)
166 {
167 return $this->modelFor('Enterprise', 'Enterprise', $ipAddress);
168 }
169
170 /**
171 * This method returns a GeoIP2 ISP model.
172 *
173 * @param string $ipAddress IPv4 or IPv6 address as a string.
174 *
175 * @return \GeoIp2\Model\Isp
176 *
177 * @throws \GeoIp2\Exception\AddressNotFoundException if the address is
178 * not in the database.
179 * @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
180 * is corrupt or invalid
181 */
182 public function isp($ipAddress)
183 {
184 return $this->flatModelFor(
185 'Isp',
186 'GeoIP2-ISP',
187 $ipAddress
188 );
189 }
190
191 private function modelFor($class, $type, $ipAddress)
192 {
193 $record = $this->getRecord($class, $type, $ipAddress);
194
195 $record['traits']['ip_address'] = $ipAddress;
196 $class = "GeoIp2\\Model\\" . $class;
197
198 return new $class($record, $this->locales);
199 }
200
201 private function flatModelFor($class, $type, $ipAddress)
202 {
203 $record = $this->getRecord($class, $type, $ipAddress);
204
205 $record['ip_address'] = $ipAddress;
206 $class = "GeoIp2\\Model\\" . $class;
207
208 return new $class($record);
209 }
210
211 private function getRecord($class, $type, $ipAddress)
212 {
213 if (strpos($this->metadata()->databaseType, $type) === false) {
214 $method = lcfirst($class);
215 throw new \BadMethodCallException(
216 "The $method method cannot be used to open a "
217 . $this->metadata()->databaseType . " database"
218 );
219 }
220 $record = $this->dbReader->get($ipAddress);
221 if ($record === null) {
222 throw new AddressNotFoundException(
223 "The address $ipAddress is not in the database."
224 );
225 }
226 return $record;
227 }
228
229 /**
230 * @throws \InvalidArgumentException if arguments are passed to the method.
231 * @throws \BadMethodCallException if the database has been closed.
232 * @return \MaxMind\Db\Reader\Metadata object for the database.
233 */
234 public function metadata()
235 {
236 return $this->dbReader->metadata();
237 }
238
239 /**
240 * Closes the GeoIP2 database and returns the resources to the system.
241 */
242 public function close()
243 {
244 $this->dbReader->close();
245 }
246 }
247