Compare commits
143 Commits
Author | SHA1 | Date | |
---|---|---|---|
4ec525a313 | |||
6f776ffac1 | |||
a323cc38cb | |||
|
a7f561bb64 | ||
|
0f77785480 | ||
|
a9e6ff4cfa | ||
|
01f58d749b | ||
|
64f2262093 | ||
|
8ef95cb4d1 | ||
|
076213aedb | ||
|
1546532b39 | ||
|
f1fe6587b4 | ||
|
2d6d43b62c | ||
|
09cf864045 | ||
|
4ae7983706 | ||
|
3142e44b3e | ||
|
4bdb050a50 | ||
|
c44053c276 | ||
|
caf91dd247 | ||
|
ffc6493c8d | ||
|
e5f61fd275 | ||
|
6859340968 | ||
|
970d1dba45 | ||
|
9e6449290f | ||
|
0c6ba34623 | ||
|
fbf4583b3e | ||
|
18686e11ac | ||
|
00a520f3c5 | ||
|
6cd0863499 | ||
|
5407b4f7c6 | ||
|
c58034524e | ||
|
94f4f9d5e6 | ||
|
dac9e94304 | ||
|
51e2f84d07 | ||
|
42efc47796 | ||
|
36624ae87a | ||
|
08697f2e7b | ||
|
2f9746c32b | ||
|
920a92f352 | ||
|
0d90c7a78e | ||
|
d52a0b057e | ||
|
5c4dd5b1e5 | ||
|
942ba4b8f5 | ||
|
a9fa7194aa | ||
|
13fbcae21c | ||
|
1925936b26 | ||
|
9384f93a72 | ||
|
9a7d49f683 | ||
|
b3e5aaac21 | ||
|
7d78bd9b2e | ||
|
6cf9b98993 | ||
|
a5fe44c3d3 | ||
|
6b919b4cba | ||
|
e441dbb64e | ||
|
adffe69dd2 | ||
|
04ccb67cea | ||
|
84299eba92 | ||
|
cdf75ec505 | ||
|
22babda1c9 | ||
|
9f0c743afd | ||
|
4e92cd0254 | ||
|
d61ddda4ef | ||
|
10ecb36d16 | ||
|
205483e14c | ||
|
6584b545ea | ||
|
ac6592b7a5 | ||
|
cb9c024699 | ||
|
e014aadf8d | ||
|
a043336cae | ||
|
0c9b774015 | ||
|
38bacff692 | ||
|
5cfe1353bb | ||
|
6715f848bb | ||
|
56407eff17 | ||
|
9b2fa1bcd1 | ||
|
ee2124b699 | ||
|
24c856cbfa | ||
|
8bd00943f4 | ||
|
a29e43bad4 | ||
|
7b0f8ca0c0 | ||
|
fbbe2dba24 | ||
|
0bed941634 | ||
|
8bf8442607 | ||
|
6d21d5682a | ||
|
bdb13d31f6 | ||
|
569043cb8f | ||
|
7fa971aef8 | ||
|
edb6940c74 | ||
|
57cb77a53c | ||
|
8aedaa5f91 | ||
|
87f6e2ad6b | ||
|
6bcd0ab21e | ||
|
e03b9558a9 | ||
|
234dcaff7c | ||
|
b8188bc558 | ||
|
8f16ed6115 | ||
|
8f3331002a | ||
|
b4b0341307 | ||
|
ee00329652 | ||
|
e8fa9a3a24 | ||
|
167433de0c | ||
|
c584dbfd6b | ||
|
c642a32b0c | ||
|
decfda7e90 | ||
|
3a560452af | ||
|
8febab1fe4 | ||
|
f0430b613d | ||
|
e3289ec416 | ||
|
1d1dcec74c | ||
|
630765f924 | ||
|
b55d42b5cd | ||
|
044ca4d085 | ||
|
3ba84992c8 | ||
|
a6c1f9378e | ||
|
1c0817d133 | ||
|
59a51ef34d | ||
|
3e0fc2a837 | ||
|
c898f76a50 | ||
|
8a265a763e | ||
|
3579ce7297 | ||
|
aa88c3040f | ||
|
5df4bbee47 | ||
|
e60181f13a | ||
|
1c37dcac03 | ||
|
f4898f7f90 | ||
|
6f85654820 | ||
|
fc74279d11 | ||
|
b8aa4bc429 | ||
|
d9a87dd5bd | ||
|
b45b3c1ed5 | ||
|
3431141943 | ||
|
c90fe87d3d | ||
|
1c256e1e64 | ||
|
1d294bd473 | ||
|
9a9a1e86b2 | ||
|
893c715047 | ||
|
f99ac351ab | ||
|
4d9957ccf5 | ||
|
3a382f0d26 | ||
|
c4867ef7c7 | ||
|
bfb8de7ffa | ||
|
e38c46950f | ||
|
7f81643a98 |
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -1,8 +1,14 @@
|
||||||
bin/
|
_site
|
||||||
|
.gh-pages
|
||||||
|
.idea
|
||||||
|
GeoLite2-City.mmdb
|
||||||
|
apigen.phar
|
||||||
|
box.phar
|
||||||
|
build
|
||||||
composer.lock
|
composer.lock
|
||||||
composer.phar
|
composer.phar
|
||||||
phpunit.xml
|
phpunit.xml
|
||||||
|
geoip2-php.sublime-*
|
||||||
vendor/
|
vendor/
|
||||||
*.sw?
|
*.sw?
|
||||||
t.php
|
|
||||||
*.old
|
*.old
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "maxmind-db"]
|
||||||
|
path = maxmind-db
|
||||||
|
url = git://github.com/maxmind/MaxMind-DB.git
|
|
@ -4,16 +4,18 @@ php:
|
||||||
- 5.3
|
- 5.3
|
||||||
- 5.4
|
- 5.4
|
||||||
- 5.5
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- hhvm
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- composer self-update
|
- composer self-update
|
||||||
- composer install --dev -n --prefer-source
|
- composer install --dev -n --prefer-source
|
||||||
- pyrus install pear/PHP_CodeSniffer
|
- if [ "5.5" == $TRAVIS_PHP_VERSION ]; then pyrus install pear/PHP_CodeSniffer; fi
|
||||||
- phpenv rehash
|
- phpenv rehash
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- mkdir -p build/logs
|
- mkdir -p build/logs
|
||||||
- phpcs --standard=PSR2 src/
|
- if [ "5.5" == $TRAVIS_PHP_VERSION ]; then phpcs --standard=PSR2 src/; fi
|
||||||
- phpunit -c phpunit.xml.dist
|
- phpunit -c phpunit.xml.dist
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
|
|
131
CHANGELOG.md
131
CHANGELOG.md
|
@ -1,14 +1,139 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
2.1.1 (2014-12-03)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The 2.1.0 Phar builds included a shebang line, causing issues when loading
|
||||||
|
it as a library. This has been corrected. GitHub #33.
|
||||||
|
|
||||||
|
2.1.0 (2014-10-29)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Update ApiGen dependency to version that isn't broken on case sensitive
|
||||||
|
file systems.
|
||||||
|
* Added support for the GeoIP2 Anonymous IP database. The
|
||||||
|
`GeoIP2\Database\Reader` class now has an `anonymousIp` method which returns
|
||||||
|
a `GeoIP2\Model\AnonymousIp` object.
|
||||||
|
* Boolean attributes like those in the `GeoIP2\Record\Traits` class now return
|
||||||
|
`false` instead of `null` when they were not true.
|
||||||
|
|
||||||
|
2.0.0 (2014-09-22)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* First production release.
|
||||||
|
|
||||||
|
0.9.0 (2014-09-15)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* IMPORTANT: The deprecated `omni()` and `cityIspOrg()` methods have been
|
||||||
|
removed from `GeoIp2\WebService\Client`.
|
||||||
|
|
||||||
|
0.8.1 (2014-09-12)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The check added to the `GeoIP2\Database\Reader` lookup methods in 0.8.0 did
|
||||||
|
not work with the GeoIP2 City Database Subset by Continent with World
|
||||||
|
Countries. This has been fixed. Fixes GitHub issue #23.
|
||||||
|
|
||||||
|
0.8.0 (2014-09-10)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The `GeoIp2\Database\Reader` lookup methods (e.g., `city()`, `isp()`) now
|
||||||
|
throw a `BadMethodCallException` if they are used with a database that
|
||||||
|
does not match the method. In particular, doing a `city()` lookup on a
|
||||||
|
GeoIP2 Country database will result in an exception, and vice versa.
|
||||||
|
* A `metadata()` method has been added to the `GeoIP2\Database\Reader` class.
|
||||||
|
This returns a `MaxMind\Db\Reader\Metadata` class with information about the
|
||||||
|
database.
|
||||||
|
* The name attribute was missing from the RepresentedCountry class.
|
||||||
|
|
||||||
|
0.7.0 (2014-07-22)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The web service client API has been updated for the v2.1 release of the web
|
||||||
|
service. In particular, the `cityIspOrg` and `omni` methods on
|
||||||
|
`GeoIp2\WebService\Client` should be considered deprecated. The `city`
|
||||||
|
method now provides all of the data formerly provided by `cityIspOrg`, and
|
||||||
|
the `omni` method has been replaced by the `insights` method.
|
||||||
|
* Support was added for GeoIP2 Connection Type, Domain and ISP databases.
|
||||||
|
|
||||||
|
|
||||||
|
0.6.3 (2014-05-12)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* With the previous Phar builds, some users received `phar error: invalid url
|
||||||
|
or non-existent phar` errors. The correct alias is now used for the Phar,
|
||||||
|
and this should no longer be an issue.
|
||||||
|
|
||||||
|
0.6.2 (2014-05-08)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* The Phar build was broken with Guzzle 3.9.0+. This has been fixed.
|
||||||
|
|
||||||
|
0.6.1 (2014-05-01)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* This API now officially supports HHVM.
|
||||||
|
* The `maxmind-db/reader` dependency was updated to a version that does not
|
||||||
|
require BC Math.
|
||||||
|
* The Composer compatibility autoload rules are now targeted more narrowly.
|
||||||
|
* A `box.json` file is included to build a Phar package.
|
||||||
|
|
||||||
|
0.6.0 (2014-02-19)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* This API is now licensed under the Apache License, Version 2.0.
|
||||||
|
* Model and record classes now implement `JsonSerializable`.
|
||||||
|
* `isset` now works with model and record classes.
|
||||||
|
|
||||||
|
0.5.0 (2013-10-21)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Renamed $languages constructor parameters to $locales for both the Client
|
||||||
|
and Reader classes.
|
||||||
|
* Documentation and code clean-up (Ben Morel).
|
||||||
|
* Added the interface `GeoIp2\ProviderInterface`, which is implemented by both
|
||||||
|
`\GeoIp2\Database\Reader` and `\GeoIp2\WebService\Client`.
|
||||||
|
|
||||||
|
0.4.0 (2013-07-16)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* This is the first release with the GeoIP2 database reader. Please see the
|
||||||
|
`README.md` file and the `\GeoIp2\Database\Reader` class.
|
||||||
|
* The general exception classes were replaced with specific exception classes
|
||||||
|
representing particular types of errors, such as an authentication error.
|
||||||
|
|
||||||
|
0.3.0 (2013-07-12)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* In namespaces and class names, "GeoIP2" was renamed to "GeoIp2" to improve
|
||||||
|
consistency.
|
||||||
|
|
||||||
|
0.2.1 (2013-06-10)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* First official beta release.
|
||||||
|
* Documentation updates and corrections.
|
||||||
|
|
||||||
|
0.2.0 (2013-05-29)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* `GenericException` was renamed to `GeoIP2Exception`.
|
||||||
|
* We now support more languages. The new languages are de, es, fr, and pt-BR.
|
||||||
|
* The REST API now returns a record with data about your account. There is
|
||||||
|
a new `GeoIP\Records\MaxMind` class for this data.
|
||||||
|
* The `continentCode` attribute on `Continent` was renamed to `code`.
|
||||||
|
* Documentation updates.
|
||||||
|
|
||||||
0.1.1 (2013-05-14)
|
0.1.1 (2013-05-14)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
* Updated Guzzle version requirement
|
* Updated Guzzle version requirement.
|
||||||
* Fixed Composer example in README.md
|
* Fixed Composer example in README.md.
|
||||||
|
|
||||||
|
|
||||||
0.1.0 (2013-05-13)
|
0.1.0 (2013-05-13)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
* Initial release
|
* Initial release.
|
||||||
|
|
638
LICENSE
638
LICENSE
|
@ -1,504 +1,202 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
Apache License
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Version 2.0, January 2004
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
http://www.apache.org/licenses/
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
[This is the first released version of the Lesser GPL. It also counts
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
as the successor of the GNU Library Public License, version 2, hence
|
|
||||||
the version number 2.1.]
|
|
||||||
|
|
||||||
Preamble
|
1. Definitions.
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
Licenses are intended to guarantee your freedom to share and change
|
|
||||||
free software--to make sure the software is free for all its users.
|
|
||||||
|
|
||||||
This license, the Lesser General Public License, applies to some
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
specially designated software packages--typically libraries--of the
|
the copyright owner that is granting the License.
|
||||||
Free Software Foundation and other authors who decide to use it. You
|
|
||||||
can use it too, but we suggest you first think carefully about whether
|
|
||||||
this license or the ordinary General Public License is the better
|
|
||||||
strategy to use in any particular case, based on the explanations below.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom of use,
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
not price. Our General Public Licenses are designed to make sure that
|
other entities that control, are controlled by, or are under common
|
||||||
you have the freedom to distribute copies of free software (and charge
|
control with that entity. For the purposes of this definition,
|
||||||
for this service if you wish); that you receive source code or can get
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
it if you want it; that you can change the software and use pieces of
|
direction or management of such entity, whether by contract or
|
||||||
it in new free programs; and that you are informed that you can do
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
these things.
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
distributors to deny you these rights or to ask you to surrender these
|
exercising permissions granted by this License.
|
||||||
rights. These restrictions translate to certain responsibilities for
|
|
||||||
you if you distribute copies of the library or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of the library, whether gratis
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
or for a fee, you must give the recipients all the rights that we gave
|
including but not limited to software source code, documentation
|
||||||
you. You must make sure that they, too, receive or can get the source
|
source, and configuration files.
|
||||||
code. If you link other code with the library, you must provide
|
|
||||||
complete object files to the recipients, so that they can relink them
|
|
||||||
with the library after making changes to the library and recompiling
|
|
||||||
it. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
We protect your rights with a two-step method: (1) we copyright the
|
"Object" form shall mean any form resulting from mechanical
|
||||||
library, and (2) we offer you this license, which gives you legal
|
transformation or translation of a Source form, including but
|
||||||
permission to copy, distribute and/or modify the library.
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
To protect each distributor, we want to make it very clear that
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
there is no warranty for the free library. Also, if the library is
|
Object form, made available under the License, as indicated by a
|
||||||
modified by someone else and passed on, the recipients should know
|
copyright notice that is included in or attached to the work
|
||||||
that what they have is not the original version, so that the original
|
(an example is provided in the Appendix below).
|
||||||
author's reputation will not be affected by problems that might be
|
|
||||||
introduced by others.
|
|
||||||
|
|
||||||
Finally, software patents pose a constant threat to the existence of
|
|
||||||
any free program. We wish to make sure that a company cannot
|
|
||||||
effectively restrict the users of a free program by obtaining a
|
|
||||||
restrictive license from a patent holder. Therefore, we insist that
|
|
||||||
any patent license obtained for a version of the library must be
|
|
||||||
consistent with the full freedom of use specified in this license.
|
|
||||||
|
|
||||||
Most GNU software, including some libraries, is covered by the
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
ordinary GNU General Public License. This license, the GNU Lesser
|
form, that is based on (or derived from) the Work and for which the
|
||||||
General Public License, applies to certain designated libraries, and
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
is quite different from the ordinary General Public License. We use
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
this license for certain libraries in order to permit linking those
|
of this License, Derivative Works shall not include works that remain
|
||||||
libraries into non-free programs.
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
When a program is linked with a library, whether statically or using
|
"Contribution" shall mean any work of authorship, including
|
||||||
a shared library, the combination of the two is legally speaking a
|
the original version of the Work and any modifications or additions
|
||||||
combined work, a derivative of the original library. The ordinary
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
General Public License therefore permits such linking only if the
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
entire combination fits its criteria of freedom. The Lesser General
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
Public License permits more lax criteria for linking other code with
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
the library.
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
We call this license the "Lesser" General Public License because it
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
does Less to protect the user's freedom than the ordinary General
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
Public License. It also provides other free software developers Less
|
subsequently incorporated within the Work.
|
||||||
of an advantage over competing non-free programs. These disadvantages
|
|
||||||
are the reason we use the ordinary General Public License for many
|
|
||||||
libraries. However, the Lesser license provides advantages in certain
|
|
||||||
special circumstances.
|
|
||||||
|
|
||||||
For example, on rare occasions, there may be a special need to
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
encourage the widest possible use of a certain library, so that it becomes
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
a de-facto standard. To achieve this, non-free programs must be
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
allowed to use the library. A more frequent case is that a free
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
library does the same job as widely used non-free libraries. In this
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
case, there is little to gain by limiting the free library to free
|
Work and such Derivative Works in Source or Object form.
|
||||||
software only, so we use the Lesser General Public License.
|
|
||||||
|
|
||||||
In other cases, permission to use a particular library in non-free
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
programs enables a greater number of people to use a large body of
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
free software. For example, permission to use the GNU C Library in
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
non-free programs enables many more people to use the whole GNU
|
(except as stated in this section) patent license to make, have made,
|
||||||
operating system, as well as its variant, the GNU/Linux operating
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
system.
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
Although the Lesser General Public License is Less protective of the
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
users' freedom, it does ensure that the user of a program that is
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
linked with the Library has the freedom and the wherewithal to run
|
modifications, and in Source or Object form, provided that You
|
||||||
that program using a modified version of the Library.
|
meet the following conditions:
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
(a) You must give any other recipients of the Work or
|
||||||
modification follow. Pay close attention to the difference between a
|
Derivative Works a copy of this License; and
|
||||||
"work based on the library" and a "work that uses the library". The
|
|
||||||
former contains code derived from the library, whereas the latter must
|
|
||||||
be combined with the library in order to run.
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
(b) You must cause any modified files to carry prominent notices
|
||||||
program which contains a notice placed by the copyright holder or
|
stating that You changed the files; and
|
||||||
other authorized party saying it may be distributed under the terms of
|
|
||||||
this Lesser General Public License (also called "this License").
|
|
||||||
Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
A "library" means a collection of software functions and/or data
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
prepared so as to be conveniently linked with application programs
|
that You distribute, all copyright, patent, trademark, and
|
||||||
(which use some of those functions and data) to form executables.
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
The "Library", below, refers to any such software library or work
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
which has been distributed under these terms. A "work based on the
|
distribution, then any Derivative Works that You distribute must
|
||||||
Library" means either the Library or any derivative work under
|
include a readable copy of the attribution notices contained
|
||||||
copyright law: that is to say, a work containing the Library or a
|
within such NOTICE file, excluding those notices that do not
|
||||||
portion of it, either verbatim or with modifications and/or translated
|
pertain to any part of the Derivative Works, in at least one
|
||||||
straightforwardly into another language. (Hereinafter, translation is
|
of the following places: within a NOTICE text file distributed
|
||||||
included without limitation in the term "modification".)
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
"Source code" for a work means the preferred form of the work for
|
You may add Your own copyright statement to Your modifications and
|
||||||
making modifications to it. For a library, complete source code means
|
may provide additional or different license terms and conditions
|
||||||
all the source code for all modules it contains, plus any associated
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
interface definition files, plus the scripts used to control compilation
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
and installation of the library.
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
covered by this License; they are outside its scope. The act of
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
running a program using the Library is not restricted, and output from
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
such a program is covered only if its contents constitute a work based
|
this License, without any additional terms or conditions.
|
||||||
on the Library (independent of the use of the Library in a tool for
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
writing it). Whether that is true depends on what the Library does
|
the terms of any separate license agreement you may have executed
|
||||||
and what the program that uses the Library does.
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
complete source code as you receive it, in any medium, provided that
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
you conspicuously and appropriately publish on each copy an
|
except as required for reasonable and customary use in describing the
|
||||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
all the notices that refer to this License and to the absence of any
|
|
||||||
warranty; and distribute a copy of this License along with the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy,
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
and you may at your option offer warranty protection in exchange for a
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
fee.
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
2. You may modify your copy or copies of the Library or any portion
|
implied, including, without limitation, any warranties or conditions
|
||||||
of it, thus forming a work based on the Library, and copy and
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
distribute such modifications or work under the terms of Section 1
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
above, provided that you also meet all of these conditions:
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
a) The modified work must itself be a software library.
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
b) You must cause the files modified to carry prominent notices
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
stating that you changed the files and the date of any change.
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
c) You must cause the whole of the work to be licensed at no
|
or other liability obligations and/or rights consistent with this
|
||||||
charge to all third parties under the terms of this License.
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
d) If a facility in the modified Library refers to a function or a
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
table of data to be supplied by an application program that uses
|
defend, and hold each Contributor harmless for any liability
|
||||||
the facility, other than as an argument passed when the facility
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
is invoked, then you must make a good faith effort to ensure that,
|
of your accepting any such warranty or additional liability.
|
||||||
in the event an application does not supply such function or
|
|
||||||
table, the facility still operates, and performs whatever part of
|
|
||||||
its purpose remains meaningful.
|
|
||||||
|
|
||||||
(For example, a function in a library to compute square roots has
|
|
||||||
a purpose that is entirely well-defined independent of the
|
|
||||||
application. Therefore, Subsection 2d requires that any
|
|
||||||
application-supplied function or table used by this function must
|
|
||||||
be optional: if the application does not supply it, the square
|
|
||||||
root function must still compute square roots.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Library,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Library, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote
|
|
||||||
it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Library.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Library
|
|
||||||
with the Library (or with a work based on the Library) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
|
||||||
License instead of this License to a given copy of the Library. To do
|
|
||||||
this, you must alter all the notices that refer to this License, so
|
|
||||||
that they refer to the ordinary GNU General Public License, version 2,
|
|
||||||
instead of to this License. (If a newer version than version 2 of the
|
|
||||||
ordinary GNU General Public License has appeared, then you can specify
|
|
||||||
that version instead if you wish.) Do not make any other change in
|
|
||||||
these notices.
|
|
||||||
|
|
||||||
Once this change is made in a given copy, it is irreversible for
|
|
||||||
that copy, so the ordinary GNU General Public License applies to all
|
|
||||||
subsequent copies and derivative works made from that copy.
|
|
||||||
|
|
||||||
This option is useful when you wish to copy part of the code of
|
|
||||||
the Library into a program that is not a library.
|
|
||||||
|
|
||||||
4. You may copy and distribute the Library (or a portion or
|
|
||||||
derivative of it, under Section 2) in object code or executable form
|
|
||||||
under the terms of Sections 1 and 2 above provided that you accompany
|
|
||||||
it with the complete corresponding machine-readable source code, which
|
|
||||||
must be distributed under the terms of Sections 1 and 2 above on a
|
|
||||||
medium customarily used for software interchange.
|
|
||||||
|
|
||||||
If distribution of object code is made by offering access to copy
|
|
||||||
from a designated place, then offering equivalent access to copy the
|
|
||||||
source code from the same place satisfies the requirement to
|
|
||||||
distribute the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
5. A program that contains no derivative of any portion of the
|
|
||||||
Library, but is designed to work with the Library by being compiled or
|
|
||||||
linked with it, is called a "work that uses the Library". Such a
|
|
||||||
work, in isolation, is not a derivative work of the Library, and
|
|
||||||
therefore falls outside the scope of this License.
|
|
||||||
|
|
||||||
However, linking a "work that uses the Library" with the Library
|
|
||||||
creates an executable that is a derivative of the Library (because it
|
|
||||||
contains portions of the Library), rather than a "work that uses the
|
|
||||||
library". The executable is therefore covered by this License.
|
|
||||||
Section 6 states terms for distribution of such executables.
|
|
||||||
|
|
||||||
When a "work that uses the Library" uses material from a header file
|
|
||||||
that is part of the Library, the object code for the work may be a
|
|
||||||
derivative work of the Library even though the source code is not.
|
|
||||||
Whether this is true is especially significant if the work can be
|
|
||||||
linked without the Library, or if the work is itself a library. The
|
|
||||||
threshold for this to be true is not precisely defined by law.
|
|
||||||
|
|
||||||
If such an object file uses only numerical parameters, data
|
|
||||||
structure layouts and accessors, and small macros and small inline
|
|
||||||
functions (ten lines or less in length), then the use of the object
|
|
||||||
file is unrestricted, regardless of whether it is legally a derivative
|
|
||||||
work. (Executables containing this object code plus portions of the
|
|
||||||
Library will still fall under Section 6.)
|
|
||||||
|
|
||||||
Otherwise, if the work is a derivative of the Library, you may
|
|
||||||
distribute the object code for the work under the terms of Section 6.
|
|
||||||
Any executables containing that work also fall under Section 6,
|
|
||||||
whether or not they are linked directly with the Library itself.
|
|
||||||
|
|
||||||
6. As an exception to the Sections above, you may also combine or
|
|
||||||
link a "work that uses the Library" with the Library to produce a
|
|
||||||
work containing portions of the Library, and distribute that work
|
|
||||||
under terms of your choice, provided that the terms permit
|
|
||||||
modification of the work for the customer's own use and reverse
|
|
||||||
engineering for debugging such modifications.
|
|
||||||
|
|
||||||
You must give prominent notice with each copy of the work that the
|
|
||||||
Library is used in it and that the Library and its use are covered by
|
|
||||||
this License. You must supply a copy of this License. If the work
|
|
||||||
during execution displays copyright notices, you must include the
|
|
||||||
copyright notice for the Library among them, as well as a reference
|
|
||||||
directing the user to the copy of this License. Also, you must do one
|
|
||||||
of these things:
|
|
||||||
|
|
||||||
a) Accompany the work with the complete corresponding
|
|
||||||
machine-readable source code for the Library including whatever
|
|
||||||
changes were used in the work (which must be distributed under
|
|
||||||
Sections 1 and 2 above); and, if the work is an executable linked
|
|
||||||
with the Library, with the complete machine-readable "work that
|
|
||||||
uses the Library", as object code and/or source code, so that the
|
|
||||||
user can modify the Library and then relink to produce a modified
|
|
||||||
executable containing the modified Library. (It is understood
|
|
||||||
that the user who changes the contents of definitions files in the
|
|
||||||
Library will not necessarily be able to recompile the application
|
|
||||||
to use the modified definitions.)
|
|
||||||
|
|
||||||
b) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (1) uses at run time a
|
|
||||||
copy of the library already present on the user's computer system,
|
|
||||||
rather than copying library functions into the executable, and (2)
|
|
||||||
will operate properly with a modified version of the library, if
|
|
||||||
the user installs one, as long as the modified version is
|
|
||||||
interface-compatible with the version that the work was made with.
|
|
||||||
|
|
||||||
c) Accompany the work with a written offer, valid for at
|
|
||||||
least three years, to give the same user the materials
|
|
||||||
specified in Subsection 6a, above, for a charge no more
|
|
||||||
than the cost of performing this distribution.
|
|
||||||
|
|
||||||
d) If distribution of the work is made by offering access to copy
|
|
||||||
from a designated place, offer equivalent access to copy the above
|
|
||||||
specified materials from the same place.
|
|
||||||
|
|
||||||
e) Verify that the user has already received a copy of these
|
|
||||||
materials or that you have already sent this user a copy.
|
|
||||||
|
|
||||||
For an executable, the required form of the "work that uses the
|
|
||||||
Library" must include any data and utility programs needed for
|
|
||||||
reproducing the executable from it. However, as a special exception,
|
|
||||||
the materials to be distributed need not include anything that is
|
|
||||||
normally distributed (in either source or binary form) with the major
|
|
||||||
components (compiler, kernel, and so on) of the operating system on
|
|
||||||
which the executable runs, unless that component itself accompanies
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
It may happen that this requirement contradicts the license
|
|
||||||
restrictions of other proprietary libraries that do not normally
|
|
||||||
accompany the operating system. Such a contradiction means you cannot
|
|
||||||
use both them and the Library together in an executable that you
|
|
||||||
distribute.
|
|
||||||
|
|
||||||
7. You may place library facilities that are a work based on the
|
|
||||||
Library side-by-side in a single library together with other library
|
|
||||||
facilities not covered by this License, and distribute such a combined
|
|
||||||
library, provided that the separate distribution of the work based on
|
|
||||||
the Library and of the other library facilities is otherwise
|
|
||||||
permitted, and provided that you do these two things:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work
|
|
||||||
based on the Library, uncombined with any other library
|
|
||||||
facilities. This must be distributed under the terms of the
|
|
||||||
Sections above.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library of the fact
|
|
||||||
that part of it is a work based on the Library, and explaining
|
|
||||||
where to find the accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
8. You may not copy, modify, sublicense, link with, or distribute
|
|
||||||
the Library except as expressly provided under this License. Any
|
|
||||||
attempt otherwise to copy, modify, sublicense, link with, or
|
|
||||||
distribute the Library is void, and will automatically terminate your
|
|
||||||
rights under this License. However, parties who have received copies,
|
|
||||||
or rights, from you under this License will not have their licenses
|
|
||||||
terminated so long as such parties remain in full compliance.
|
|
||||||
|
|
||||||
9. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Library or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Library (or any work based on the
|
|
||||||
Library), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Library or works based on it.
|
|
||||||
|
|
||||||
10. Each time you redistribute the Library (or any work based on the
|
|
||||||
Library), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute, link with or modify the Library
|
|
||||||
subject to these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties with
|
|
||||||
this License.
|
|
||||||
|
|
||||||
11. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Library at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Library by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Library.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under any
|
|
||||||
particular circumstance, the balance of the section is intended to apply,
|
|
||||||
and the section as a whole is intended to apply in other circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
12. If the distribution and/or use of the Library is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Library under this License may add
|
|
||||||
an explicit geographical distribution limitation excluding those countries,
|
|
||||||
so that distribution is permitted only in or among countries not thus
|
|
||||||
excluded. In such case, this License incorporates the limitation as if
|
|
||||||
written in the body of this License.
|
|
||||||
|
|
||||||
13. The Free Software Foundation may publish revised and/or new
|
|
||||||
versions of the Lesser General Public License from time to time.
|
|
||||||
Such new versions will be similar in spirit to the present version,
|
|
||||||
but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Library
|
|
||||||
specifies a version number of this License which applies to it and
|
|
||||||
"any later version", you have the option of following the terms and
|
|
||||||
conditions either of that version or of any later version published by
|
|
||||||
the Free Software Foundation. If the Library does not specify a
|
|
||||||
license version number, you may choose any version ever published by
|
|
||||||
the Free Software Foundation.
|
|
||||||
|
|
||||||
14. If you wish to incorporate parts of the Library into other free
|
|
||||||
programs whose distribution conditions are incompatible with these,
|
|
||||||
write to the author to ask for permission. For software which is
|
|
||||||
copyrighted by the Free Software Foundation, write to the Free
|
|
||||||
Software Foundation; we sometimes make exceptions for this. Our
|
|
||||||
decision will be guided by the two goals of preserving the free status
|
|
||||||
of all derivatives of our free software and of promoting the sharing
|
|
||||||
and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
||||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
|
||||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
|
||||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
|
||||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
|
||||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
|
||||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
|
||||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
|
||||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
||||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
||||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
|
||||||
|
|
||||||
If you develop a new library, and you want it to be of the greatest
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
possible use to the public, we recommend making it free software that
|
|
||||||
everyone can redistribute and change. You can do so by permitting
|
|
||||||
redistribution under these terms (or, alternatively, under the terms of the
|
|
||||||
ordinary General Public License).
|
|
||||||
|
|
||||||
To apply these terms, attach the following notices to the library. It is
|
To apply the Apache License to your work, attach the following
|
||||||
safest to attach them to the start of each source file to most effectively
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
convey the exclusion of warranty; and each file should have at least the
|
replaced with your own identifying information. (Don't include
|
||||||
"copyright" line and a pointer to where the full notice is found.
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
<one line to give the library's name and a brief idea of what it does.>
|
Copyright [yyyy] [name of copyright owner]
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
modify it under the terms of the GNU Lesser General Public
|
you may not use this file except in compliance with the License.
|
||||||
License as published by the Free Software Foundation; either
|
You may obtain a copy of the License at
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
|
||||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1990
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
That's all there is to it!
|
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
315
README.md
315
README.md
|
@ -1,62 +1,201 @@
|
||||||
# GeoIP2 PHP API #
|
# GeoIP2 PHP API #
|
||||||
|
|
||||||
**NOTE**: This is an alpha release. The API may change before the final
|
|
||||||
production release.
|
|
||||||
|
|
||||||
## Description ##
|
## Description ##
|
||||||
|
|
||||||
Currently, this distribution provides an API for the GeoIP2 web services
|
This package provides an API for the GeoIP2 [web services]
|
||||||
(as documented at http://dev.maxmind.com/geoip/geoip2/web-services).
|
(http://dev.maxmind.com/geoip/geoip2/web-services) and [databases]
|
||||||
|
(http://dev.maxmind.com/geoip/geoip2/downloadable). The API also works with
|
||||||
|
the free [GeoLite2 databases](http://dev.maxmind.com/geoip/geoip2/geolite2/).
|
||||||
|
|
||||||
In the future, this distribution will also provide the same API for the
|
## Install via Composer ##
|
||||||
GeoIP2 downloadable databases. These databases have not yet been
|
|
||||||
released as a downloadable product.
|
|
||||||
|
|
||||||
See GeoIP2\WebService\Client for details on the web service client
|
|
||||||
API.
|
|
||||||
|
|
||||||
## Installation ##
|
|
||||||
|
|
||||||
### Define Your Dependencies ###
|
|
||||||
|
|
||||||
We recommend installing this package with [Composer](http://getcomposer.org/).
|
We recommend installing this package with [Composer](http://getcomposer.org/).
|
||||||
To do this, add ```geoip2/geoip2``` to your ```composer.json``` file.
|
|
||||||
|
|
||||||
```json
|
### Download Composer ###
|
||||||
{
|
|
||||||
"require": {
|
To download Composer, run in the root directory of your project:
|
||||||
"geoip2/geoip2": "0.1.*"
|
|
||||||
}
|
```bash
|
||||||
}
|
curl -sS https://getcomposer.org/installer | php
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install Composer ###
|
You should now have the file `composer.phar` in your project directory.
|
||||||
|
|
||||||
Run in your project root:
|
|
||||||
|
|
||||||
```
|
|
||||||
curl -s http://getcomposer.org/installer | php
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install Dependencies ###
|
### Install Dependencies ###
|
||||||
|
|
||||||
Run in your project root:
|
Run in your project root:
|
||||||
|
|
||||||
```
|
```
|
||||||
php composer.phar install
|
php composer.phar require geoip2/geoip2:~2.0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You should now have the files `composer.json` and `composer.lock` as well as
|
||||||
|
the directory `vendor` in your project directory. If you use a version control
|
||||||
|
system, `composer.json` should be added to it.
|
||||||
|
|
||||||
### Require Autoloader ###
|
### Require Autoloader ###
|
||||||
|
|
||||||
You can autoload all dependencies by adding this to your code:
|
After installing the dependencies, you need to require the Composer autoloader
|
||||||
```
|
from your code:
|
||||||
|
|
||||||
|
```php
|
||||||
require 'vendor/autoload.php';
|
require 'vendor/autoload.php';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage ##
|
## Install via Phar ##
|
||||||
|
|
||||||
To use this API, you must create a new ``\GeoIP2\WebService\Client``
|
Although we strongly recommend using Composer, we also provide a
|
||||||
object with your ``$userId`` and ``$licenseKey``, then you call the method
|
[phar archive](http://php.net/manual/en/book.phar.php) containing all of the
|
||||||
|
dependencies for GeoIP2. Our latest phar archive is available on
|
||||||
|
[our releases page](https://github.com/maxmind/GeoIP2-php/releases).
|
||||||
|
|
||||||
|
To use the archive, just require it from your script:
|
||||||
|
|
||||||
|
```php
|
||||||
|
require 'geoip2.phar';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional C Extension ##
|
||||||
|
|
||||||
|
The [MaxMind DB API](https://github.com/maxmind/MaxMind-DB-Reader-php)
|
||||||
|
includes an optional C extension that you may install to dramatically increase
|
||||||
|
the performance of lookups in GeoIP2 or GeoLite2 databases. To install, please
|
||||||
|
follow the instructions included with that API.
|
||||||
|
|
||||||
|
The extension has no effect on web-service lookups.
|
||||||
|
|
||||||
|
## Database Reader ##
|
||||||
|
|
||||||
|
### Usage ###
|
||||||
|
|
||||||
|
To use this API, you must create a new `\GeoIp2\Database\Reader` object with
|
||||||
|
the path to the database file as the first argument to the constructor. You
|
||||||
|
may then call the method corresponding to the database you are using.
|
||||||
|
|
||||||
|
If the lookup succeeds, the method call will return a model class for the
|
||||||
|
record in the database. This model in turn contains multiple container
|
||||||
|
classes for the different parts of the data such as the city in which the
|
||||||
|
IP address is located.
|
||||||
|
|
||||||
|
If the record is not found, a `\GeoIp2\Exception\AddressNotFoundException`
|
||||||
|
is thrown. If the database is invalid or corrupt, a
|
||||||
|
`\MaxMind\Db\InvalidDatabaseException` will be thrown.
|
||||||
|
|
||||||
|
See the API documentation for more details.
|
||||||
|
|
||||||
|
### City Example ###
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
// This creates the Reader object, which should be reused across
|
||||||
|
// lookups.
|
||||||
|
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');
|
||||||
|
|
||||||
|
// Replace "city" with the appropriate method for your database, e.g.,
|
||||||
|
// "country".
|
||||||
|
$record = $reader->city('128.101.101.101');
|
||||||
|
|
||||||
|
print($record->country->isoCode . "\n"); // 'US'
|
||||||
|
print($record->country->name . "\n"); // 'United States'
|
||||||
|
print($record->country->names['zh-CN'] . "\n"); // '美国'
|
||||||
|
|
||||||
|
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
|
||||||
|
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
|
||||||
|
|
||||||
|
print($record->city->name . "\n"); // 'Minneapolis'
|
||||||
|
|
||||||
|
print($record->postal->code . "\n"); // '55455'
|
||||||
|
|
||||||
|
print($record->location->latitude . "\n"); // 44.9733
|
||||||
|
print($record->location->longitude . "\n"); // -93.2323
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Anonymous IP Example ###
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
// This creates the Reader object, which should be reused across
|
||||||
|
// lookups.
|
||||||
|
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-Anonymous-IP.mmdb');
|
||||||
|
|
||||||
|
$record = $reader->anonymousIp('128.101.101.101');
|
||||||
|
|
||||||
|
if ($record->isAnonymous) { print "anon\n"; }
|
||||||
|
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection-Type Example ###
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
// This creates the Reader object, which should be reused across
|
||||||
|
// lookups.
|
||||||
|
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-Connection-Type.mmdb');
|
||||||
|
|
||||||
|
$record = $reader->connectionType('128.101.101.101');
|
||||||
|
|
||||||
|
print($record->connectionType . "\n"); // 'Corporate'
|
||||||
|
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Domain Example ###
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
// This creates the Reader object, which should be reused across
|
||||||
|
// lookups.
|
||||||
|
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-Domain.mmdb');
|
||||||
|
|
||||||
|
$record = $reader->domain('128.101.101.101');
|
||||||
|
|
||||||
|
print($record->domain . "\n"); // 'umn.edu'
|
||||||
|
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### ISP Example ###
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
// This creates the Reader object, which should be reused across
|
||||||
|
// lookups.
|
||||||
|
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-ISP.mmdb');
|
||||||
|
|
||||||
|
$record = $reader->isp('128.101.101.101');
|
||||||
|
|
||||||
|
print($record->autonomousSystemNumber . "\n"); // 217
|
||||||
|
print($record->autonomousSystemOrganization . "\n"); // 'University of Minnesota'
|
||||||
|
print($record->isp . "\n"); // 'University of Minnesota'
|
||||||
|
print($record->organization . "\n"); // 'University of Minnesota'
|
||||||
|
|
||||||
|
print($record->ipAddress . "\n"); // '128.101.101.101'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Web Service Client ##
|
||||||
|
|
||||||
|
### Usage ###
|
||||||
|
|
||||||
|
To use this API, you must create a new `\GeoIp2\WebService\Client`
|
||||||
|
object with your `$userId` and `$licenseKey`, then you call the method
|
||||||
corresponding to a specific end point, passing it the IP address you want to
|
corresponding to a specific end point, passing it the IP address you want to
|
||||||
look up.
|
look up.
|
||||||
|
|
||||||
|
@ -64,41 +203,43 @@ If the request succeeds, the method call will return a model class for the end
|
||||||
point you called. This model in turn contains multiple record classes, each of
|
point you called. This model in turn contains multiple record classes, each of
|
||||||
which represents part of the data returned by the web service.
|
which represents part of the data returned by the web service.
|
||||||
|
|
||||||
|
If there is an error, a structured exception is thrown.
|
||||||
|
|
||||||
See the API documentation for more details.
|
See the API documentation for more details.
|
||||||
|
|
||||||
## Example ##
|
### Example ###
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
require_once 'vendor/autoload.php';
|
require_once 'vendor/autoload.php';
|
||||||
use \GeoIP2\WebService\Client;
|
use GeoIp2\WebService\Client;
|
||||||
|
|
||||||
|
// This creates a Client object that can be reused across requests.
|
||||||
|
// Replace "42" with your user ID and "license_key" with your license
|
||||||
|
// key.
|
||||||
$client = new Client(42, 'abcdef123456');
|
$client = new Client(42, 'abcdef123456');
|
||||||
$omni = $client->omni('24.24.24.24');
|
|
||||||
echo $omni->country->isoCode;
|
// Replace "city" with the method corresponding to the web service that
|
||||||
|
// you are using, e.g., "country", "insights".
|
||||||
|
$record = $client->city('128.101.101.101');
|
||||||
|
|
||||||
|
print($record->country->isoCode . "\n"); // 'US'
|
||||||
|
print($record->country->name . "\n"); // 'United States'
|
||||||
|
print($record->country->names['zh-CN'] . "\n"); // '美国'
|
||||||
|
|
||||||
|
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
|
||||||
|
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
|
||||||
|
|
||||||
|
print($record->city->name . "\n"); // 'Minneapolis'
|
||||||
|
|
||||||
|
print($record->postal->code . "\n"); // '55455'
|
||||||
|
|
||||||
|
print($record->location->latitude . "\n"); // 44.9733
|
||||||
|
print($record->location->longitude . "\n"); // -93.2323
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Exceptions ##
|
### What data is returned? ###
|
||||||
|
|
||||||
For details on the possible errors returned by the web service itself, see
|
|
||||||
http://dev.maxmind.com/geoip2/geoip/web-services for the GeoIP2 web service
|
|
||||||
docs.
|
|
||||||
|
|
||||||
If the web service returns an explicit error document, this is thrown as a
|
|
||||||
```\GeoIP2\Exception\WebServiceException```. If some other sort of transport
|
|
||||||
error occurs, this is thrown as a ```\GeoIP2\Exception\HttpException```.
|
|
||||||
The difference is that the web service error includes an error message and
|
|
||||||
error code delivered by the web service. The latter is thrown when some sort
|
|
||||||
of unanticipated error occurs, such as the web service returning a 500 or an
|
|
||||||
invalid error document.
|
|
||||||
|
|
||||||
If the web service returns any status code besides 200, 4xx, or 5xx, this also
|
|
||||||
becomes a ```\GeoIP2\Exception\HttpException```.
|
|
||||||
|
|
||||||
Finally, if the web service returns a 200 but the body is invalid, the client
|
|
||||||
throws a ```\GeoIP2\Exception\GeoIP2Exception```.
|
|
||||||
|
|
||||||
## What data is returned? ##
|
|
||||||
|
|
||||||
While many of the end points return the same basic records, the attributes
|
While many of the end points return the same basic records, the attributes
|
||||||
which can be populated vary between end points. In addition, while an end
|
which can be populated vary between end points. In addition, while an end
|
||||||
|
@ -108,24 +249,22 @@ piece of data for any given IP address.
|
||||||
Because of these factors, it is possible for any end point to return a record
|
Because of these factors, it is possible for any end point to return a record
|
||||||
where some or all of the attributes are unpopulated.
|
where some or all of the attributes are unpopulated.
|
||||||
|
|
||||||
See http://dev.maxmind.com/geoip/geoip2/web-services for details on what data
|
See the
|
||||||
each end point may return.
|
[GeoIP2 Precision web service docs](http://dev.maxmind.com/geoip/geoip2/web-services)
|
||||||
|
for details on what data each end point may return.
|
||||||
|
|
||||||
The only piece of data which is always returned is the ```ipAddress```
|
The only piece of data which is always returned is the `ipAddress`
|
||||||
attribute in the ``GeoIP2\Record\Traits`` record.
|
attribute in the `GeoIp2\Record\Traits` record.
|
||||||
|
|
||||||
Every record class attribute has a corresponding predicate method so you can
|
|
||||||
check to see if the attribute is set.
|
|
||||||
|
|
||||||
## Integration with GeoNames ##
|
## Integration with GeoNames ##
|
||||||
|
|
||||||
[GeoNames](http://www.geonames.org/) offers web services and downloadable
|
[GeoNames](http://www.geonames.org/) offers web services and downloadable
|
||||||
databases with data on geographical features around the world, including
|
databases with data on geographical features around the world, including
|
||||||
populated places. They offer both free and paid premium data. Each
|
populated places. They offer both free and paid premium data. Each
|
||||||
feature is unique identified by a ```geonameId```, which is an integer.
|
feature is unique identified by a `geonameId`, which is an integer.
|
||||||
|
|
||||||
Many of the records returned by the GeoIP2 web services and databases
|
Many of the records returned by the GeoIP2 web services and databases
|
||||||
include a ```geonameId``` property. This is the ID of a geographical feature
|
include a `geonameId` property. This is the ID of a geographical feature
|
||||||
(city, region, country, etc.) in the GeoNames database.
|
(city, region, country, etc.) in the GeoNames database.
|
||||||
|
|
||||||
Some of the data that MaxMind provides is also sourced from GeoNames. We
|
Some of the data that MaxMind provides is also sourced from GeoNames. We
|
||||||
|
@ -135,11 +274,11 @@ the GeoNames premium data set.
|
||||||
## Reporting data problems ##
|
## Reporting data problems ##
|
||||||
|
|
||||||
If the problem you find is that an IP address is incorrectly mapped,
|
If the problem you find is that an IP address is incorrectly mapped,
|
||||||
please submit your correction to MaxMind at
|
please
|
||||||
http://www.maxmind.com/en/correction.
|
[submit your correction to MaxMind](http://www.maxmind.com/en/correction).
|
||||||
|
|
||||||
If you find some other sort of mistake, like an incorrect spelling,
|
If you find some other sort of mistake, like an incorrect spelling,
|
||||||
please check the GeoNames site (http://www.geonames.org/) first. Once
|
please check the [GeoNames site](http://www.geonames.org/) first. Once
|
||||||
you've searched for a place and found it on the GeoNames map view, there
|
you've searched for a place and found it on the GeoNames map view, there
|
||||||
are a number of links you can use to correct data ("move", "edit",
|
are a number of links you can use to correct data ("move", "edit",
|
||||||
"alternate names", etc.). Once the correction is part of the GeoNames
|
"alternate names", etc.). Once the correction is part of the GeoNames
|
||||||
|
@ -147,41 +286,43 @@ data set, it will be automatically incorporated into future MaxMind
|
||||||
releases.
|
releases.
|
||||||
|
|
||||||
If you are a paying MaxMind customer and you're not sure where to submit
|
If you are a paying MaxMind customer and you're not sure where to submit
|
||||||
a correction, please contact MaxMind support at
|
a correction, please
|
||||||
http://www.maxmind.com/en/support for help.
|
[contact MaxMind support](http://www.maxmind.com/en/support) for help.
|
||||||
|
|
||||||
## Other Support ##
|
## Other Support ##
|
||||||
|
|
||||||
Please report all issues with this code using the GitHub issue tracker
|
Please report all issues with this code using the
|
||||||
at https://github.com/maxmind/GeoIP2-php/issues
|
[GitHub issue tracker](https://github.com/maxmind/GeoIP2-php/issues).
|
||||||
|
|
||||||
If you are having an issue with a MaxMind service that is not specific
|
If you are having an issue with a MaxMind service that is not specific
|
||||||
to the client API please see http://www.maxmind.com/en/support for
|
to the client API, please see
|
||||||
details.
|
[our support page](http://www.maxmind.com/en/support).
|
||||||
|
|
||||||
## Requirements ##
|
## Requirements ##
|
||||||
|
|
||||||
This code requires PHP 5.3 or greater. Older versions of PHP are not
|
This code requires PHP 5.3 or greater. Older versions of PHP are not
|
||||||
supported.
|
supported.
|
||||||
|
|
||||||
This library also relies on the [Guzzle HTTP client](http://guzzlephp.org/).
|
This library works and is tested with HHVM.
|
||||||
|
|
||||||
|
This library also relies on the [Guzzle3 HTTP client](https://github.com/guzzle/guzzle3)
|
||||||
|
and the [MaxMind DB Reader](https://github.com/maxmind/MaxMind-DB-Reader-php).
|
||||||
|
|
||||||
|
If you are using PHP 5.3 with an autoloader besides Composer, you must load
|
||||||
|
`JsonSerializable.php` in the `compat` directory.
|
||||||
|
|
||||||
## Contributing ##
|
## Contributing ##
|
||||||
|
|
||||||
Patches and pull requests are encouraged. All code should follow the
|
Patches and pull requests are encouraged. All code should follow the
|
||||||
PSR-2 style guidelines. Please include unit tests whenever possible.
|
PSR-2 style guidelines. Please include unit tests whenever possible. You may obtain the test data for the maxmind-db folder by running `git submodule update --init --recursive` or adding `--recursive` to your initial clone, or from https://github.com/maxmind/MaxMind-DB
|
||||||
|
|
||||||
## Versioning ##
|
## Versioning ##
|
||||||
|
|
||||||
The GeoIP2 PHP API uses [Semantic Versioning](http://semver.org/).
|
The GeoIP2 PHP API uses [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## Author ##
|
|
||||||
|
|
||||||
[Gregory Oschwald](mailto:goschwald@maxmind.com)
|
|
||||||
|
|
||||||
## Copyright and License ##
|
## Copyright and License ##
|
||||||
|
|
||||||
This software is Copyright (c) 2013 by MaxMind, Inc.
|
This software is Copyright (c) 2014 by MaxMind, Inc.
|
||||||
|
|
||||||
|
This is free software, licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
This is free software, licensed under the GNU Lesser General Public License
|
|
||||||
version 2.1 or later.
|
|
||||||
|
|
26
bin/benchmark.php
Executable file
26
bin/benchmark.php
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once '../vendor/autoload.php';
|
||||||
|
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
use GeoIp2\Exception\AddressNotFoundException;
|
||||||
|
|
||||||
|
$reader = new Reader('GeoLite2-City.mmdb');
|
||||||
|
$count = 40000;
|
||||||
|
$startTime = microtime(true);
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$ip = long2ip(rand(0, pow(2, 32) -1));
|
||||||
|
try {
|
||||||
|
$t = $reader->city($ip);
|
||||||
|
} catch (AddressNotFoundException $e) {
|
||||||
|
}
|
||||||
|
if ($i % 1000 == 0) {
|
||||||
|
print($i . ' ' . $ip . "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$endTime = microtime(true);
|
||||||
|
|
||||||
|
$duration = $endTime - $startTime;
|
||||||
|
print('Requests per second: ' . $count / $duration . "\n");
|
36
box.json
Normal file
36
box.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"alias": "geoip2.phar",
|
||||||
|
"main": "phar-stub.php",
|
||||||
|
"output": "geoip2.phar",
|
||||||
|
"compactors": [
|
||||||
|
"Herrera\\Box\\Compactor\\Composer",
|
||||||
|
"Herrera\\Box\\Compactor\\Json",
|
||||||
|
"Herrera\\Box\\Compactor\\Php"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"finder": [
|
||||||
|
{
|
||||||
|
"name": [
|
||||||
|
"LICENSE",
|
||||||
|
"LICENSE.*",
|
||||||
|
"*.php",
|
||||||
|
"*.pem",
|
||||||
|
"*.pem.md5"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"phpunit",
|
||||||
|
"satooshi",
|
||||||
|
"Tests",
|
||||||
|
"tests",
|
||||||
|
"yaml"
|
||||||
|
],
|
||||||
|
"in": "vendor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directories": ["compat", "src/"],
|
||||||
|
"git-version": "git-version",
|
||||||
|
"shebang": false,
|
||||||
|
"stub": true
|
||||||
|
}
|
13
compat/JsonSerializable.php
Normal file
13
compat/JsonSerializable.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface exists to provide backwards compatibility with PHP 5.3
|
||||||
|
*/
|
||||||
|
interface JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns data that can be serialized by json_encode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function jsonSerialize();
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "geoip2/geoip2",
|
"name": "geoip2/geoip2",
|
||||||
"description": "MaxMind GeoIP2 PHP API",
|
"description": "MaxMind GeoIP2 PHP API",
|
||||||
"keywords": [ "geoip", "geolocation", "maxmind" ],
|
"keywords": ["geoip", "geoip2", "geolocation", "ip", "maxmind"],
|
||||||
"homepage": "https://github.com/maxmind/GeoIP2-php",
|
"homepage": "https://github.com/maxmind/GeoIP2-php",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "LGPL-2.1+",
|
"license": "Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Gregory J. Oschwald",
|
"name": "Gregory J. Oschwald",
|
||||||
|
@ -14,13 +14,17 @@
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"guzzle/guzzle": "3.*",
|
"guzzle/guzzle": "3.*",
|
||||||
|
"maxmind-db/reader": "~1.0",
|
||||||
"php": ">=5.3.1"
|
"php": ">=5.3.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "3.7.*",
|
"phpunit/phpunit": "4.2.*",
|
||||||
"satooshi/php-coveralls": "dev-master"
|
"satooshi/php-coveralls": "dev-master"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": { "GeoIP2": "src/" }
|
"psr-0": {
|
||||||
|
"GeoIp2": "src/",
|
||||||
|
"JsonSerializable": "compat/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
dev-bin/phar-test.php
Executable file
15
dev-bin/phar-test.php
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
require_once 'geoip2.phar';
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
|
||||||
|
$record = $reader->city('81.2.69.160');
|
||||||
|
|
||||||
|
if ( $record->country->isoCode === 'GB' ) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Problem with Phar!');
|
||||||
|
exit(1);
|
112
dev-bin/release.sh
Executable file
112
dev-bin/release.sh
Executable file
|
@ -0,0 +1,112 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TAG=$1
|
||||||
|
|
||||||
|
if [ -z $TAG ]; then
|
||||||
|
echo "Please specify a tag"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f geoip2.phar ]; then
|
||||||
|
rm geoip2.phar
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo ". is not clean." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d vendor ]; then
|
||||||
|
rm -fr vendor
|
||||||
|
fi
|
||||||
|
|
||||||
|
php composer.phar self-update
|
||||||
|
php composer.phar update --no-dev
|
||||||
|
|
||||||
|
if [ ! -f box.phar ]; then
|
||||||
|
wget -O box.phar "https://github.com/box-project/box2/releases/download/2.5.0/box-2.5.0.phar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
php box.phar build
|
||||||
|
|
||||||
|
PHAR_TEST=$(./dev-bin/phar-test.php)
|
||||||
|
if [[ -n $PHAR_TEST ]]; then
|
||||||
|
echo "Phar test outputed non-empty string: $PHAR_TEST"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download test deps
|
||||||
|
php composer.phar update
|
||||||
|
|
||||||
|
./vendor/bin/phpunit
|
||||||
|
|
||||||
|
if [ ! -d .gh-pages ]; then
|
||||||
|
echo "Checking out gh-pages in .gh-pages"
|
||||||
|
git clone -b gh-pages git@git.maxmind.com:GeoIP2-php .gh-pages
|
||||||
|
pushd .gh-pages
|
||||||
|
else
|
||||||
|
echo "Updating .gh-pages"
|
||||||
|
pushd .gh-pages
|
||||||
|
git pull
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo ".gh-pages is not clean" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We no longer have apigen as a dependency in Composer as releases are
|
||||||
|
# sporadically deleted upstream and compatibility is often broken on patch
|
||||||
|
# releases.
|
||||||
|
if [ ! -f apigen.phar ]; then
|
||||||
|
wget -O apigen.phar "https://github.com/apigen/apigen/releases/download/v4.0.0-RC3/apigen-4.0.0-RC3.phar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
cat <<EOF > apigen.neon
|
||||||
|
destination: doc/$TAG
|
||||||
|
|
||||||
|
source:
|
||||||
|
- ../src
|
||||||
|
|
||||||
|
title: "GeoIP2 PHP API $TAG"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
php apigen.phar generate
|
||||||
|
|
||||||
|
|
||||||
|
PAGE=index.md
|
||||||
|
cat <<EOF > $PAGE
|
||||||
|
---
|
||||||
|
layout: default
|
||||||
|
title: MaxMind GeoIP2 PHP API
|
||||||
|
language: php
|
||||||
|
version: $TAG
|
||||||
|
---
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat ../README.md >> $PAGE
|
||||||
|
|
||||||
|
git add doc/
|
||||||
|
git commit -m "Updated for $TAG" -a
|
||||||
|
|
||||||
|
read -e -p "Push to origin? " SHOULD_PUSH
|
||||||
|
|
||||||
|
if [ "$SHOULD_PUSH" != "y" ]; then
|
||||||
|
echo "Aborting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we don't push directly to github, the page doesn't get built for some
|
||||||
|
# reason.
|
||||||
|
git push git@github.com:maxmind/GeoIP2-php.git
|
||||||
|
git push
|
||||||
|
|
||||||
|
popd
|
||||||
|
|
||||||
|
git tag -a $TAG
|
||||||
|
git push
|
||||||
|
git push --tags
|
1
maxmind-db
Submodule
1
maxmind-db
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit e53ed8cde6951be3bbd0fdb300d69c898b399a97
|
17
phar-stub.php
Normal file
17
phar-stub.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'phar://geoip2.phar/vendor/autoload.php';
|
||||||
|
|
||||||
|
// The following was taken from Guzzle (MIT license)
|
||||||
|
|
||||||
|
// Copy the cacert.pem file from the phar if it is not in the temp folder.
|
||||||
|
$from = 'phar://geoip2.phar/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem';
|
||||||
|
$certFile = sys_get_temp_dir() . '/guzzle-cacert.pem';
|
||||||
|
|
||||||
|
// Only copy when the file size is different
|
||||||
|
if (!file_exists($certFile) || filesize($certFile) != filesize($from)) {
|
||||||
|
if (!copy($from, $certFile)) {
|
||||||
|
throw new RuntimeException("Could not copy {$from} to {$certFile}: "
|
||||||
|
. var_export(error_get_last(), true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,13 +3,13 @@
|
||||||
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
|
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="GeoIP2 Test Suite">
|
<testsuite name="GeoIP2 Test Suite">
|
||||||
<directory suffix="Test.php">./tests/GeoIP2/Test/</directory>
|
<directory suffix="Test.php">./tests/GeoIp2/Test/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<filter>
|
<filter>
|
||||||
<whitelist>
|
<whitelist>
|
||||||
<directory suffix=".php">./src/GeoIP2/</directory>
|
<directory suffix=".php">./src/GeoIp2/</directory>
|
||||||
</whitelist>
|
</whitelist>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a generic error.
|
|
||||||
*/
|
|
||||||
class GeoIP2Exception extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a model for the data returned by the GeoIP2
|
|
||||||
* City/ISP/Org end point.
|
|
||||||
*
|
|
||||||
* The only difference between the City, City/ISP/Org, and Omni model
|
|
||||||
* classes is which fields in each record may be populated. See
|
|
||||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\City $city City data for the requested IP
|
|
||||||
* address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Continent $continent Continent data for the
|
|
||||||
* requested IP address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $country Country data for the requested
|
|
||||||
* IP address. This object represents the country where MaxMind believes the
|
|
||||||
* end user is located.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Location $location Location data for the
|
|
||||||
* requested IP address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\MaxMind $maxmind Data related to your MaxMind
|
|
||||||
* account.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $registeredCountry Registered country
|
|
||||||
* data for the requested IP address. This record represents the country
|
|
||||||
* where the ISP has registered a given IP block in and may differ from the
|
|
||||||
* user's country.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\RepresentedCountry $representedCountry
|
|
||||||
* Represented country data for the requested IP address. The represented
|
|
||||||
* country is used for things like military bases or embassies. It is only
|
|
||||||
* present when the represented country differs from the country.
|
|
||||||
*
|
|
||||||
* @property array $subdivisions An array of {@link \GeoIP2\Record\Subdivision}
|
|
||||||
* objects representing the country subdivisions for the requested IP
|
|
||||||
* address. The number and type of subdivisions varies by country, but a
|
|
||||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
|
||||||
* are ordered from most general (largest) to most specific (smallest).
|
|
||||||
* If the response did not contain any subdivisions, this method returns
|
|
||||||
* an empty array.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Subdivision $mostSpecificSubdivision An object
|
|
||||||
* representing the most specific subdivision returned. If the response
|
|
||||||
* did not contain any subdivisions, this method returns an empty
|
|
||||||
* {@link \GeoIP2\Record\Subdivision} object.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Traits $traits Data for the traits of the
|
|
||||||
* requested IP address.
|
|
||||||
*/
|
|
||||||
class CityIspOrg extends City
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a model for the data returned by the GeoIP2 Country
|
|
||||||
* end point.
|
|
||||||
*
|
|
||||||
* The only difference between the City, City/ISP/Org, and Omni model
|
|
||||||
* classes is which fields in each record may be populated. See
|
|
||||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Continent $continent Continent data for the
|
|
||||||
* requested IP address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $country Country data for the requested
|
|
||||||
* IP address. This object represents the country where MaxMind believes the
|
|
||||||
* end user is located.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\MaxMind $maxmind Data related to your MaxMind
|
|
||||||
* account.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $registeredCountry Registered country
|
|
||||||
* data for the requested IP address. This record represents the country
|
|
||||||
* where the ISP has registered a given IP block in and may differ from the
|
|
||||||
* user's country.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\RepresentedCountry $representedCountry
|
|
||||||
* Represented country data for the requested IP address. The represented
|
|
||||||
* country is used for things like military bases or embassies. It is only
|
|
||||||
* present when the represented country differs from the country.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Traits $traits Data for the traits of the
|
|
||||||
* requested IP address.
|
|
||||||
*/
|
|
||||||
class Country
|
|
||||||
{
|
|
||||||
private $continent;
|
|
||||||
private $country;
|
|
||||||
private $languages;
|
|
||||||
private $maxmind;
|
|
||||||
private $registeredCountry;
|
|
||||||
private $representedCountry;
|
|
||||||
private $traits;
|
|
||||||
private $raw;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
public function __construct($raw, $languages)
|
|
||||||
{
|
|
||||||
$this->raw = $raw;
|
|
||||||
|
|
||||||
$this->continent = new \GeoIP2\Record\Continent(
|
|
||||||
$this->get('continent'),
|
|
||||||
$languages
|
|
||||||
);
|
|
||||||
$this->country = new \GeoIP2\Record\Country(
|
|
||||||
$this->get('country'),
|
|
||||||
$languages
|
|
||||||
);
|
|
||||||
$this->maxmind = new \GeoIP2\Record\MaxMind($this->get('maxmind'));
|
|
||||||
$this->registeredCountry = new \GeoIP2\Record\Country(
|
|
||||||
$this->get('registered_country'),
|
|
||||||
$languages
|
|
||||||
);
|
|
||||||
$this->representedCountry = new \GeoIP2\Record\RepresentedCountry(
|
|
||||||
$this->get('represented_country'),
|
|
||||||
$languages
|
|
||||||
);
|
|
||||||
$this->traits = new \GeoIP2\Record\Traits($this->get('traits'));
|
|
||||||
|
|
||||||
$this->languages = $languages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
protected function get($field)
|
|
||||||
{
|
|
||||||
return isset($this->raw[$field]) ? $this->raw[$field] : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
public function __get ($attr)
|
|
||||||
{
|
|
||||||
if ($attr != "instance" && isset($this->$attr)) {
|
|
||||||
return $this->$attr;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \RuntimeException("Unknown attribute: $attr");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a model for the data returned by the GeoIP2
|
|
||||||
* Omni end point.
|
|
||||||
*
|
|
||||||
* The only difference between the City, City/ISP/Org, and Omni model
|
|
||||||
* classes is which fields in each record may be populated. See
|
|
||||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\City $city City data for the requested IP
|
|
||||||
* address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Continent $continent Continent data for the
|
|
||||||
* requested IP address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $country Country data for the requested
|
|
||||||
* IP address. This object represents the country where MaxMind believes the
|
|
||||||
* end user is located.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Location $location Location data for the
|
|
||||||
* requested IP address.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\MaxMind $maxmind Data related to your MaxMind
|
|
||||||
* account.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Country $registeredCountry Registered country
|
|
||||||
* data for the requested IP address. This record represents the country
|
|
||||||
* where the ISP has registered a given IP block in and may differ from the
|
|
||||||
* user's country.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\RepresentedCountry $representedCountry
|
|
||||||
* Represented country data for the requested IP address. The represented
|
|
||||||
* country is used for things like military bases or embassies. It is only
|
|
||||||
* present when the represented country differs from the country.
|
|
||||||
*
|
|
||||||
* @property array $subdivisions An array of {@link \GeoIP2\Record\Subdivision}
|
|
||||||
* objects representing the country subdivisions for the requested IP
|
|
||||||
* address. The number and type of subdivisions varies by country, but a
|
|
||||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
|
||||||
* are ordered from most general (largest) to most specific (smallest).
|
|
||||||
* If the response did not contain any subdivisions, this method returns
|
|
||||||
* an empty array.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Subdivision $mostSpecificSubdivision An object
|
|
||||||
* representing the most specific subdivision returned. If the response
|
|
||||||
* did not contain any subdivisions, this method returns an empty
|
|
||||||
* {@link \GeoIP2\Record\Subdivision} object.
|
|
||||||
*
|
|
||||||
* @property \GeoIP2\Record\Traits $traits Data for the traits of the
|
|
||||||
* requested IP address.
|
|
||||||
*/
|
|
||||||
class Omni extends CityIspOrg
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
|
||||||
|
|
||||||
abstract class AbstractRecord
|
|
||||||
{
|
|
||||||
private $record;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
public function __construct($record)
|
|
||||||
{
|
|
||||||
$this->record = $record;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
public function __get($attr)
|
|
||||||
{
|
|
||||||
$valid = in_array($attr, $this->validAttributes);
|
|
||||||
// XXX - kind of ugly but greatly reduces boilerplate code
|
|
||||||
$key = strtolower(preg_replace('/([A-Z])/', '_\1', $attr));
|
|
||||||
|
|
||||||
if ($valid && isset($this->record[$key])) {
|
|
||||||
return $this->record[$key];
|
|
||||||
} elseif ($valid) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException("Unknown attribute: $attr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,312 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace GeoIP2\WebService;
|
|
||||||
|
|
||||||
use GeoIP2\Exception\GeoIP2Exception;
|
|
||||||
use GeoIP2\Exception\HttpException;
|
|
||||||
use GeoIP2\Exception\WebServiceException;
|
|
||||||
use GeoIP2\Model\City;
|
|
||||||
use GeoIP2\Model\CityIspOrg;
|
|
||||||
use GeoIP2\Model\Country;
|
|
||||||
use GeoIP2\Model\Omni;
|
|
||||||
use Guzzle\Http\Client as GuzzleClient;
|
|
||||||
use Guzzle\Common\Exception\RuntimeException;
|
|
||||||
use Guzzle\Http\Exception\ClientErrorResponseException;
|
|
||||||
use Guzzle\Http\Exception\ServerErrorResponseException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides a client API for all the GeoIP2 web service's
|
|
||||||
* end points. The end points are Country, City, City/ISP/Org, and Omni. Each
|
|
||||||
* end point returns a different set of data about an IP address, with Country
|
|
||||||
* returning the least data and Omni the most.
|
|
||||||
*
|
|
||||||
* Each web service end point is represented by a different model class, and
|
|
||||||
* these model classes in turn contain multiple Record classes. The record
|
|
||||||
* classes have attributes which contain data about the IP address.
|
|
||||||
*
|
|
||||||
* If the web service does not return a particular piece of data for an IP
|
|
||||||
* address, the associated attribute is not populated.
|
|
||||||
*
|
|
||||||
* The web service may not return any information for an entire record, in
|
|
||||||
* which case all of the attributes for that record class will be empty.
|
|
||||||
*
|
|
||||||
* **Usage**
|
|
||||||
*
|
|
||||||
* The basic API for this class is the same for all of the web service end
|
|
||||||
* points. First you create a web service object with your MaxMind
|
|
||||||
* <code>$userId</code> and <code>$licenseKey</code>, then you call the method
|
|
||||||
* corresponding to a specific end point, passing it the IP address you want
|
|
||||||
* to look up.
|
|
||||||
*
|
|
||||||
* If the request succeeds, the method call will return a model class for
|
|
||||||
* the end point you called. This model in turn contains multiple record
|
|
||||||
* classes, each of which represents part of the data returned by the web
|
|
||||||
* service.
|
|
||||||
*
|
|
||||||
* If the request fails, the client class throws an exception.
|
|
||||||
*
|
|
||||||
* **Exceptions**
|
|
||||||
*
|
|
||||||
* For details on the possible errors returned by the web service itself, see
|
|
||||||
* {@link http://dev.maxmind.com/geoip2/geoip/web-services the GeoIP2 web
|
|
||||||
* service docs}.
|
|
||||||
*
|
|
||||||
* If the web service returns an explicit error document, this is thrown as a
|
|
||||||
* {@link \GeoIP2\Exception\WebServiceException}. If some other sort of
|
|
||||||
* transport error occurs, this is thrown as a {@link
|
|
||||||
* \GeoIP2\Exception\HttpException}. The difference is that the web service
|
|
||||||
* error includes an error message and error code delivered by the web
|
|
||||||
* service. The latter is thrown when some sort of unanticipated error occurs,
|
|
||||||
* such as the web service returning a 500 or an invalid error document.
|
|
||||||
*
|
|
||||||
* If the web service returns any status code besides 200, 4xx, or 5xx, this
|
|
||||||
* also becomes a {@link \GeoIP2\Exception\HttpException}.
|
|
||||||
*
|
|
||||||
* Finally, if the web service returns a 200 but the body is invalid, the
|
|
||||||
* client throws a {@link \GeoIP2\Exception\GeoIP2Exception}.
|
|
||||||
*/
|
|
||||||
class Client
|
|
||||||
{
|
|
||||||
private $userId;
|
|
||||||
private $licenseKey;
|
|
||||||
private $languages;
|
|
||||||
private $host;
|
|
||||||
private $guzzleClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param int $userId Your MaxMind user ID
|
|
||||||
* @param string $licenseKey Your MaxMind license key
|
|
||||||
* @param array $languages List of language codes to use in name property
|
|
||||||
* from most preferred to least preferred.
|
|
||||||
* @param string $host Optional host parameter
|
|
||||||
* @param object $guzzleClient Optional Guzzle client to use (to facilitate
|
|
||||||
* unit testing).
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
$userId,
|
|
||||||
$licenseKey,
|
|
||||||
$languages = array('en'),
|
|
||||||
$host = 'geoip.maxmind.com',
|
|
||||||
$guzzleClient = null
|
|
||||||
) {
|
|
||||||
$this->userId = $userId;
|
|
||||||
$this->licenseKey = $licenseKey;
|
|
||||||
$this->languages = $languages;
|
|
||||||
$this->host = $host;
|
|
||||||
// To enable unit testing
|
|
||||||
$this->guzzleClient = $guzzleClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method calls the GeoIP2 City endpoint.
|
|
||||||
*
|
|
||||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
|
||||||
* address is provided, the address that the web service is called
|
|
||||||
* from will be used.
|
|
||||||
*
|
|
||||||
* @return \GeoIP2\Model\City
|
|
||||||
*
|
|
||||||
* @throws \GeoIP2\Exception\GeoIP2Exception if there was a generic
|
|
||||||
* error processing your request.
|
|
||||||
* @throws \GeoIP2\Exception\HttpException if there was an HTTP transport
|
|
||||||
* error.
|
|
||||||
* @throws \GeoIP2\Exception\WebServiceException if an error was returned
|
|
||||||
* by MaxMind's GeoIP2 web service.
|
|
||||||
*/
|
|
||||||
public function city($ipAddress = 'me')
|
|
||||||
{
|
|
||||||
return $this->responseFor('city', 'City', $ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method calls the GeoIP2 Country endpoint.
|
|
||||||
*
|
|
||||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
|
||||||
* address is provided, the address that the web service is called
|
|
||||||
* from will be used.
|
|
||||||
*
|
|
||||||
* @return \GeoIP2\Model\Country
|
|
||||||
*
|
|
||||||
* @throws \GeoIP2\Exception\GeoIP2Exception if there was a generic
|
|
||||||
* error processing your request.
|
|
||||||
* @throws \GeoIP2\Exception\HttpException if there was an HTTP transport
|
|
||||||
* error.
|
|
||||||
* @throws \GeoIP2\Exception\WebServiceException if an error was returned
|
|
||||||
* by MaxMind's GeoIP2 web service.
|
|
||||||
*/
|
|
||||||
public function country($ipAddress = 'me')
|
|
||||||
{
|
|
||||||
return $this->responseFor('country', 'Country', $ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method calls the GeoIP2 City/ISP/Org endpoint.
|
|
||||||
*
|
|
||||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
|
||||||
* address is provided, the address that the web service is called
|
|
||||||
* from will be used.
|
|
||||||
*
|
|
||||||
* @return \GeoIP2\Model\CityIspOrg
|
|
||||||
*
|
|
||||||
* @throws \GeoIP2\Exception\GeoIP2Exception if there was a generic
|
|
||||||
* error processing your request.
|
|
||||||
* @throws \GeoIP2\Exception\HttpException if there was an HTTP transport
|
|
||||||
* error.
|
|
||||||
* @throws \GeoIP2\Exception\WebServiceException if an error was returned
|
|
||||||
* by MaxMind's GeoIP2 web service.
|
|
||||||
*/
|
|
||||||
public function cityIspOrg($ipAddress = 'me')
|
|
||||||
{
|
|
||||||
return $this->responseFor('city_isp_org', 'CityIspOrg', $ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method calls the GeoIP2 Omni endpoint.
|
|
||||||
*
|
|
||||||
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
|
||||||
* address is provided, the address that the web service is called
|
|
||||||
* from will be used.
|
|
||||||
*
|
|
||||||
* @return \GeoIP2\Model\Omni
|
|
||||||
*
|
|
||||||
* @throws \GeoIP2\Exception\GeoIP2Exception if there was a generic
|
|
||||||
* error processing your request.
|
|
||||||
* @throws \GeoIP2\Exception\HttpException if there was an HTTP transport
|
|
||||||
* error.
|
|
||||||
* @throws \GeoIP2\Exception\WebServiceException if an error was returned
|
|
||||||
* by MaxMind's GeoIP2 web service.
|
|
||||||
*/
|
|
||||||
public function omni($ipAddress = 'me')
|
|
||||||
{
|
|
||||||
return $this->responseFor('omni', 'Omni', $ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function responseFor($endpoint, $class, $ipAddress)
|
|
||||||
{
|
|
||||||
$uri = implode('/', array($this->baseUri(), $endpoint, $ipAddress));
|
|
||||||
|
|
||||||
$client = $this->guzzleClient ?
|
|
||||||
$this->guzzleClient : new GuzzleClient();
|
|
||||||
$request = $client->get($uri, array('Accept' => 'application/json'));
|
|
||||||
$request->setAuth($this->userId, $this->licenseKey);
|
|
||||||
$ua = $request->getHeader('User-Agent');
|
|
||||||
$ua = "GeoIP2 PHP API ($ua)";
|
|
||||||
$request->setHeader('User-Agent', $ua);
|
|
||||||
|
|
||||||
$response = null;
|
|
||||||
try {
|
|
||||||
$response = $request->send();
|
|
||||||
} catch (ClientErrorResponseException $e) {
|
|
||||||
$this->handle4xx($e->getResponse(), $uri);
|
|
||||||
} catch (ServerErrorResponseException $e) {
|
|
||||||
$this->handle5xx($e->getResponse(), $uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($response && $response->isSuccessful()) {
|
|
||||||
$body = $this->handleSuccess($response, $uri);
|
|
||||||
$class = "GeoIP2\\Model\\" . $class;
|
|
||||||
return new $class($body, $this->languages);
|
|
||||||
} else {
|
|
||||||
$this->handleNon200($response, $uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleSuccess($response, $uri)
|
|
||||||
{
|
|
||||||
if ($response->getContentLength() == 0) {
|
|
||||||
throw new GeoIP2Exception(
|
|
||||||
"Received a 200 response for $uri but did not " .
|
|
||||||
"receive a HTTP body."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return $response->json();
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
throw new GeoIP2Exception(
|
|
||||||
"Received a 200 response for $uri but could not decode " .
|
|
||||||
"the response as JSON: " . $e->getMessage()
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handle4xx($response, $uri)
|
|
||||||
{
|
|
||||||
$status = $response->getStatusCode();
|
|
||||||
|
|
||||||
$body = array();
|
|
||||||
|
|
||||||
if ($response->getContentLength() > 0) {
|
|
||||||
if (strstr($response->getContentType(), 'json')) {
|
|
||||||
try {
|
|
||||||
$body = $response->json();
|
|
||||||
if (!isset($body['code']) || !isset($body['error'])) {
|
|
||||||
throw new GeoIP2Exception(
|
|
||||||
'Response contains JSON but it does not specify ' .
|
|
||||||
'code or error keys: ' . $response->getBody()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
throw new HttpException(
|
|
||||||
"Received a $status error for $uri but it did not " .
|
|
||||||
"include the expected JSON body: " .
|
|
||||||
$e->getMessage(),
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
"Received a $status error for $uri with the " .
|
|
||||||
"following body: " . $response->getBody(),
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new HttpException(
|
|
||||||
"Received a $status error for $uri with no body",
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new WebServiceException(
|
|
||||||
$body['error'],
|
|
||||||
$body['code'],
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handle5xx($response, $uri)
|
|
||||||
{
|
|
||||||
$status = $response->getStatusCode();
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
"Received a server error ($status) for $uri",
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleNon200($response, $uri)
|
|
||||||
{
|
|
||||||
$status = $response->getStatusCode();
|
|
||||||
|
|
||||||
throw new HttpException(
|
|
||||||
"Received a very surprising HTTP status " .
|
|
||||||
"($status) for $uri",
|
|
||||||
$status,
|
|
||||||
$uri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function baseUri()
|
|
||||||
{
|
|
||||||
return 'https://' . $this->host . '/geoip/v2.0';
|
|
||||||
}
|
|
||||||
}
|
|
229
src/GeoIp2/Database/Reader.php
Normal file
229
src/GeoIp2/Database/Reader.php
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Database;
|
||||||
|
|
||||||
|
use GeoIp2\Exception\AddressNotFoundException;
|
||||||
|
use GeoIp2\ProviderInterface;
|
||||||
|
use MaxMind\Db\Reader as DbReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class provide a reader for the GeoIP2 database format.
|
||||||
|
* IP addresses can be looked up using the database specific methods.
|
||||||
|
*
|
||||||
|
* ## Usage ##
|
||||||
|
*
|
||||||
|
* The basic API for this class is the same for every database. First, you
|
||||||
|
* create a reader object, specifying a file name. You then call the method
|
||||||
|
* corresponding to the specific database, passing it the IP address you want
|
||||||
|
* to look up.
|
||||||
|
*
|
||||||
|
* If the request succeeds, the method call will return a model class for
|
||||||
|
* the method you called. This model in turn contains multiple record classes,
|
||||||
|
* each of which represents part of the data returned by the database. If
|
||||||
|
* the database does not contain the requested information, the attributes
|
||||||
|
* on the record class will have a `null` value.
|
||||||
|
*
|
||||||
|
* If the address is not in the database, an
|
||||||
|
* {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
|
||||||
|
* thrown. If an invalid IP address is passed to one of the methods, a
|
||||||
|
* SPL {@link \InvalidArgumentException} will be thrown. If the database is
|
||||||
|
* corrupt or invalid, a {@link \MaxMind\Db\Reader\InvalidDatabaseException}
|
||||||
|
* will be thrown.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Reader implements ProviderInterface
|
||||||
|
{
|
||||||
|
private $dbReader;
|
||||||
|
private $locales;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $filename The path to the GeoIP2 database file.
|
||||||
|
* @param array $locales List of locale codes to use in name property
|
||||||
|
* from most preferred to least preferred.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$filename,
|
||||||
|
$locales = array('en')
|
||||||
|
) {
|
||||||
|
$this->dbReader = new DbReader($filename);
|
||||||
|
$this->locales = $locales;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 City model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\City
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function city($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->modelFor('City', 'City', $ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 Country model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\Country
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function country($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->modelFor('Country', 'Country', $ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 Anonymous IP model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\AnonymousIp
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function anonymousIp($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->flatModelFor(
|
||||||
|
'AnonymousIp',
|
||||||
|
'GeoIP2-Anonymous-IP',
|
||||||
|
$ipAddress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 Connection Type model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\ConnectionType
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function connectionType($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->flatModelFor(
|
||||||
|
'ConnectionType',
|
||||||
|
'GeoIP2-Connection-Type',
|
||||||
|
$ipAddress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 Domain model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\Domain
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function domain($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->flatModelFor(
|
||||||
|
'Domain',
|
||||||
|
'GeoIP2-Domain',
|
||||||
|
$ipAddress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a GeoIP2 ISP model.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\Isp
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address is
|
||||||
|
* not in the database.
|
||||||
|
* @throws \MaxMind\Db\Reader\InvalidDatabaseException if the database
|
||||||
|
* is corrupt or invalid
|
||||||
|
*/
|
||||||
|
public function isp($ipAddress)
|
||||||
|
{
|
||||||
|
return $this->flatModelFor(
|
||||||
|
'Isp',
|
||||||
|
'GeoIP2-ISP',
|
||||||
|
$ipAddress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function modelFor($class, $type, $ipAddress)
|
||||||
|
{
|
||||||
|
$record = $this->getRecord($class, $type, $ipAddress);
|
||||||
|
|
||||||
|
$record['traits']['ip_address'] = $ipAddress;
|
||||||
|
$class = "GeoIp2\\Model\\" . $class;
|
||||||
|
|
||||||
|
return new $class($record, $this->locales);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function flatModelFor($class, $type, $ipAddress)
|
||||||
|
{
|
||||||
|
$record = $this->getRecord($class, $type, $ipAddress);
|
||||||
|
|
||||||
|
$record['ip_address'] = $ipAddress;
|
||||||
|
$class = "GeoIp2\\Model\\" . $class;
|
||||||
|
|
||||||
|
return new $class($record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRecord($class, $type, $ipAddress)
|
||||||
|
{
|
||||||
|
if (strpos($this->metadata()->databaseType, $type) === false) {
|
||||||
|
$method = lcfirst($class);
|
||||||
|
throw new \BadMethodCallException(
|
||||||
|
"The $method method cannot be used to open a "
|
||||||
|
. $this->metadata()->databaseType . " database"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$record = $this->dbReader->get($ipAddress);
|
||||||
|
if ($record === null) {
|
||||||
|
throw new AddressNotFoundException(
|
||||||
|
"The address $ipAddress is not in the database."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \InvalidArgumentException if arguments are passed to the method.
|
||||||
|
* @throws \BadMethodCallException if the database has been closed.
|
||||||
|
* @return \MaxMind\Db\Reader\Metadata object for the database.
|
||||||
|
*/
|
||||||
|
public function metadata()
|
||||||
|
{
|
||||||
|
return $this->dbReader->metadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the GeoIP2 database and returns the resources to the system.
|
||||||
|
*/
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
$this->dbReader->close();
|
||||||
|
}
|
||||||
|
}
|
10
src/GeoIp2/Exception/AddressNotFoundException.php
Normal file
10
src/GeoIp2/Exception/AddressNotFoundException.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a generic error.
|
||||||
|
*/
|
||||||
|
class AddressNotFoundException extends GeoIp2Exception
|
||||||
|
{
|
||||||
|
}
|
10
src/GeoIp2/Exception/AuthenticationException.php
Normal file
10
src/GeoIp2/Exception/AuthenticationException.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a generic error.
|
||||||
|
*/
|
||||||
|
class AuthenticationException extends GeoIp2Exception
|
||||||
|
{
|
||||||
|
}
|
10
src/GeoIp2/Exception/GeoIp2Exception.php
Normal file
10
src/GeoIp2/Exception/GeoIp2Exception.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a generic error.
|
||||||
|
*/
|
||||||
|
class GeoIp2Exception extends \Exception
|
||||||
|
{
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Exception;
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents an HTTP transport error.
|
* This class represents an HTTP transport error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class HttpException extends GeoIP2Exception
|
class HttpException extends GeoIp2Exception
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The URI queried
|
* The URI queried
|
||||||
|
@ -17,7 +17,7 @@ class HttpException extends GeoIP2Exception
|
||||||
$message,
|
$message,
|
||||||
$httpStatus,
|
$httpStatus,
|
||||||
$uri,
|
$uri,
|
||||||
Exception $previous = null
|
\Exception $previous = null
|
||||||
) {
|
) {
|
||||||
$this->uri = $uri;
|
$this->uri = $uri;
|
||||||
parent::__construct($message, $httpStatus, $previous);
|
parent::__construct($message, $httpStatus, $previous);
|
|
@ -1,12 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Exception;
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents an error returned by MaxMind's GeoIP2
|
* This class represents an error returned by MaxMind's GeoIP2
|
||||||
* web service.
|
* web service.
|
||||||
*/
|
*/
|
||||||
class WebServiceException extends HttpException
|
class InvalidRequestException extends HttpException
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The code returned by the MaxMind web service
|
* The code returned by the MaxMind web service
|
||||||
|
@ -18,7 +18,7 @@ class WebServiceException extends HttpException
|
||||||
$error,
|
$error,
|
||||||
$httpStatus,
|
$httpStatus,
|
||||||
$uri,
|
$uri,
|
||||||
Exception $previous = null
|
\Exception $previous = null
|
||||||
) {
|
) {
|
||||||
$this->error = $error;
|
$this->error = $error;
|
||||||
parent::__construct($message, $httpStatus, $uri, $previous);
|
parent::__construct($message, $httpStatus, $uri, $previous);
|
10
src/GeoIp2/Exception/OutOfQueriesException.php
Normal file
10
src/GeoIp2/Exception/OutOfQueriesException.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a generic error.
|
||||||
|
*/
|
||||||
|
class OutOfQueriesException extends GeoIp2Exception
|
||||||
|
{
|
||||||
|
}
|
60
src/GeoIp2/Model/AbstractModel.php
Normal file
60
src/GeoIp2/Model/AbstractModel.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
abstract class AbstractModel implements \JsonSerializable
|
||||||
|
{
|
||||||
|
protected $raw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
$this->raw = $raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
protected function get($field)
|
||||||
|
{
|
||||||
|
if (isset($this->raw[$field])) {
|
||||||
|
return $this->raw[$field];
|
||||||
|
} else {
|
||||||
|
if (preg_match('/^is_/', $field)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __get($attr)
|
||||||
|
{
|
||||||
|
if ($attr != "instance" && property_exists($this, $attr)) {
|
||||||
|
return $this->$attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException("Unknown attribute: $attr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __isset($attr)
|
||||||
|
{
|
||||||
|
return $attr != "instance" && isset($this->$attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->raw;
|
||||||
|
}
|
||||||
|
}
|
50
src/GeoIp2/Model/AnonymousIp.php
Normal file
50
src/GeoIp2/Model/AnonymousIp.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the GeoIP2 Anonymous IP model.
|
||||||
|
*
|
||||||
|
* @property boolean $isAnonymous This is true if the IP address belongs to
|
||||||
|
* any sort of anonymous network.
|
||||||
|
*
|
||||||
|
* @property boolean $isAnonymousVpn This is true if the IP address belongs to
|
||||||
|
* an anonymous VPN system.
|
||||||
|
*
|
||||||
|
* @property boolean $isHostingProvider This is true if the IP address belongs
|
||||||
|
* to a hosting provider.
|
||||||
|
*
|
||||||
|
* @property boolean $isPublicProxy This is true if the IP address belongs to
|
||||||
|
* a public proxy.
|
||||||
|
*
|
||||||
|
* @property boolean $isTorExitNode This is true if the IP address is a Tor
|
||||||
|
* exit node.
|
||||||
|
*
|
||||||
|
* @property string $ipAddress The IP address that the data in the model is
|
||||||
|
* for.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class AnonymousIp extends AbstractModel
|
||||||
|
{
|
||||||
|
protected $isAnonymous;
|
||||||
|
protected $isAnonymousVpn;
|
||||||
|
protected $isHostingProvider;
|
||||||
|
protected $isPublicProxy;
|
||||||
|
protected $isTorExitNode;
|
||||||
|
protected $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
parent::__construct($raw);
|
||||||
|
|
||||||
|
$this->isAnonymous = $this->get('is_anonymous');
|
||||||
|
$this->isAnonymousVpn = $this->get('is_anonymous_vpn');
|
||||||
|
$this->isHostingProvider = $this->get('is_hosting_provider');
|
||||||
|
$this->isPublicProxy = $this->get('is_public_proxy');
|
||||||
|
$this->isTorExitNode = $this->get('is_tor_exit_node');
|
||||||
|
$this->ipAddress = $this->get('ip_address');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,42 +1,41 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Model;
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a model for the data returned by the GeoIP2
|
* Model class for the data returned by GeoIP2 City web service and database.
|
||||||
* City end point.
|
|
||||||
*
|
*
|
||||||
* The only difference between the City, City/ISP/Org, and Omni model
|
* The only difference between the City and Insights model classes is which
|
||||||
* classes is which fields in each record may be populated. See
|
* fields in each record may be populated. See
|
||||||
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\City $city City data for the requested IP
|
* @property \GeoIp2\Record\City $city City data for the requested IP
|
||||||
* address.
|
* address.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Continent $continent Continent data for the
|
* @property \GeoIp2\Record\Continent $continent Continent data for the
|
||||||
* requested IP address.
|
* requested IP address.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Country $country Country data for the requested
|
* @property \GeoIp2\Record\Country $country Country data for the requested
|
||||||
* IP address. This object represents the country where MaxMind believes the
|
* IP address. This object represents the country where MaxMind believes the
|
||||||
* end user is located.
|
* end user is located.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Location $location Location data for the
|
* @property \GeoIp2\Record\Location $location Location data for the
|
||||||
* requested IP address.
|
* requested IP address.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\MaxMind $maxmind Data related to your MaxMind
|
* @property \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||||
* account.
|
* account.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Country $registeredCountry Registered country
|
* @property \GeoIp2\Record\Country $registeredCountry Registered country
|
||||||
* data for the requested IP address. This record represents the country
|
* data for the requested IP address. This record represents the country
|
||||||
* where the ISP has registered a given IP block in and may differ from the
|
* where the ISP has registered a given IP block and may differ from the
|
||||||
* user's country.
|
* user's country.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\RepresentedCountry $representedCountry
|
* @property \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||||
* Represented country data for the requested IP address. The represented
|
* Represented country data for the requested IP address. The represented
|
||||||
* country is used for things like military bases or embassies. It is only
|
* country is used for things like military bases. It is only present when
|
||||||
* present when the represented country differs from the country.
|
* the represented country differs from the country.
|
||||||
*
|
*
|
||||||
* @property array $subdivisions An array of {@link \GeoIP2\Record\Subdivision}
|
* @property array $subdivisions An array of {@link \GeoIp2\Record\Subdivision}
|
||||||
* objects representing the country subdivisions for the requested IP
|
* objects representing the country subdivisions for the requested IP
|
||||||
* address. The number and type of subdivisions varies by country, but a
|
* address. The number and type of subdivisions varies by country, but a
|
||||||
* subdivision is typically a state, province, county, etc. Subdivisions
|
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||||
|
@ -44,12 +43,12 @@ namespace GeoIP2\Model;
|
||||||
* If the response did not contain any subdivisions, this method returns
|
* If the response did not contain any subdivisions, this method returns
|
||||||
* an empty array.
|
* an empty array.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Subdivision $mostSpecificSubdivision An object
|
* @property \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||||
* representing the most specific subdivision returned. If the response
|
* representing the most specific subdivision returned. If the response
|
||||||
* did not contain any subdivisions, this method returns an empty
|
* did not contain any subdivisions, this method returns an empty
|
||||||
* {@link \GeoIP2\Record\Subdivision} object.
|
* {@link \GeoIp2\Record\Subdivision} object.
|
||||||
*
|
*
|
||||||
* @property \GeoIP2\Record\Traits $traits Data for the traits of the
|
* @property \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||||
* requested IP address.
|
* requested IP address.
|
||||||
*/
|
*/
|
||||||
class City extends Country
|
class City extends Country
|
||||||
|
@ -74,18 +73,18 @@ class City extends Country
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
public function __construct($raw, $languages)
|
public function __construct($raw, $locales = array('en'))
|
||||||
{
|
{
|
||||||
parent::__construct($raw, $languages);
|
parent::__construct($raw, $locales);
|
||||||
|
|
||||||
$this->city = new \GeoIP2\Record\City($this->get('city'), $languages);
|
$this->city = new \GeoIp2\Record\City($this->get('city'), $locales);
|
||||||
$this->location = new \GeoIP2\Record\Location($this->get('location'));
|
$this->location = new \GeoIp2\Record\Location($this->get('location'));
|
||||||
$this->postal = new \GeoIP2\Record\Postal($this->get('postal'));
|
$this->postal = new \GeoIp2\Record\Postal($this->get('postal'));
|
||||||
|
|
||||||
$this->createSubdivisions($raw, $languages);
|
$this->createSubdivisions($raw, $locales);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createSubdivisions($raw, $languages)
|
private function createSubdivisions($raw, $locales)
|
||||||
{
|
{
|
||||||
if (!isset($raw['subdivisions'])) {
|
if (!isset($raw['subdivisions'])) {
|
||||||
return;
|
return;
|
||||||
|
@ -94,7 +93,7 @@ class City extends Country
|
||||||
foreach ($raw['subdivisions'] as $sub) {
|
foreach ($raw['subdivisions'] as $sub) {
|
||||||
array_push(
|
array_push(
|
||||||
$this->subdivisions,
|
$this->subdivisions,
|
||||||
new \GeoIP2\Record\Subdivision($sub, $languages)
|
new \GeoIp2\Record\Subdivision($sub, $locales)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,8 +112,8 @@ class City extends Country
|
||||||
|
|
||||||
private function mostSpecificSubdivision()
|
private function mostSpecificSubdivision()
|
||||||
{
|
{
|
||||||
return empty($this->subdivisions)?
|
return empty($this->subdivisions) ?
|
||||||
new \GeoIP2\Record\Subdivision(array(), $this->languages):
|
new \GeoIp2\Record\Subdivision(array(), $this->locales) :
|
||||||
end($this->subdivisions);
|
end($this->subdivisions);
|
||||||
}
|
}
|
||||||
}
|
}
|
31
src/GeoIp2/Model/ConnectionType.php
Normal file
31
src/GeoIp2/Model/ConnectionType.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the GeoIP2 Connection-Type model.
|
||||||
|
*
|
||||||
|
* @property string $connectionType The connection type may take the following
|
||||||
|
* values: "Dialup", "Cable/DSL", "Corporate", "Cellular". Additional
|
||||||
|
* values may be added in the future.
|
||||||
|
*
|
||||||
|
* @property string $ipAddress The IP address that the data in the model is
|
||||||
|
* for.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ConnectionType extends AbstractModel
|
||||||
|
{
|
||||||
|
protected $connectionType;
|
||||||
|
protected $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
parent::__construct($raw);
|
||||||
|
|
||||||
|
$this->connectionType = $this->get('connection_type');
|
||||||
|
$this->ipAddress = $this->get('ip_address');
|
||||||
|
}
|
||||||
|
}
|
73
src/GeoIp2/Model/Country.php
Normal file
73
src/GeoIp2/Model/Country.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model class for the data returned by GeoIP2 Country web service and database.
|
||||||
|
*
|
||||||
|
* The only difference between the City and Insights model classes is which
|
||||||
|
* fields in each record may be populated. See
|
||||||
|
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Continent $continent Continent data for the
|
||||||
|
* requested IP address.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Country $country Country data for the requested
|
||||||
|
* IP address. This object represents the country where MaxMind believes the
|
||||||
|
* end user is located.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||||
|
* account.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Country $registeredCountry Registered country
|
||||||
|
* data for the requested IP address. This record represents the country
|
||||||
|
* where the ISP has registered a given IP block and may differ from the
|
||||||
|
* user's country.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||||
|
* Represented country data for the requested IP address. The represented
|
||||||
|
* country is used for things like military bases. It is only present when
|
||||||
|
* the represented country differs from the country.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||||
|
* requested IP address.
|
||||||
|
*/
|
||||||
|
class Country extends AbstractModel
|
||||||
|
{
|
||||||
|
protected $continent;
|
||||||
|
protected $country;
|
||||||
|
protected $locales;
|
||||||
|
protected $maxmind;
|
||||||
|
protected $registeredCountry;
|
||||||
|
protected $representedCountry;
|
||||||
|
protected $traits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw, $locales = array('en'))
|
||||||
|
{
|
||||||
|
parent::__construct($raw);
|
||||||
|
|
||||||
|
$this->continent = new \GeoIp2\Record\Continent(
|
||||||
|
$this->get('continent'),
|
||||||
|
$locales
|
||||||
|
);
|
||||||
|
$this->country = new \GeoIp2\Record\Country(
|
||||||
|
$this->get('country'),
|
||||||
|
$locales
|
||||||
|
);
|
||||||
|
$this->maxmind = new \GeoIp2\Record\MaxMind($this->get('maxmind'));
|
||||||
|
$this->registeredCountry = new \GeoIp2\Record\Country(
|
||||||
|
$this->get('registered_country'),
|
||||||
|
$locales
|
||||||
|
);
|
||||||
|
$this->representedCountry = new \GeoIp2\Record\RepresentedCountry(
|
||||||
|
$this->get('represented_country'),
|
||||||
|
$locales
|
||||||
|
);
|
||||||
|
$this->traits = new \GeoIp2\Record\Traits($this->get('traits'));
|
||||||
|
|
||||||
|
$this->locales = $locales;
|
||||||
|
}
|
||||||
|
}
|
31
src/GeoIp2/Model/Domain.php
Normal file
31
src/GeoIp2/Model/Domain.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the GeoIP2 Domain model.
|
||||||
|
*
|
||||||
|
* @property string $domain The second level domain associated with the IP
|
||||||
|
* address. This will be something like "example.com" or "example.co.uk",
|
||||||
|
* not "foo.example.com".
|
||||||
|
*
|
||||||
|
* @property string $ipAddress The IP address that the data in the model is
|
||||||
|
* for.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Domain extends AbstractModel
|
||||||
|
{
|
||||||
|
protected $domain;
|
||||||
|
protected $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
parent::__construct($raw);
|
||||||
|
|
||||||
|
$this->domain = $this->get('domain');
|
||||||
|
$this->ipAddress = $this->get('ip_address');
|
||||||
|
}
|
||||||
|
}
|
56
src/GeoIp2/Model/Insights.php
Normal file
56
src/GeoIp2/Model/Insights.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model class for the data returned by GeoIP2 Precision: Insights web service.
|
||||||
|
*
|
||||||
|
* The only difference between the City and Insights model classes is which
|
||||||
|
* fields in each record may be populated. See
|
||||||
|
* http://dev.maxmind.com/geoip/geoip2/web-services more details.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\City $city City data for the requested IP
|
||||||
|
* address.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Continent $continent Continent data for the
|
||||||
|
* requested IP address.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Country $country Country data for the requested
|
||||||
|
* IP address. This object represents the country where MaxMind believes the
|
||||||
|
* end user is located.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Location $location Location data for the
|
||||||
|
* requested IP address.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\MaxMind $maxmind Data related to your MaxMind
|
||||||
|
* account.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Country $registeredCountry Registered country
|
||||||
|
* data for the requested IP address. This record represents the country
|
||||||
|
* where the ISP has registered a given IP block and may differ from the
|
||||||
|
* user's country.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\RepresentedCountry $representedCountry
|
||||||
|
* Represented country data for the requested IP address. The represented
|
||||||
|
* country is used for things like military bases. It is only present when
|
||||||
|
* the represented country differs from the country.
|
||||||
|
*
|
||||||
|
* @property array $subdivisions An array of {@link \GeoIp2\Record\Subdivision}
|
||||||
|
* objects representing the country subdivisions for the requested IP
|
||||||
|
* address. The number and type of subdivisions varies by country, but a
|
||||||
|
* subdivision is typically a state, province, county, etc. Subdivisions
|
||||||
|
* are ordered from most general (largest) to most specific (smallest).
|
||||||
|
* If the response did not contain any subdivisions, this method returns
|
||||||
|
* an empty array.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Subdivision $mostSpecificSubdivision An object
|
||||||
|
* representing the most specific subdivision returned. If the response
|
||||||
|
* did not contain any subdivisions, this method returns an empty
|
||||||
|
* {@link \GeoIp2\Record\Subdivision} object.
|
||||||
|
*
|
||||||
|
* @property \GeoIp2\Record\Traits $traits Data for the traits of the
|
||||||
|
* requested IP address.
|
||||||
|
*/
|
||||||
|
class Insights extends City
|
||||||
|
{
|
||||||
|
}
|
45
src/GeoIp2/Model/Isp.php
Normal file
45
src/GeoIp2/Model/Isp.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the GeoIP2 Connection-Type model.
|
||||||
|
*
|
||||||
|
* @property integer $autonomousSystemNumber The autonomous system number
|
||||||
|
* associated with the IP address.
|
||||||
|
*
|
||||||
|
* @property string $autonomousSystemOrganization The organization associated
|
||||||
|
* with the registered autonomous system number for the IP address.
|
||||||
|
*
|
||||||
|
* @property string $isp The name of the ISP associated with the IP address.
|
||||||
|
*
|
||||||
|
* @property string $organization The name of the organization associated with
|
||||||
|
* the IP address.
|
||||||
|
*
|
||||||
|
* @property string $ipAddress The IP address that the data in the model is
|
||||||
|
* for.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Isp extends AbstractModel
|
||||||
|
{
|
||||||
|
protected $autonomousSystemNumber;
|
||||||
|
protected $autonomousSystemOrganization;
|
||||||
|
protected $isp;
|
||||||
|
protected $organization;
|
||||||
|
protected $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
parent::__construct($raw);
|
||||||
|
$this->autonomousSystemNumber = $this->get('autonomous_system_number');
|
||||||
|
$this->autonomousSystemOrganization =
|
||||||
|
$this->get('autonomous_system_organization');
|
||||||
|
$this->isp = $this->get('isp');
|
||||||
|
$this->organization = $this->get('organization');
|
||||||
|
|
||||||
|
$this->ipAddress = $this->get('ip_address');
|
||||||
|
}
|
||||||
|
}
|
20
src/GeoIp2/ProviderInterface.php
Normal file
20
src/GeoIp2/ProviderInterface.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2;
|
||||||
|
|
||||||
|
interface ProviderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ipAddress
|
||||||
|
* IPv4 or IPv6 address to lookup.
|
||||||
|
* @return \GeoIp2\Model\Country A Country model for the requested IP address.
|
||||||
|
*/
|
||||||
|
public function country($ipAddress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ipAddress
|
||||||
|
* IPv4 or IPv6 address to lookup.
|
||||||
|
* @return \GeoIp2\Model\City A City model for the requested IP address.
|
||||||
|
*/
|
||||||
|
public function city($ipAddress);
|
||||||
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
abstract class AbstractPlaceRecord extends AbstractRecord
|
abstract class AbstractPlaceRecord extends AbstractRecord
|
||||||
{
|
{
|
||||||
private $languages;
|
private $locales;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
public function __construct($record, $languages)
|
public function __construct($record, $locales = array('en'))
|
||||||
{
|
{
|
||||||
$this->languages = $languages;
|
$this->locales = $locales;
|
||||||
parent::__construct($record);
|
parent::__construct($record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,9 @@ abstract class AbstractPlaceRecord extends AbstractRecord
|
||||||
|
|
||||||
private function name()
|
private function name()
|
||||||
{
|
{
|
||||||
foreach ($this->languages as $language) {
|
foreach ($this->locales as $locale) {
|
||||||
if (isset($this->names[$language])) {
|
if (isset($this->names[$locale])) {
|
||||||
return $this->names[$language];
|
return $this->names[$locale];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
58
src/GeoIp2/Record/AbstractRecord.php
Normal file
58
src/GeoIp2/Record/AbstractRecord.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
|
abstract class AbstractRecord implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private $record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __construct($record)
|
||||||
|
{
|
||||||
|
$this->record = isset($record) ? $record : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
public function __get($attr)
|
||||||
|
{
|
||||||
|
// XXX - kind of ugly but greatly reduces boilerplate code
|
||||||
|
$key = $this->attributeToKey($attr);
|
||||||
|
|
||||||
|
if ($this->__isset($attr)) {
|
||||||
|
return $this->record[$key];
|
||||||
|
} elseif ($this->validAttribute($attr)) {
|
||||||
|
if (preg_match('/^is_/', $key)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException("Unknown attribute: $attr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($attr)
|
||||||
|
{
|
||||||
|
return $this->validAttribute($attr) &&
|
||||||
|
isset($this->record[$this->attributeToKey($attr)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function attributeToKey($attr)
|
||||||
|
{
|
||||||
|
return strtolower(preg_replace('/([A-Z])/', '_\1', $attr));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validAttribute($attr)
|
||||||
|
{
|
||||||
|
return in_array($attr, $this->validAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->record;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* City-level data associated with an IP address.
|
* City-level data associated with an IP address.
|
||||||
|
@ -9,15 +9,15 @@ namespace GeoIP2\Record;
|
||||||
*
|
*
|
||||||
* @property int $confidence A value from 0-100 indicating MaxMind's
|
* @property int $confidence A value from 0-100 indicating MaxMind's
|
||||||
* confidence that the city is correct. This attribute is only available
|
* confidence that the city is correct. This attribute is only available
|
||||||
* from the Omni end point.
|
* from the Insights end point.
|
||||||
*
|
*
|
||||||
* @property int $geonameId The GeoName ID for the city. This attribute
|
* @property int $geonameId The GeoName ID for the city. This attribute
|
||||||
* is returned by all end points.
|
* is returned by all end points.
|
||||||
*
|
*
|
||||||
* @property string $name The name of the city based on the languages list
|
* @property string $name The name of the city based on the locales list
|
||||||
* passed to the constructor. This attribute is returned by all end points.
|
* passed to the constructor. This attribute is returned by all end points.
|
||||||
*
|
*
|
||||||
* @property array $names A array map where the keys are language codes
|
* @property array $names A array map where the keys are locale codes
|
||||||
* and the values are names. This attribute is returned by all end points.
|
* and the values are names. This attribute is returned by all end points.
|
||||||
*/
|
*/
|
||||||
class City extends AbstractPlaceRecord
|
class City extends AbstractPlaceRecord
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data for the continent record associated with an IP address
|
* Contains data for the continent record associated with an IP address
|
||||||
|
@ -14,10 +14,10 @@ namespace GeoIP2\Record;
|
||||||
* is returned by all end points.
|
* is returned by all end points.
|
||||||
*
|
*
|
||||||
* @property string $name Returns the name of the continent based on the
|
* @property string $name Returns the name of the continent based on the
|
||||||
* languages list passed to the constructor. This attribute is returned by
|
* locales list passed to the constructor. This attribute is returned by
|
||||||
* all end points.
|
* all end points.
|
||||||
*
|
*
|
||||||
* @property array $names An array map where the keys are language codes
|
* @property array $names An array map where the keys are locale codes
|
||||||
* and the values are names. This attribute is returned by all end points.
|
* and the values are names. This attribute is returned by all end points.
|
||||||
*/
|
*/
|
||||||
class Continent extends AbstractPlaceRecord
|
class Continent extends AbstractPlaceRecord
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data for the country record associated with an IP address
|
* Contains data for the country record associated with an IP address
|
||||||
|
@ -18,10 +18,10 @@ namespace GeoIP2\Record;
|
||||||
* two-character ISO 3166-1 alpha code} for the country. This attribute is
|
* two-character ISO 3166-1 alpha code} for the country. This attribute is
|
||||||
* returned by all end points.
|
* returned by all end points.
|
||||||
*
|
*
|
||||||
* @property string $name The name of the country based on the languages list
|
* @property string $name The name of the country based on the locales list
|
||||||
* passed to the constructor. This attribute is returned by all end points.
|
* passed to the constructor. This attribute is returned by all end points.
|
||||||
*
|
*
|
||||||
* @property array $names An array map where the keys are language codes and
|
* @property array $names An array map where the keys are locale codes and
|
||||||
* the values are names. This attribute is returned by all end points.
|
* the values are names. This attribute is returned by all end points.
|
||||||
*/
|
*/
|
||||||
class Country extends AbstractPlaceRecord
|
class Country extends AbstractPlaceRecord
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data for the location record associated with an IP address
|
* Contains data for the location record associated with an IP address
|
||||||
|
@ -9,7 +9,7 @@ namespace GeoIP2\Record;
|
||||||
*
|
*
|
||||||
* @property int $accuracyRadius The radius in kilometers around the
|
* @property int $accuracyRadius The radius in kilometers around the
|
||||||
* specified location where the IP address is likely to be. This attribute
|
* specified location where the IP address is likely to be. This attribute
|
||||||
* is only available from the Omni end point.
|
* is only available from the Insights end point.
|
||||||
*
|
*
|
||||||
* @property float $latitude The latitude of the location as a floating
|
* @property float $latitude The latitude of the location as a floating
|
||||||
* point number. This attribute is returned by all end points except the
|
* point number. This attribute is returned by all end points except the
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data about your account.
|
* Contains data about your account.
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data for the postal record associated with an IP address
|
* Contains data for the postal record associated with an IP address
|
||||||
|
@ -14,7 +14,7 @@ namespace GeoIP2\Record;
|
||||||
*
|
*
|
||||||
* @property int $confidence A value from 0-100 indicating MaxMind's
|
* @property int $confidence A value from 0-100 indicating MaxMind's
|
||||||
* confidence that the postal code is correct. This attribute is only
|
* confidence that the postal code is correct. This attribute is only
|
||||||
* available from the Omni end point.
|
* available from the Insights end point.
|
||||||
*/
|
*/
|
||||||
class Postal extends AbstractRecord
|
class Postal extends AbstractRecord
|
||||||
{
|
{
|
|
@ -1,37 +1,32 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains data for the represented country associated with an IP address
|
* Contains data for the represented country associated with an IP address
|
||||||
*
|
*
|
||||||
* This class contains the country-level data associated with an IP address
|
* This class contains the country-level data associated with an IP address
|
||||||
* for the IP's represented country. The represented country is the country
|
* for the IP's represented country. The represented country is the country
|
||||||
* represented by something like a military base or embassy.
|
* represented by something like a military base.
|
||||||
*
|
|
||||||
* This record is returned by all the end points.
|
|
||||||
*
|
*
|
||||||
* @property int $confidence A value from 0-100 indicating MaxMind's
|
* @property int $confidence A value from 0-100 indicating MaxMind's
|
||||||
* confidence that the country is correct. This attribute is only available
|
* confidence that the country is correct. This attribute is only available
|
||||||
* from the Omni end point.
|
* from the Insights end point.
|
||||||
*
|
*
|
||||||
* @property int $geonameId The GeoName ID for the country. This attribute is
|
* @property int $geonameId The GeoName ID for the country.
|
||||||
* returned by all end points.
|
|
||||||
*
|
*
|
||||||
* @property string $isoCode The {@link http://en.wikipedia.org/wiki/ISO_3166-1
|
* @property string $isoCode The {@link http://en.wikipedia.org/wiki/ISO_3166-1
|
||||||
* two-character ISO 3166-1 alpha code} for the country. This attribute is
|
* two-character ISO 3166-1 alpha code} for the country.
|
||||||
* returned by all end points.
|
|
||||||
*
|
*
|
||||||
* @property string $name The name of the country based on the languages list
|
* @property string $name The name of the country based on the locales list
|
||||||
* passed to the constructor. This attribute is returned by all end points.
|
* passed to the constructor.
|
||||||
*
|
*
|
||||||
* @property array $names An array map where the keys are language codes and
|
* @property array $names An array map where the keys are locale codes and
|
||||||
* the values are names. This attribute is returned by all end points.
|
* the values are names.
|
||||||
*
|
*
|
||||||
* @property string $type A string indicating the type of entity that is
|
* @property string $type A string indicating the type of entity that is
|
||||||
* representing the country. Currently we only return <code>military</code>
|
* representing the country. Currently we only return <code>military</code>
|
||||||
* but this could expand to include other types such as <code>embassy</code>
|
* but this could expand to include other types in the future.
|
||||||
* in the future. Returned by all endpoints.
|
|
||||||
*/
|
*/
|
||||||
class RepresentedCountry extends Country
|
class RepresentedCountry extends Country
|
||||||
{
|
{
|
||||||
|
@ -39,7 +34,7 @@ class RepresentedCountry extends Country
|
||||||
'confidence',
|
'confidence',
|
||||||
'geonameId',
|
'geonameId',
|
||||||
'isoCode',
|
'isoCode',
|
||||||
'namespace',
|
'names',
|
||||||
'type'
|
'type'
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -10,7 +10,7 @@ namespace GeoIP2\Record;
|
||||||
*
|
*
|
||||||
* @property int $confidence This is a value from 0-100 indicating MaxMind's
|
* @property int $confidence This is a value from 0-100 indicating MaxMind's
|
||||||
* confidence that the subdivision is correct. This attribute is only
|
* confidence that the subdivision is correct. This attribute is only
|
||||||
* available from the Omni end point.
|
* available from the Insights end point.
|
||||||
*
|
*
|
||||||
* @property int $geonameId This is a GeoName ID for the subdivision. This
|
* @property int $geonameId This is a GeoName ID for the subdivision. This
|
||||||
* attribute is returned by all end points except Country.
|
* attribute is returned by all end points except Country.
|
||||||
|
@ -20,14 +20,14 @@ namespace GeoIP2\Record;
|
||||||
* http://en.wikipedia.org/wiki/ISO_3166-2 ISO 3166-2 code}. This attribute
|
* http://en.wikipedia.org/wiki/ISO_3166-2 ISO 3166-2 code}. This attribute
|
||||||
* is returned by all end points except Country.
|
* is returned by all end points except Country.
|
||||||
*
|
*
|
||||||
* @property string $name The name of the subdivision based on the languages
|
* @property string $name The name of the subdivision based on the locales
|
||||||
* list passed to the constructor. This attribute is returned by all end
|
* list passed to the constructor. This attribute is returned by all end
|
||||||
* points except Country.
|
* points except Country.
|
||||||
*
|
*
|
||||||
* @property array $names An array map where the keys are language codes and
|
* @property array $names An array map where the keys are locale codes and
|
||||||
* the values are names. This attribute is returned by all end points except
|
* the values are names. This attribute is returned by all end points except
|
||||||
* Country.
|
* Country.
|
||||||
*/
|
*/
|
||||||
class Subdivision extends AbstractPlaceRecord
|
class Subdivision extends AbstractPlaceRecord
|
||||||
{
|
{
|
||||||
/**
|
/**
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Record;
|
namespace GeoIp2\Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -11,18 +11,18 @@ namespace GeoIP2\Record;
|
||||||
* @property int $autonomousSystemNumber The {@link
|
* @property int $autonomousSystemNumber The {@link
|
||||||
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
||||||
* system number} associated with the IP address. This attribute is only
|
* system number} associated with the IP address. This attribute is only
|
||||||
* available from the City/ISP/Org and Omni end points.
|
* available from the City and Insights web service end points.
|
||||||
*
|
*
|
||||||
* @property string $autonomousSystemOrganization The organization
|
* @property string $autonomousSystemOrganization The organization
|
||||||
* associated with the registered {@link
|
* associated with the registered {@link
|
||||||
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
|
||||||
* system number} for the IP address. This attribute is only available from
|
* system number} for the IP address. This attribute is only available from
|
||||||
* the City/ISP/Org and Omni end points.
|
* the City and Insights web service end points.
|
||||||
*
|
*
|
||||||
* @property string $domain The second level domain associated with the
|
* @property string $domain The second level domain associated with the
|
||||||
* IP address. This will be something like "example.com" or "example.co.uk",
|
* IP address. This will be something like "example.com" or "example.co.uk",
|
||||||
* not "foo.example.com". This attribute is only available from the
|
* not "foo.example.com". This attribute is only available from the
|
||||||
* City/ISP/Org and Omni end points.
|
* City and Insights web service end points.
|
||||||
*
|
*
|
||||||
* @property string $ipAddress The IP address that the data in the model
|
* @property string $ipAddress The IP address that the data in the model
|
||||||
* is for. If you performed a "me" lookup against the web service, this
|
* is for. If you performed a "me" lookup against the web service, this
|
||||||
|
@ -39,13 +39,13 @@ namespace GeoIP2\Record;
|
||||||
* to a satellite Internet provider. This attribute is returned by all
|
* to a satellite Internet provider. This attribute is returned by all
|
||||||
* end points.
|
* end points.
|
||||||
*
|
*
|
||||||
* @property string $isp The name of the ISP associated the IP address.
|
* @property string $isp The name of the ISP associated with the IP address.
|
||||||
* This attribute is only available from the City/ISP/Org and Omni end
|
* This attribute is only available from the City and Insights web service end
|
||||||
* points.
|
* points.
|
||||||
*
|
*
|
||||||
* @property string $organization The name of the organization associated
|
* @property string $organization The name of the organization associated
|
||||||
* the IP address. This attribute is only available from the City/ISP/Org
|
* with the IP address. This attribute is only available from the City and
|
||||||
* and Omni end points.
|
* Insights web service end points.
|
||||||
*
|
*
|
||||||
* @property string $userType <p>The user type associated with the IP
|
* @property string $userType <p>The user type associated with the IP
|
||||||
* address. This can be one of the following values:</p>
|
* address. This can be one of the following values:</p>
|
||||||
|
@ -66,7 +66,10 @@ namespace GeoIP2\Record;
|
||||||
* <li>search_engine_spider
|
* <li>search_engine_spider
|
||||||
* <li>traveler
|
* <li>traveler
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>This attribute is only available from the Omni end point.</p>
|
* <p>
|
||||||
|
* This attribute is only available from the Insights web service end
|
||||||
|
* point.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
class Traits extends AbstractRecord
|
class Traits extends AbstractRecord
|
||||||
{
|
{
|
341
src/GeoIp2/WebService/Client.php
Normal file
341
src/GeoIp2/WebService/Client.php
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\WebService;
|
||||||
|
|
||||||
|
use GeoIp2\Exception\AddressNotFoundException;
|
||||||
|
use GeoIp2\Exception\AuthenticationException;
|
||||||
|
use GeoIp2\Exception\GeoIp2Exception;
|
||||||
|
use GeoIp2\Exception\HttpException;
|
||||||
|
use GeoIp2\Exception\InvalidRequestException;
|
||||||
|
use GeoIp2\Exception\OutOfQueriesException;
|
||||||
|
use GeoIp2\ProviderInterface;
|
||||||
|
use Guzzle\Common\Exception\RuntimeException;
|
||||||
|
use Guzzle\Http\Client as GuzzleClient;
|
||||||
|
use Guzzle\Http\Exception\ClientErrorResponseException;
|
||||||
|
use Guzzle\Http\Exception\ServerErrorResponseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a client API for all the GeoIP2 Precision web service
|
||||||
|
* end points. The end points are Country, City, and Insights. Each end point
|
||||||
|
* returns a different set of data about an IP address, with Country returning
|
||||||
|
* the least data and Insights the most.
|
||||||
|
*
|
||||||
|
* Each web service end point is represented by a different model class, and
|
||||||
|
* these model classes in turn contain multiple Record classes. The record
|
||||||
|
* classes have attributes which contain data about the IP address.
|
||||||
|
*
|
||||||
|
* If the web service does not return a particular piece of data for an IP
|
||||||
|
* address, the associated attribute is not populated.
|
||||||
|
*
|
||||||
|
* The web service may not return any information for an entire record, in
|
||||||
|
* which case all of the attributes for that record class will be empty.
|
||||||
|
*
|
||||||
|
* ## Usage ##
|
||||||
|
*
|
||||||
|
* The basic API for this class is the same for all of the web service end
|
||||||
|
* points. First you create a web service object with your MaxMind `$userId`
|
||||||
|
* and `$licenseKey`, then you call the method corresponding to a specific end
|
||||||
|
* point, passing it the IP address you want to look up.
|
||||||
|
*
|
||||||
|
* If the request succeeds, the method call will return a model class for
|
||||||
|
* the end point you called. This model in turn contains multiple record
|
||||||
|
* classes, each of which represents part of the data returned by the web
|
||||||
|
* service.
|
||||||
|
*
|
||||||
|
* If the request fails, the client class throws an exception.
|
||||||
|
*/
|
||||||
|
class Client implements ProviderInterface
|
||||||
|
{
|
||||||
|
private $userId;
|
||||||
|
private $licenseKey;
|
||||||
|
private $locales;
|
||||||
|
private $host;
|
||||||
|
private $guzzleClient;
|
||||||
|
private $timeout;
|
||||||
|
private $connectTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param int $userId Your MaxMind user ID
|
||||||
|
* @param string $licenseKey Your MaxMind license key
|
||||||
|
* @param array $locales List of locale codes to use in name property
|
||||||
|
* from most preferred to least preferred.
|
||||||
|
* @param string $host Optional host parameter
|
||||||
|
* @param object $guzzleClient Optional Guzzle client to use (to facilitate
|
||||||
|
* unit testing).
|
||||||
|
* @param string $timeout Total transaction timeout in seconds
|
||||||
|
* @param string $connectTimeout Initial connection timeout in seconds
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
$userId,
|
||||||
|
$licenseKey,
|
||||||
|
$locales = array('en'),
|
||||||
|
$host = 'geoip.maxmind.com',
|
||||||
|
$guzzleClient = null,
|
||||||
|
$timeout = null,
|
||||||
|
$connectTimeout = null
|
||||||
|
) {
|
||||||
|
$this->userId = $userId;
|
||||||
|
$this->licenseKey = $licenseKey;
|
||||||
|
$this->locales = $locales;
|
||||||
|
$this->host = $host;
|
||||||
|
// To enable unit testing
|
||||||
|
$this->guzzleClient = $guzzleClient;
|
||||||
|
$this->timeout = $timeout;
|
||||||
|
$this->connectTimeout = $connectTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method calls the GeoIP2 Precision: City endpoint.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||||
|
* address is provided, the address that the web service is called
|
||||||
|
* from will be used.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\City
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||||
|
* provided is not in our database (e.g., a private address).
|
||||||
|
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||||
|
* with the user ID or license key that you provided.
|
||||||
|
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||||
|
* of queries.
|
||||||
|
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||||
|
* received by the web service but is invalid for some other reason.
|
||||||
|
* This may indicate an issue with this API. Please report the error to
|
||||||
|
* MaxMind.
|
||||||
|
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||||
|
* code or message was returned. This could indicate a problem with the
|
||||||
|
* connection between your server and the web service or that the web
|
||||||
|
* service returned an invalid document or 500 error code.
|
||||||
|
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||||
|
* class to the above exceptions. It will be thrown directly if a 200
|
||||||
|
* status code is returned but the body is invalid.
|
||||||
|
*/
|
||||||
|
public function city($ipAddress = 'me')
|
||||||
|
{
|
||||||
|
return $this->responseFor('city', 'City', $ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method calls the GeoIP2 Precision: Country endpoint.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||||
|
* address is provided, the address that the web service is called
|
||||||
|
* from will be used.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\Country
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||||
|
* provided is not in our database (e.g., a private address).
|
||||||
|
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||||
|
* with the user ID or license key that you provided.
|
||||||
|
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||||
|
* of queries.
|
||||||
|
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||||
|
* received by the web service but is invalid for some other reason.
|
||||||
|
* This may indicate an issue with this API. Please report the error to
|
||||||
|
* MaxMind.
|
||||||
|
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||||
|
* code or message was returned. This could indicate a problem with the
|
||||||
|
* connection between your server and the web service or that the web
|
||||||
|
* service returned an invalid document or 500 error code.
|
||||||
|
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||||
|
* class to the above exceptions. It will be thrown directly if a 200
|
||||||
|
* status code is returned but the body is invalid.
|
||||||
|
*/
|
||||||
|
public function country($ipAddress = 'me')
|
||||||
|
{
|
||||||
|
return $this->responseFor('country', 'Country', $ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method calls the GeoIP2 Precision: Insights endpoint.
|
||||||
|
*
|
||||||
|
* @param string $ipAddress IPv4 or IPv6 address as a string. If no
|
||||||
|
* address is provided, the address that the web service is called
|
||||||
|
* from will be used.
|
||||||
|
*
|
||||||
|
* @return \GeoIp2\Model\Insights
|
||||||
|
*
|
||||||
|
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
|
||||||
|
* provided is not in our database (e.g., a private address).
|
||||||
|
* @throws \GeoIp2\Exception\AuthenticationException if there is a problem
|
||||||
|
* with the user ID or license key that you provided.
|
||||||
|
* @throws \GeoIp2\Exception\OutOfQueriesException if your account is out
|
||||||
|
* of queries.
|
||||||
|
* @throws \GeoIp2\Exception\InvalidRequestException} if your request was
|
||||||
|
* received by the web service but is invalid for some other reason.
|
||||||
|
* This may indicate an issue with this API. Please report the error to
|
||||||
|
* MaxMind.
|
||||||
|
* @throws \GeoIp2\Exception\HttpException if an unexpected HTTP error
|
||||||
|
* code or message was returned. This could indicate a problem with the
|
||||||
|
* connection between your server and the web service or that the web
|
||||||
|
* service returned an invalid document or 500 error code.
|
||||||
|
* @throws \GeoIp2\Exception\GeoIp2Exception This serves as the parent
|
||||||
|
* class to the above exceptions. It will be thrown directly if a 200
|
||||||
|
* status code is returned but the body is invalid.
|
||||||
|
*/
|
||||||
|
public function insights($ipAddress = 'me')
|
||||||
|
{
|
||||||
|
return $this->responseFor('insights', 'Insights', $ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function responseFor($endpoint, $class, $ipAddress)
|
||||||
|
{
|
||||||
|
$uri = implode('/', array($this->baseUri(), $endpoint, $ipAddress));
|
||||||
|
|
||||||
|
$client = $this->guzzleClient ?
|
||||||
|
$this->guzzleClient : new GuzzleClient();
|
||||||
|
$options = array();
|
||||||
|
if ($this->timeout !== null) {
|
||||||
|
$options['timeout'] = $this->timeout;
|
||||||
|
}
|
||||||
|
if ($this->connectTimeout !== null) {
|
||||||
|
$options['connect_timeout'] = $this->connectTimeout;
|
||||||
|
}
|
||||||
|
$request = $client->get($uri, array('Accept' => 'application/json'), $options);
|
||||||
|
$request->setAuth($this->userId, $this->licenseKey);
|
||||||
|
$this->setUserAgent($request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $request->send();
|
||||||
|
} catch (ClientErrorResponseException $e) {
|
||||||
|
$this->handle4xx($e->getResponse(), $uri);
|
||||||
|
} catch (ServerErrorResponseException $e) {
|
||||||
|
$this->handle5xx($e->getResponse(), $uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response && $response->isSuccessful()) {
|
||||||
|
$body = $this->handleSuccess($response, $uri);
|
||||||
|
$class = "GeoIp2\\Model\\" . $class;
|
||||||
|
return new $class($body, $this->locales);
|
||||||
|
} else {
|
||||||
|
$this->handleNon200($response, $uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleSuccess($response, $uri)
|
||||||
|
{
|
||||||
|
if ($response->getContentLength() == 0) {
|
||||||
|
throw new GeoIp2Exception(
|
||||||
|
"Received a 200 response for $uri but did not " .
|
||||||
|
"receive a HTTP body."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $response->json();
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
throw new GeoIp2Exception(
|
||||||
|
"Received a 200 response for $uri but could not decode " .
|
||||||
|
"the response as JSON: " . $e->getMessage()
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handle4xx($response, $uri)
|
||||||
|
{
|
||||||
|
$status = $response->getStatusCode();
|
||||||
|
|
||||||
|
if ($response->getContentLength() > 0) {
|
||||||
|
if (strstr($response->getContentType(), 'json')) {
|
||||||
|
try {
|
||||||
|
$body = $response->json();
|
||||||
|
if (!isset($body['code']) || !isset($body['error'])) {
|
||||||
|
throw new GeoIp2Exception(
|
||||||
|
'Response contains JSON but it does not specify ' .
|
||||||
|
'code or error keys: ' . $response->getBody()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
throw new HttpException(
|
||||||
|
"Received a $status error for $uri but it did not " .
|
||||||
|
"include the expected JSON body: " .
|
||||||
|
$e->getMessage(),
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new HttpException(
|
||||||
|
"Received a $status error for $uri with the " .
|
||||||
|
"following body: " . $response->getBody(),
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new HttpException(
|
||||||
|
"Received a $status error for $uri with no body",
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->handleWebServiceError(
|
||||||
|
$body['error'],
|
||||||
|
$body['code'],
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleWebServiceError($message, $code, $status, $uri)
|
||||||
|
{
|
||||||
|
switch ($code) {
|
||||||
|
case 'IP_ADDRESS_NOT_FOUND':
|
||||||
|
case 'IP_ADDRESS_RESERVED':
|
||||||
|
throw new AddressNotFoundException($message);
|
||||||
|
case 'AUTHORIZATION_INVALID':
|
||||||
|
case 'LICENSE_KEY_REQUIRED':
|
||||||
|
case 'USER_ID_REQUIRED':
|
||||||
|
throw new AuthenticationException($message);
|
||||||
|
case 'OUT_OF_QUERIES':
|
||||||
|
throw new OutOfQueriesException($message);
|
||||||
|
default:
|
||||||
|
throw new InvalidRequestException(
|
||||||
|
$message,
|
||||||
|
$code,
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handle5xx($response, $uri)
|
||||||
|
{
|
||||||
|
$status = $response->getStatusCode();
|
||||||
|
|
||||||
|
throw new HttpException(
|
||||||
|
"Received a server error ($status) for $uri",
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleNon200($response, $uri)
|
||||||
|
{
|
||||||
|
$status = $response->getStatusCode();
|
||||||
|
|
||||||
|
throw new HttpException(
|
||||||
|
"Received a very surprising HTTP status " .
|
||||||
|
"($status) for $uri",
|
||||||
|
$status,
|
||||||
|
$uri
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setUserAgent($request)
|
||||||
|
{
|
||||||
|
$userAgent = $request->getHeader('User-Agent');
|
||||||
|
$userAgent = "GeoIP2 PHP API ($userAgent)";
|
||||||
|
$request->setHeader('User-Agent', $userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function baseUri()
|
||||||
|
{
|
||||||
|
return 'https://' . $this->host . '/geoip/v2.1';
|
||||||
|
}
|
||||||
|
}
|
154
tests/GeoIp2/Test/Database/ReaderTest.php
Normal file
154
tests/GeoIp2/Test/Database/ReaderTest.php
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GeoIp2\Test\WebService;
|
||||||
|
|
||||||
|
use GeoIp2\Database\Reader;
|
||||||
|
|
||||||
|
class ReaderTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testDefaultLocale()
|
||||||
|
{
|
||||||
|
foreach (array('City', 'Country') as $type) {
|
||||||
|
$reader = new Reader("maxmind-db/test-data/GeoIP2-$type-Test.mmdb");
|
||||||
|
$method = lcfirst($type);
|
||||||
|
$record = $reader->$method('81.2.69.160');
|
||||||
|
$this->assertEquals('United Kingdom', $record->country->name);
|
||||||
|
}
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLocaleList()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (array('City', 'Country') as $type) {
|
||||||
|
$reader = new Reader(
|
||||||
|
"maxmind-db/test-data/GeoIP2-$type-Test.mmdb",
|
||||||
|
array('xx', 'ru', 'pt-BR', 'es', 'en')
|
||||||
|
);
|
||||||
|
$method = lcfirst($type);
|
||||||
|
|
||||||
|
$record = $reader->$method('81.2.69.160');
|
||||||
|
$this->assertEquals('Великобритания', $record->country->name);
|
||||||
|
}
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasIpAddress()
|
||||||
|
{
|
||||||
|
foreach (array('City', 'Country') as $type) {
|
||||||
|
$reader = new Reader("maxmind-db/test-data/GeoIP2-$type-Test.mmdb");
|
||||||
|
$method = lcfirst($type);
|
||||||
|
$record = $reader->$method('81.2.69.160');
|
||||||
|
$this->assertEquals('81.2.69.160', $record->traits->ipAddress);
|
||||||
|
}
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AddressNotFoundException
|
||||||
|
* @expectedExceptionMessage The address 10.10.10.10 is not in the database.
|
||||||
|
*/
|
||||||
|
public function testUnknownAddress()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
$reader->city('10.10.10.10');
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException BadMethodCallException
|
||||||
|
* @expectedExceptionMessage The country method cannot be used to open a GeoIP2-City database
|
||||||
|
*/
|
||||||
|
public function testIncorrectDatabase()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
$reader->country('10.10.10.10');
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException BadMethodCallException
|
||||||
|
* @expectedExceptionMessage The domain method cannot be used to open a GeoIP2-City database
|
||||||
|
*/
|
||||||
|
public function testIncorrectDatabaseFlat()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
$reader->domain('10.10.10.10');
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage is not a valid IP address
|
||||||
|
*/
|
||||||
|
public function testInvalidAddress()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
$reader->city('invalid');
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAnonymousIp()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-Anonymous-IP-Test.mmdb');
|
||||||
|
$ipAddress = '1.2.0.1';
|
||||||
|
|
||||||
|
$record = $reader->anonymousIp($ipAddress);
|
||||||
|
$this->assertSame(true, $record->isAnonymous);
|
||||||
|
$this->assertSame(true, $record->isAnonymousVpn);
|
||||||
|
$this->assertSame(false, $record->isHostingProvider);
|
||||||
|
$this->assertSame(false, $record->isPublicProxy);
|
||||||
|
$this->assertSame(false, $record->isTorExitNode);
|
||||||
|
$this->assertEquals($ipAddress, $record->ipAddress);
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConnectionType()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-Connection-Type-Test.mmdb');
|
||||||
|
$ipAddress = '1.0.1.0';
|
||||||
|
|
||||||
|
$record = $reader->connectionType($ipAddress);
|
||||||
|
$this->assertEquals('Cable/DSL', $record->connectionType);
|
||||||
|
$this->assertEquals($ipAddress, $record->ipAddress);
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDomain()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-Domain-Test.mmdb');
|
||||||
|
|
||||||
|
$ipAddress = '1.2.0.0';
|
||||||
|
$record = $reader->domain($ipAddress);
|
||||||
|
$this->assertEquals('maxmind.com', $record->domain);
|
||||||
|
$this->assertEquals($ipAddress, $record->ipAddress);
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsp()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-ISP-Test.mmdb');
|
||||||
|
|
||||||
|
$ipAddress = '1.128.0.0';
|
||||||
|
$record = $reader->isp($ipAddress);
|
||||||
|
$this->assertEquals(1221, $record->autonomousSystemNumber);
|
||||||
|
$this->assertEquals(
|
||||||
|
'Telstra Pty Ltd',
|
||||||
|
$record->autonomousSystemOrganization
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('Telstra Internet', $record->isp);
|
||||||
|
$this->assertEquals('Telstra Internet', $record->organization);
|
||||||
|
|
||||||
|
$this->assertEquals($ipAddress, $record->ipAddress);
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMetadata()
|
||||||
|
{
|
||||||
|
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
|
||||||
|
$this->assertEquals('GeoIP2-City', $reader->metadata()->databaseType);
|
||||||
|
|
||||||
|
$reader->close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Test\Model;
|
namespace GeoIp2\Test\Model;
|
||||||
|
|
||||||
use GeoIP2\Model\Country;
|
use GeoIp2\Model\Country;
|
||||||
|
|
||||||
class CountryTest extends \PHPUnit_Framework_TestCase
|
class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -11,17 +11,17 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
'continent' => array(
|
'continent' => array(
|
||||||
'code' => 'NA',
|
'code' => 'NA',
|
||||||
'geoname_id' => 42,
|
'geoname_id' => 42,
|
||||||
'names' => array( 'en' => 'North America' ),
|
'names' => array('en' => 'North America'),
|
||||||
),
|
),
|
||||||
'country' => array(
|
'country' => array(
|
||||||
'geoname_id' => 1,
|
'geoname_id' => 1,
|
||||||
'iso_code' => 'US',
|
'iso_code' => 'US',
|
||||||
'names' => array( 'en' => 'United States of America' ),
|
'names' => array('en' => 'United States of America'),
|
||||||
),
|
),
|
||||||
'registered_country' => array(
|
'registered_country' => array(
|
||||||
'geoname_id' => 2,
|
'geoname_id' => 2,
|
||||||
'iso_code' => 'CA',
|
'iso_code' => 'CA',
|
||||||
'names' => array( 'en' => 'Canada' ),
|
'names' => array('en' => 'Canada'),
|
||||||
),
|
),
|
||||||
'traits' => array(
|
'traits' => array(
|
||||||
'ip_address' => '1.2.3.4',
|
'ip_address' => '1.2.3.4',
|
||||||
|
@ -30,36 +30,36 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
private $model;
|
private $model;
|
||||||
|
|
||||||
public function setUp ()
|
public function setUp()
|
||||||
{
|
{
|
||||||
$this->model = new Country($this->raw, array('en'));
|
$this->model = new Country($this->raw, array('en'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testObjects ()
|
public function testObjects()
|
||||||
{
|
{
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Model\Country',
|
'GeoIp2\Model\Country',
|
||||||
$this->model,
|
$this->model,
|
||||||
'minimal GeoIP2::Model::Country object'
|
'minimal GeoIp2::Model::Country object'
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Continent',
|
'GeoIp2\Record\Continent',
|
||||||
$this->model->continent
|
$this->model->continent
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$this->model->country
|
$this->model->country
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$this->model->registeredCountry
|
$this->model->registeredCountry
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\RepresentedCountry',
|
'GeoIp2\Record\RepresentedCountry',
|
||||||
$this->model->representedCountry
|
$this->model->representedCountry
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Traits',
|
'GeoIp2\Record\Traits',
|
||||||
$this->model->traits
|
$this->model->traits
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array( 'en' => 'North America' ),
|
array('en' => 'North America'),
|
||||||
$this->model->continent->names,
|
$this->model->continent->names,
|
||||||
'continent names'
|
'continent names'
|
||||||
);
|
);
|
||||||
|
@ -104,7 +104,7 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array( 'en' => 'United States of America' ),
|
array('en' => 'United States of America'),
|
||||||
$this->model->country->names,
|
$this->model->country->names,
|
||||||
'country name'
|
'country name'
|
||||||
);
|
);
|
||||||
|
@ -134,7 +134,7 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array( 'en' => 'Canada' ),
|
array('en' => 'Canada'),
|
||||||
$this->model->registeredCountry->names,
|
$this->model->registeredCountry->names,
|
||||||
'registered_country names'
|
'registered_country names'
|
||||||
);
|
);
|
||||||
|
@ -145,7 +145,7 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
'registered_country name is Canada'
|
'registered_country name is Canada'
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach (array( 'isAnonymousProxy', 'isSatelliteProvider' ) as $meth) {
|
foreach (array('isAnonymousProxy', 'isSatelliteProvider') as $meth) {
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
0,
|
0,
|
||||||
$this->model->traits->$meth,
|
$this->model->traits->$meth,
|
||||||
|
@ -159,4 +159,68 @@ class CountryTest extends \PHPUnit_Framework_TestCase
|
||||||
'raw method returns raw input'
|
'raw method returns raw input'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testJsonSerialize()
|
||||||
|
{
|
||||||
|
$this->assertEquals(
|
||||||
|
$this->raw,
|
||||||
|
$this->model->jsonSerialize(),
|
||||||
|
'jsonSerialize returns initial array'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$this->raw['country'],
|
||||||
|
$this->model->country->jsonSerialize(),
|
||||||
|
'jsonSerialize returns initial array for the record'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (version_compare(PHP_VERSION, '5.4.0', '<')) {
|
||||||
|
$this->markTestSkipped('Requires PHP 5.4+.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
json_encode($this->raw),
|
||||||
|
json_encode($this->model),
|
||||||
|
'json_encode can be called on the model object directly'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
json_encode($this->raw['country']),
|
||||||
|
json_encode($this->model->country),
|
||||||
|
'json_encode can be called on the record object directly'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsSet()
|
||||||
|
{
|
||||||
|
$this->assertTrue(isset($this->model->traits), 'traits is set');
|
||||||
|
$this->assertFalse(isset($this->model->unknown), 'unknown is not set');
|
||||||
|
|
||||||
|
$this->assertTrue(
|
||||||
|
isset($this->model->traits->ipAddress),
|
||||||
|
'ip_address is set'
|
||||||
|
);
|
||||||
|
$this->assertFalse(
|
||||||
|
isset($this->model->traits->unknown),
|
||||||
|
'unknown trait is not set'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException RuntimeException
|
||||||
|
* @expectedExceptionMessage Unknown attribute
|
||||||
|
*/
|
||||||
|
public function testUnknownRecord()
|
||||||
|
{
|
||||||
|
$this->model->unknownRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException RuntimeException
|
||||||
|
* @expectedExceptionMessage Unknown attribute
|
||||||
|
*/
|
||||||
|
public function testUnknownTrait()
|
||||||
|
{
|
||||||
|
$this->model->traits->unknown;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Test\Model;
|
namespace GeoIp2\Test\Model;
|
||||||
|
|
||||||
use GeoIP2\Model\Omni;
|
use GeoIp2\Model\Insights;
|
||||||
|
|
||||||
class OmniTest extends \PHPUnit_Framework_TestCase
|
class InsightsTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
public function testFull()
|
public function testFull()
|
||||||
|
@ -14,18 +14,18 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
'city' => array(
|
'city' => array(
|
||||||
'confidence' => 76,
|
'confidence' => 76,
|
||||||
'geoname_id' => 9876,
|
'geoname_id' => 9876,
|
||||||
'names' => array( 'en' => 'Minneapolis' ),
|
'names' => array('en' => 'Minneapolis'),
|
||||||
),
|
),
|
||||||
'continent' => array(
|
'continent' => array(
|
||||||
'code' => 'NA',
|
'code' => 'NA',
|
||||||
'geoname_id' => 42,
|
'geoname_id' => 42,
|
||||||
'names' => array( 'en' => 'North America' ),
|
'names' => array('en' => 'North America'),
|
||||||
),
|
),
|
||||||
'country' => array(
|
'country' => array(
|
||||||
'confidence' => 99,
|
'confidence' => 99,
|
||||||
'geoname_id' => 1,
|
'geoname_id' => 1,
|
||||||
'iso_code' => 'US',
|
'iso_code' => 'US',
|
||||||
'names' => array( 'en' => 'United States of America' ),
|
'names' => array('en' => 'United States of America'),
|
||||||
),
|
),
|
||||||
'location' => array(
|
'location' => array(
|
||||||
'accuracy_radius' => 1500,
|
'accuracy_radius' => 1500,
|
||||||
|
@ -42,19 +42,19 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
'registered_country' => array(
|
'registered_country' => array(
|
||||||
'geoname_id' => 2,
|
'geoname_id' => 2,
|
||||||
'iso_code' => 'CA',
|
'iso_code' => 'CA',
|
||||||
'names' => array( 'en' => 'Canada' ),
|
'names' => array('en' => 'Canada'),
|
||||||
),
|
),
|
||||||
'represented_country' => array(
|
'represented_country' => array(
|
||||||
'geoname_id' => 3,
|
'geoname_id' => 3,
|
||||||
'iso_code' => 'GB',
|
'iso_code' => 'GB',
|
||||||
'names' => array( 'en' => 'United Kingdom' ),
|
'names' => array('en' => 'United Kingdom'),
|
||||||
),
|
),
|
||||||
'subdivisions' => array(
|
'subdivisions' => array(
|
||||||
array(
|
array(
|
||||||
'confidence' => 88,
|
'confidence' => 88,
|
||||||
'geoname_id' => 574635,
|
'geoname_id' => 574635,
|
||||||
'iso_code' => 'MN',
|
'iso_code' => 'MN',
|
||||||
'names' => array( 'en' => 'Minnesota' ),
|
'names' => array('en' => 'Minnesota'),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'traits' => array(
|
'traits' => array(
|
||||||
|
@ -62,74 +62,86 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
'autonomous_system_organization' => 'AS Organization',
|
'autonomous_system_organization' => 'AS Organization',
|
||||||
'domain' => 'example.com',
|
'domain' => 'example.com',
|
||||||
'ip_address' => '1.2.3.4',
|
'ip_address' => '1.2.3.4',
|
||||||
'is_satellite_provider' => 1,
|
'is_satellite_provider' => true,
|
||||||
'isp' => 'Comcast',
|
'isp' => 'Comcast',
|
||||||
'organization' => 'Blorg',
|
'organization' => 'Blorg',
|
||||||
'user_type' => 'college',
|
'user_type' => 'college',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$model = new Omni($raw, array('en'));
|
$model = new Insights($raw, array('en'));
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Model\Omni',
|
'GeoIp2\Model\Insights',
|
||||||
$model,
|
$model,
|
||||||
'GeoIP2\Model\Omni object'
|
'GeoIp2\Model\Insights object'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\City',
|
'GeoIp2\Record\City',
|
||||||
$model->city,
|
$model->city,
|
||||||
'$model->city'
|
'$model->city'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Continent',
|
'GeoIp2\Record\Continent',
|
||||||
$model->continent,
|
$model->continent,
|
||||||
'$model->continent'
|
'$model->continent'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$model->country,
|
$model->country,
|
||||||
'$model->country'
|
'$model->country'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Location',
|
'GeoIp2\Record\Location',
|
||||||
$model->location,
|
$model->location,
|
||||||
'$model->location'
|
'$model->location'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$model->registeredCountry,
|
$model->registeredCountry,
|
||||||
'$model->registeredCountry'
|
'$model->registeredCountry'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\RepresentedCountry',
|
'GeoIp2\Record\RepresentedCountry',
|
||||||
$model->representedCountry,
|
$model->representedCountry,
|
||||||
'$model->representedCountry'
|
'$model->representedCountry'
|
||||||
);
|
);
|
||||||
|
|
||||||
$subdivisions = $model->subdivisions;
|
$subdivisions = $model->subdivisions;
|
||||||
foreach ($subdivisions as $subdiv) {
|
foreach ($subdivisions as $subdiv) {
|
||||||
$this->assertInstanceOf('GeoIP2\Record\Subdivision', $subdiv);
|
$this->assertInstanceOf('GeoIp2\Record\Subdivision', $subdiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Subdivision',
|
'GeoIp2\Record\Subdivision',
|
||||||
$model->mostSpecificSubdivision,
|
$model->mostSpecificSubdivision,
|
||||||
'$model->mostSpecificSubdivision'
|
'$model->mostSpecificSubdivision'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Traits',
|
'GeoIp2\Record\Traits',
|
||||||
$model->traits,
|
$model->traits,
|
||||||
'$model->traits'
|
'$model->traits'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
true,
|
||||||
|
$model->traits->isSatelliteProvider,
|
||||||
|
'$model->traits->isSatelliteProvider is true'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
false,
|
||||||
|
$model->traits->isAnonymousProxy,
|
||||||
|
'$model->traits->isAnonymousProxy is false'
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
22,
|
22,
|
||||||
$model->maxmind->queriesRemaining,
|
$model->maxmind->queriesRemaining,
|
||||||
|
@ -145,48 +157,48 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testEmptyObjects()
|
public function testEmptyObjects()
|
||||||
{
|
{
|
||||||
$raw = array( 'traits' => array( 'ip_address' => '5.6.7.8' ) );
|
$raw = array('traits' => array('ip_address' => '5.6.7.8'));
|
||||||
|
|
||||||
$model = new Omni($raw, array('en'));
|
$model = new Insights($raw, array('en'));
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Model\Omni',
|
'GeoIp2\Model\Insights',
|
||||||
$model,
|
$model,
|
||||||
'GeoIP2\Model\Omni object with no data except traits.ipAddress'
|
'GeoIp2\Model\Insights object with no data except traits.ipAddress'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\City',
|
'GeoIp2\Record\City',
|
||||||
$model->city,
|
$model->city,
|
||||||
'$model->city'
|
'$model->city'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Continent',
|
'GeoIp2\Record\Continent',
|
||||||
$model->continent,
|
$model->continent,
|
||||||
'$model->continent'
|
'$model->continent'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$model->country,
|
$model->country,
|
||||||
'$model->country'
|
'$model->country'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Location',
|
'GeoIp2\Record\Location',
|
||||||
$model->location,
|
$model->location,
|
||||||
'$model->location'
|
'$model->location'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Country',
|
'GeoIp2\Record\Country',
|
||||||
$model->registeredCountry,
|
$model->registeredCountry,
|
||||||
'$model->registeredCountry'
|
'$model->registeredCountry'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\RepresentedCountry',
|
'GeoIp2\Record\RepresentedCountry',
|
||||||
$model->representedCountry,
|
$model->representedCountry,
|
||||||
'$model->representedCountry'
|
'$model->representedCountry'
|
||||||
);
|
);
|
||||||
|
@ -198,13 +210,13 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Subdivision',
|
'GeoIp2\Record\Subdivision',
|
||||||
$model->mostSpecificSubdivision,
|
$model->mostSpecificSubdivision,
|
||||||
'$model->mostSpecificSubdivision'
|
'$model->mostSpecificSubdivision'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Record\Traits',
|
'GeoIp2\Record\Traits',
|
||||||
$model->traits,
|
$model->traits,
|
||||||
'$model->traits'
|
'$model->traits'
|
||||||
);
|
);
|
||||||
|
@ -220,23 +232,23 @@ class OmniTest extends \PHPUnit_Framework_TestCase
|
||||||
public function testUnknown()
|
public function testUnknown()
|
||||||
{
|
{
|
||||||
$raw = array(
|
$raw = array(
|
||||||
'new_top_level' => array( 'foo' => 42 ),
|
'new_top_level' => array('foo' => 42),
|
||||||
'city' => array(
|
'city' => array(
|
||||||
'confidence' => 76,
|
'confidence' => 76,
|
||||||
'geoname_id_id' => 9876,
|
'geoname_id_id' => 9876,
|
||||||
'names' => array( 'en' => 'Minneapolis' ),
|
'names' => array('en' => 'Minneapolis'),
|
||||||
'population' => 50,
|
'population' => 50,
|
||||||
),
|
),
|
||||||
'traits' => array( 'ip_address' => '5.6.7.8' )
|
'traits' => array('ip_address' => '5.6.7.8')
|
||||||
);
|
);
|
||||||
|
|
||||||
// checking whether there are exceptions with unknown keys
|
// checking whether there are exceptions with unknown keys
|
||||||
$model = new Omni($raw, array('en'));
|
$model = new Insights($raw, array('en'));
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Model\Omni',
|
'GeoIp2\Model\Insights',
|
||||||
$model,
|
$model,
|
||||||
'no exception when Omni model gets raw data with unknown keys'
|
'no exception when Insights model gets raw data with unknown keys'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Test\Model;
|
namespace GeoIp2\Test\Model;
|
||||||
|
|
||||||
use GeoIP2\Model\Country;
|
use GeoIp2\Model\Country;
|
||||||
|
|
||||||
class NameTest extends \PHPUnit_Framework_TestCase
|
class NameTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testFallback()
|
public function testFallback()
|
||||||
{
|
{
|
||||||
$model = new Country($this->raw, array( 'ru', 'zh-CN', 'en' ));
|
$model = new Country($this->raw, array('ru', 'zh-CN', 'en'));
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'北美洲',
|
'北美洲',
|
||||||
|
@ -46,7 +46,8 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTwoFallbacks() {
|
public function testTwoFallbacks()
|
||||||
|
{
|
||||||
$model = new Country($this->raw, array('ru', 'ja'));
|
$model = new Country($this->raw, array('ru', 'ja'));
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace GeoIP2\Test\WebService;
|
namespace GeoIp2\Test\WebService;
|
||||||
|
|
||||||
use GeoIP2\WebService\Client;
|
use GeoIp2\WebService\Client;
|
||||||
use Guzzle\Http\Client as GuzzleClient;
|
use Guzzle\Http\Client as GuzzleClient;
|
||||||
use Guzzle\Http\Message\Response;
|
use Guzzle\Http\Message\Response;
|
||||||
use Guzzle\Plugin\Mock\MockPlugin;
|
use Guzzle\Plugin\Mock\MockPlugin;
|
||||||
|
@ -15,12 +15,12 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
'continent' => array(
|
'continent' => array(
|
||||||
'code' => 'NA',
|
'code' => 'NA',
|
||||||
'geoname_id' => 42,
|
'geoname_id' => 42,
|
||||||
'names' => array( 'en' => 'North America' ),
|
'names' => array('en' => 'North America'),
|
||||||
),
|
),
|
||||||
'country' => array(
|
'country' => array(
|
||||||
'geoname_id' => 1,
|
'geoname_id' => 1,
|
||||||
'iso_code' => 'US',
|
'iso_code' => 'US',
|
||||||
'names' => array( 'en' => 'United States of America' ),
|
'names' => array('en' => 'United States of America'),
|
||||||
),
|
),
|
||||||
'maxmind' => array('queries_remaining' => 11),
|
'maxmind' => array('queries_remaining' => 11),
|
||||||
'traits' => array(
|
'traits' => array(
|
||||||
|
@ -44,7 +44,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
),
|
),
|
||||||
'1.2.3.5' => $this->response('country', 200),
|
'1.2.3.5' => $this->response('country', 200),
|
||||||
'2.2.3.5' => $this->response('country', 200, 'bad body'),
|
'2.2.3.5' => $this->response('country', 200, 'bad body'),
|
||||||
'1.2.3.6'=> $this->response(
|
'1.2.3.6' => $this->response(
|
||||||
'error',
|
'error',
|
||||||
400,
|
400,
|
||||||
array(
|
array(
|
||||||
|
@ -59,7 +59,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
'1.2.3.8' => $this->response(
|
'1.2.3.8' => $this->response(
|
||||||
'error',
|
'error',
|
||||||
400,
|
400,
|
||||||
array( 'weird' => 42 )
|
array('weird' => 42)
|
||||||
),
|
),
|
||||||
'1.2.3.9' => $this->response(
|
'1.2.3.9' => $this->response(
|
||||||
'error',
|
'error',
|
||||||
|
@ -82,6 +82,54 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
null,
|
null,
|
||||||
'text/plain'
|
'text/plain'
|
||||||
),
|
),
|
||||||
|
'1.2.3.13' => $this->response(
|
||||||
|
'error',
|
||||||
|
404,
|
||||||
|
array(
|
||||||
|
'code' => 'IP_ADDRESS_NOT_FOUND',
|
||||||
|
'error' => 'The address "1.2.3.13" is not in our database.'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'1.2.3.14' => $this->response(
|
||||||
|
'error',
|
||||||
|
400,
|
||||||
|
array(
|
||||||
|
'code' => 'IP_ADDRESS_RESERVED',
|
||||||
|
'error' => 'The address "1.2.3.14" is a private address.'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'1.2.3.15' => $this->response(
|
||||||
|
'error',
|
||||||
|
401,
|
||||||
|
array(
|
||||||
|
'code' => 'AUTHORIZATION_INVALID',
|
||||||
|
'error' => 'A user ID and license key are required to use this service'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'1.2.3.16' => $this->response(
|
||||||
|
'error',
|
||||||
|
401,
|
||||||
|
array(
|
||||||
|
'code' => 'LICENSE_KEY_REQUIRED',
|
||||||
|
'error' => 'A license key is required to use this service'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'1.2.3.17' => $this->response(
|
||||||
|
'error',
|
||||||
|
401,
|
||||||
|
array(
|
||||||
|
'code' => 'USER_ID_REQUIRED',
|
||||||
|
'error' => 'A user ID is required to use this service'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'1.2.3.18' => $this->response(
|
||||||
|
'error',
|
||||||
|
402,
|
||||||
|
array(
|
||||||
|
'code' => 'OUT_OF_QUERIES',
|
||||||
|
'error' => 'The license key you have provided is out of queries.'
|
||||||
|
)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return $responses[$ip];
|
return $responses[$ip];
|
||||||
}
|
}
|
||||||
|
@ -91,7 +139,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$country = $this->client($this->getResponse('1.2.3.4'))
|
$country = $this->client($this->getResponse('1.2.3.4'))
|
||||||
->country('1.2.3.4');
|
->country('1.2.3.4');
|
||||||
|
|
||||||
$this->assertInstanceOf('GeoIP2\Model\Country', $country);
|
$this->assertInstanceOf('GeoIp2\Model\Country', $country);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
42,
|
42,
|
||||||
|
@ -130,7 +178,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array( 'en' => 'United States of America' ),
|
array('en' => 'United States of America'),
|
||||||
$country->country->names,
|
$country->country->names,
|
||||||
'country names'
|
'country names'
|
||||||
);
|
);
|
||||||
|
@ -150,16 +198,17 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testOmni()
|
public function testInsights()
|
||||||
{
|
{
|
||||||
$omni = $this->client($this->getResponse('1.2.3.4'))
|
|
||||||
->omni('1.2.3.4');
|
|
||||||
|
|
||||||
$this->assertInstanceOf('GeoIP2\Model\Omni', $omni);
|
$record = $this->client($this->getResponse('1.2.3.4'))
|
||||||
|
->insights('1.2.3.4');
|
||||||
|
|
||||||
|
$this->assertInstanceOf('GeoIp2\Model\Insights', $record);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
42,
|
42,
|
||||||
$omni->continent->geonameId,
|
$record->continent->geonameId,
|
||||||
'continent geoname_id is 42'
|
'continent geoname_id is 42'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -169,7 +218,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$city = $this->client($this->getResponse('1.2.3.4'))
|
$city = $this->client($this->getResponse('1.2.3.4'))
|
||||||
->city('1.2.3.4');
|
->city('1.2.3.4');
|
||||||
|
|
||||||
$this->assertInstanceOf('GeoIP2\Model\City', $city);
|
$this->assertInstanceOf('GeoIp2\Model\City', $city);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMe()
|
public function testMe()
|
||||||
|
@ -177,15 +226,15 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$client = $this->client($this->getResponse('me'));
|
$client = $this->client($this->getResponse('me'));
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'GeoIP2\Model\CityIspOrg',
|
'GeoIp2\Model\City',
|
||||||
$client->cityIspOrg('me'),
|
$client->city('me'),
|
||||||
'can set ip parameter to me'
|
'can set ip parameter to me'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\GeoIP2Exception
|
* @expectedException GeoIp2\Exception\GeoIp2Exception
|
||||||
* @expectedExceptionMessage Received a 200 response for https://geoip.maxmind.com/geoip/v2.0/country/1.2.3.5 but did not receive a HTTP body.
|
* @expectedExceptionMessage Received a 200 response for https://geoip.maxmind.com/geoip/v2.1/country/1.2.3.5 but did not receive a HTTP body.
|
||||||
*/
|
*/
|
||||||
public function testNoBodyException()
|
public function testNoBodyException()
|
||||||
{
|
{
|
||||||
|
@ -195,8 +244,8 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\GeoIP2Exception
|
* @expectedException GeoIp2\Exception\GeoIp2Exception
|
||||||
* @expectedExceptionMessage Received a 200 response for https://geoip.maxmind.com/geoip/v2.0/country/2.2.3.5 but could not decode the response as JSON:
|
* @expectedExceptionMessage Received a 200 response for https://geoip.maxmind.com/geoip/v2.1/country/2.2.3.5 but could not decode the response as JSON:
|
||||||
*/
|
*/
|
||||||
public function testBadBodyException()
|
public function testBadBodyException()
|
||||||
{
|
{
|
||||||
|
@ -207,7 +256,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\WebServiceException
|
* @expectedException GeoIp2\Exception\InvalidRequestException
|
||||||
* @expectedExceptionCode 400
|
* @expectedExceptionCode 400
|
||||||
* @expectedExceptionMessage The value "1.2.3" is not a valid ip address
|
* @expectedExceptionMessage The value "1.2.3" is not a valid ip address
|
||||||
*/
|
*/
|
||||||
|
@ -216,11 +265,10 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$client = $this->client($this->getResponse('1.2.3.6'));
|
$client = $this->client($this->getResponse('1.2.3.6'));
|
||||||
|
|
||||||
$client->country('1.2.3.6');
|
$client->country('1.2.3.6');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\HttpException
|
* @expectedException GeoIp2\Exception\HttpException
|
||||||
* @expectedExceptionCode 400
|
* @expectedExceptionCode 400
|
||||||
* @expectedExceptionMessage with no body
|
* @expectedExceptionMessage with no body
|
||||||
*/
|
*/
|
||||||
|
@ -232,7 +280,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\GeoIP2Exception
|
* @expectedException GeoIp2\Exception\GeoIp2Exception
|
||||||
* @expectedExceptionMessage Response contains JSON but it does not specify code or error keys
|
* @expectedExceptionMessage Response contains JSON but it does not specify code or error keys
|
||||||
*/
|
*/
|
||||||
public function testWeirdErrorBodyIPException()
|
public function testWeirdErrorBodyIPException()
|
||||||
|
@ -244,7 +292,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\HttpException
|
* @expectedException GeoIp2\Exception\HttpException
|
||||||
* @expectedExceptionCode 400
|
* @expectedExceptionCode 400
|
||||||
* @expectedExceptionMessage did not include the expected JSON body
|
* @expectedExceptionMessage did not include the expected JSON body
|
||||||
*/
|
*/
|
||||||
|
@ -257,7 +305,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\HttpException
|
* @expectedException GeoIp2\Exception\HttpException
|
||||||
* @expectedExceptionCode 500
|
* @expectedExceptionCode 500
|
||||||
* @expectedExceptionMessage Received a server error (500)
|
* @expectedExceptionMessage Received a server error (500)
|
||||||
*/
|
*/
|
||||||
|
@ -270,7 +318,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\HttpException
|
* @expectedException GeoIp2\Exception\HttpException
|
||||||
* @expectedExceptionCode 300
|
* @expectedExceptionCode 300
|
||||||
* @expectedExceptionMessage Received a very surprising HTTP status (300)
|
* @expectedExceptionMessage Received a very surprising HTTP status (300)
|
||||||
*/
|
*/
|
||||||
|
@ -283,9 +331,9 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException GeoIP2\Exception\HttpException
|
* @expectedException GeoIp2\Exception\HttpException
|
||||||
* @expectedExceptionCode 406
|
* @expectedExceptionCode 406
|
||||||
* @expectedExceptionMessage Received a 406 error for https://geoip.maxmind.com/geoip/v2.0/country/1.2.3.12 with the following body: Cannot satisfy your Accept-Charset requirements
|
* @expectedExceptionMessage Received a 406 error for https://geoip.maxmind.com/geoip/v2.1/country/1.2.3.12 with the following body: Cannot satisfy your Accept-Charset requirements
|
||||||
*/
|
*/
|
||||||
public function test406Exception()
|
public function test406Exception()
|
||||||
{
|
{
|
||||||
|
@ -293,6 +341,72 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$client->country('1.2.3.12');
|
$client->country('1.2.3.12');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AddressNotFoundException
|
||||||
|
* @expectedExceptionMessage The address "1.2.3.13" is not in our database.
|
||||||
|
*/
|
||||||
|
public function testAddressNotFoundException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.13'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.13');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AddressNotFoundException
|
||||||
|
* @expectedExceptionMessage The address "1.2.3.14" is a private address.
|
||||||
|
*/
|
||||||
|
public function testAddressReservedException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.14'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.14');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AuthenticationException
|
||||||
|
* @expectedExceptionMessage A user ID and license key are required to use this service
|
||||||
|
*/
|
||||||
|
public function testAuthorizationException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.15'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.15');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AuthenticationException
|
||||||
|
* @expectedExceptionMessage A license key is required to use this service
|
||||||
|
*/
|
||||||
|
public function testMissingLicenseKeyException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.16'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.16');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\AuthenticationException
|
||||||
|
* @expectedExceptionMessage A user ID is required to use this service
|
||||||
|
*/
|
||||||
|
public function testMissingUserIdException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.17'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.17');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException GeoIp2\Exception\OutOfQueriesException
|
||||||
|
* @expectedExceptionMessage The license key you have provided is out of queries.
|
||||||
|
*/
|
||||||
|
public function testOutOfQueriesException()
|
||||||
|
{
|
||||||
|
$client = $this->client($this->getResponse('1.2.3.18'));
|
||||||
|
|
||||||
|
$client->country('1.2.3.18');
|
||||||
|
}
|
||||||
|
|
||||||
public function testParams()
|
public function testParams()
|
||||||
{
|
{
|
||||||
$plugin = new MockPlugin();
|
$plugin = new MockPlugin();
|
||||||
|
@ -305,7 +419,9 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
'abcdef123456',
|
'abcdef123456',
|
||||||
array('en'),
|
array('en'),
|
||||||
'geoip.maxmind.com',
|
'geoip.maxmind.com',
|
||||||
$guzzleClient
|
$guzzleClient,
|
||||||
|
27,
|
||||||
|
72
|
||||||
);
|
);
|
||||||
$client->country('1.2.3.4');
|
$client->country('1.2.3.4');
|
||||||
|
|
||||||
|
@ -313,7 +429,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$request = $all_requests[0];
|
$request = $all_requests[0];
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'https://geoip.maxmind.com/geoip/v2.0/country/1.2.3.4',
|
'https://geoip.maxmind.com/geoip/v2.1/country/1.2.3.4',
|
||||||
$request->getUrl(),
|
$request->getUrl(),
|
||||||
'got expected URI for Country request'
|
'got expected URI for Country request'
|
||||||
);
|
);
|
||||||
|
@ -332,12 +448,26 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertStringMatchesFormat(
|
$this->assertStringMatchesFormat(
|
||||||
'GeoIP2 PHP API (Guzzle%s)',
|
'GeoIP2 PHP API (Guzzle%s)',
|
||||||
$request->getHeader('User-Agent') . '',
|
$request->getHeader('User-Agent') . '',
|
||||||
'request sets Accept header to application/json'
|
'request sets Accept header to GeoIP2 PHP API (Guzzle%s)'
|
||||||
|
);
|
||||||
|
|
||||||
|
$curlOptions = $request->getCurlOptions();
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'27000',
|
||||||
|
$curlOptions[CURLOPT_TIMEOUT_MS],
|
||||||
|
'request sets Curl Option Timeout to 27 seconds'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'72000',
|
||||||
|
$curlOptions[CURLOPT_CONNECTTIMEOUT_MS],
|
||||||
|
'request sets Curl Option Connect Timeout to 72 seconds'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function client($response, $languages = array('en'))
|
private function client($response, $locales = array('en'))
|
||||||
{
|
{
|
||||||
$plugin = new MockPlugin();
|
$plugin = new MockPlugin();
|
||||||
$plugin->addResponse($response);
|
$plugin->addResponse($response);
|
||||||
|
@ -347,9 +477,13 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$client = new Client(
|
$client = new Client(
|
||||||
42,
|
42,
|
||||||
'abcdef123456',
|
'abcdef123456',
|
||||||
$languages,
|
$locales,
|
||||||
'geoip.maxmind.com',
|
'geoip.maxmind.com',
|
||||||
$guzzleClient
|
$guzzleClient
|
||||||
|
// intentionally not specifying the below, to ensure backwards compatibility
|
||||||
|
//,
|
||||||
|
// 1, // optional timeout
|
||||||
|
// 1 // optional connect timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
return $client;
|
return $client;
|
||||||
|
@ -365,7 +499,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
|
||||||
$headers = array();
|
$headers = array();
|
||||||
if ($contentType) {
|
if ($contentType) {
|
||||||
$headers['Content-Type'] = $contentType;
|
$headers['Content-Type'] = $contentType;
|
||||||
} elseif ($status == 200 || ( $status >= 400 && $status < 500 )) {
|
} elseif ($status == 200 || ($status >= 400 && $status < 500)) {
|
||||||
$headers['Content-Type'] = 'application/vnd.maxmind.com-'
|
$headers['Content-Type'] = 'application/vnd.maxmind.com-'
|
||||||
. $endpoint . '+json; charset=UTF-8; version=1.0;';
|
. $endpoint . '+json; charset=UTF-8; version=1.0;';
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
if (!$loader = @include __DIR__.'/../vendor/autoload.php') {
|
if (!$loader = @include __DIR__ . '/../vendor/autoload.php') {
|
||||||
die('Project dependencies missing');
|
die('Project dependencies missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
$loader->add('GeoIP2\Test', __DIR__);
|
$loader->add('GeoIp2\Test', __DIR__);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user