Compare commits

...

75 Commits

Author SHA1 Message Date
4ec525a313 Making oschwald's style changes and fixing tests 2015-03-20 19:18:55 -07:00
6f776ffac1 Mentioning test data in readme 2015-03-19 13:24:36 -07:00
a323cc38cb Adding ability to specify an HTTP timeout
Also changing Guzzle link in readme to point to appropriate version
2015-03-19 13:17:24 -07:00
Gregory Oschwald
a7f561bb64 Switch to Box 2.5.0, which fixes shebang issue 2014-12-03 17:15:50 -08:00
Gregory Oschwald
0f77785480 Improve Phar release test 2014-12-03 07:10:46 -08:00
Gregory Oschwald
a9e6ff4cfa Remove whitespace 2014-12-03 07:01:50 -08:00
Gregory Oschwald
01f58d749b Prepare for 2.1.1 2014-12-03 06:59:16 -08:00
Gregory Oschwald
64f2262093 Fix a couple minor release script issues 2014-10-29 10:11:44 -07:00
Dave Rolsky
8ef95cb4d1 Merge pull request #32 from maxmind/greg/release-updates
Automatically download apigen/box and run box
2014-10-29 11:35:19 -05:00
Gregory Oschwald
076213aedb Switch another <code> usage 2014-10-29 09:03:25 -07:00
Gregory Oschwald
1546532b39 Prepare for 2.1.0 2014-10-29 08:48:07 -07:00
Gregory Oschwald
f1fe6587b4 Fix outdated docs and use ` instead of <code> 2014-10-29 08:46:57 -07:00
Gregory Oschwald
2d6d43b62c Bump next release to 2.1.0 as it adds new features 2014-10-28 15:44:49 -07:00
Gregory Oschwald
09cf864045 Be sure to include all LICENSE files in phar 2014-10-28 14:52:18 -07:00
Gregory Oschwald
4ae7983706 Automatically download apigen/box and run box 2014-10-28 14:18:33 -07:00
Gregory Oschwald
3142e44b3e Merge pull request #31 from maxmind/dave/boolean-false-not-null
Return false instead of null for non-true boolean attributes
2014-10-28 10:49:29 -07:00
Gregory Oschwald
4bdb050a50 Fix misname property in model docs 2014-10-28 10:11:42 -07:00
Dave Rolsky
c44053c276 Return false instead of null for boolean attributes 2014-10-28 11:28:02 -05:00
Gregory Oschwald
caf91dd247 Merge pull request #30 from maxmind/dave/anonymous-ip-database
Add support for the GeoIP2 Anonymous IP database
2014-10-28 09:18:47 -07:00
Dave Rolsky
ffc6493c8d Fix small typo in CHANGELOG.md 2014-10-28 10:31:30 -05:00
Dave Rolsky
e5f61fd275 Add example for Anonymous-IP database in README.md 2014-10-28 10:10:37 -05:00
Dave Rolsky
6859340968 Add Changes for Anonymous IP support 2014-10-27 17:24:27 -05:00
Dave Rolsky
970d1dba45 Fix return vlaue docs for anonymousIp method 2014-10-27 17:21:38 -05:00
Dave Rolsky
9e6449290f Use assertSame instead of assertEquals to test boolean attributes 2014-10-27 17:21:10 -05:00
Dave Rolsky
0c6ba34623 Remove apigen dep 2014-10-27 16:39:20 -05:00
Dave Rolsky
fbf4583b3e Add support for Anonymous IP database 2014-10-27 16:30:40 -05:00
Dave Rolsky
18686e11ac Add docs for all model-returning methods on the Reader class 2014-10-27 16:06:26 -05:00
Gregory Oschwald
00a520f3c5 Remove incorrect doc 2014-09-29 13:16:23 -07:00
Gregory Oschwald
6cd0863499 Pin apigen at exactly 2.8.2. Everything else is broken 2014-09-22 16:33:18 -07:00
Gregory Oschwald
5407b4f7c6 Remove nette/nette pin so new version of apigen can be installed 2014-09-22 16:21:37 -07:00
Gregory Oschwald
c58034524e Prepare for 2.0.0 2014-09-22 10:49:45 -07:00
Gregory Oschwald
94f4f9d5e6 Prepare for 0.9.0 2014-09-15 10:16:20 -07:00
Gregory Oschwald
dac9e94304 Fix redundancy in text 2014-09-15 10:15:25 -07:00
Dave Rolsky
51e2f84d07 Merge pull request #25 from maxmind/greg/remove-deprecated-methods
Remove deprecated web service methods
2014-09-15 11:18:58 -05:00
Gregory Oschwald
42efc47796 Remove deprecated web service methods 2014-09-15 10:39:33 -05:00
Gregory Oschwald
36624ae87a Ignore GeoLite2 db 2014-09-12 07:15:42 -07:00
Gregory Oschwald
08697f2e7b Prepare for 0.8.1 2014-09-12 07:13:37 -07:00
Gregory Oschwald
2f9746c32b Relax City and Country database checks
The strict database checks broke the per-continent City databases,
and adding all of those to an array is a bit much (and slow).

Closes #23.
2014-09-12 07:06:12 -07:00
Gregory Oschwald
920a92f352 Update apigen executable name 2014-09-10 12:43:15 -07:00
Gregory Oschwald
0d90c7a78e Prepare for 0.8.0 2014-09-10 12:41:40 -07:00
Dave Rolsky
d52a0b057e Merge pull request #22 from maxmind/greg/metadata-and-type-check
Added checks of database type in lookup method
2014-09-10 14:18:48 -05:00
Gregory Oschwald
5c4dd5b1e5 Added checks of database type in lookup method 2014-09-10 12:13:09 -07:00
Gregory Oschwald
942ba4b8f5 Added a comment about 5.3 compat files (GitHub #21) 2014-08-07 06:36:04 -07:00
Gregory Oschwald
a9fa7194aa Fixed typo in attribute name (Fixes #20) 2014-08-06 06:47:50 -07:00
Gregory Oschwald
13fbcae21c Use apigen from composer 2014-07-22 09:30:20 -07:00
Gregory Oschwald
1925936b26 Update version in README.md 2014-07-22 09:22:12 -07:00
Gregory Oschwald
9384f93a72 Updated .gitignore 2014-07-22 09:19:54 -07:00
Gregory Oschwald
9a7d49f683 Prepare for 0.7.0 2014-07-22 09:19:07 -07:00
Olaf Alders
b3e5aaac21 Merge pull request #19 from maxmind/greg/ws-v2.1
Update for GeoIP2 web services v2.1
2014-07-21 12:24:02 -04:00
Gregory Oschwald
7d78bd9b2e Added missing 's' 2014-07-21 09:23:05 -07:00
Gregory Oschwald
6cf9b98993 Removed mention of embassies 2014-07-21 07:59:20 -07:00
Gregory Oschwald
a5fe44c3d3 Update for GeoIP2 web services v2.1 2014-07-15 14:19:30 -07:00
Gregory Oschwald
6b919b4cba Make headings more consistent 2014-07-14 12:33:59 -07:00
Gregory Oschwald
e441dbb64e Simplify Composer instructions 2014-07-14 12:22:43 -07:00
Boris Zentner
adffe69dd2 Merge pull request #14 from maxmind/greg/new-dbs
Greg/new dbs
2014-06-18 23:31:55 +02:00
Gregory Oschwald
04ccb67cea Fix for hhvm difference 2014-06-18 10:37:21 -07:00
Gregory Oschwald
84299eba92 Updated for new ISP test DB 2014-06-18 10:29:54 -07:00
Gregory Oschwald
cdf75ec505 Expanded examples plus small bug fix 2014-06-17 10:16:14 -07:00
Gregory Oschwald
22babda1c9 Added Connection-Type, Domain, and ISP databases 2014-06-17 09:29:14 -07:00
Gregory Oschwald
9f0c743afd Prepare for 0.6.3 2014-05-12 10:53:20 -07:00
Gregory Oschwald
4e92cd0254 Fix for Phar path issue 2014-05-09 15:07:21 -07:00
Gregory Oschwald
d61ddda4ef Ignore phar 2014-05-08 15:30:59 -07:00
Gregory Oschwald
10ecb36d16 Prepare for 0.6.2 2014-05-08 15:30:23 -07:00
Gregory Oschwald
205483e14c Fix phar with new versions of Guzzle 2014-05-08 15:30:23 -07:00
Gregory Oschwald
6584b545ea Only run phpcs on 5.5. It is broken on 5.6 and hhvm. 2014-05-02 06:57:11 -07:00
Gregory Oschwald
ac6592b7a5 Wording tweak 2014-05-01 16:47:38 -07:00
Gregory Oschwald
cb9c024699 Prepare for 0.6.1 2014-05-01 07:20:30 -07:00
Gregory Oschwald
e014aadf8d Merge pull request #13 from Seldaek/patch-1
Target compat autoload rules more narrowly
2014-04-25 05:50:18 -07:00
Jordi Boggiano
a043336cae Target compat autoload rules more narrowly 2014-04-25 14:13:31 +02:00
Gregory Oschwald
0c9b774015 Updated submodule 2014-04-14 07:15:31 -07:00
Gregory Oschwald
38bacff692 Clean up box.json 2014-04-11 17:21:33 -07:00
Gregory Oschwald
5cfe1353bb Added doc about using phar 2014-04-11 16:18:14 -07:00
Gregory Oschwald
6715f848bb Add box.json for creating phar 2014-04-11 16:13:20 -07:00
Gregory Oschwald
56407eff17 Test HHVM and 5.6 2014-04-03 10:59:16 -07:00
Gregory Oschwald
9b2fa1bcd1 Added note about creating composer.json 2014-03-06 13:23:20 -08:00
34 changed files with 985 additions and 390 deletions

5
.gitignore vendored
View File

@ -1,11 +1,14 @@
_site
.gh-pages
.idea
GeoLite2-City.mmdb
apigen.phar
box.phar
build
composer.lock
composer.phar
phpunit.xml
geoip2-php.sublime-*
vendor/
*.sw?
t.php
*.old

View File

@ -4,16 +4,18 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_install:
- composer self-update
- 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
script:
- 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
after_script:

View File

@ -1,6 +1,85 @@
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)
------------------

150
README.md
View File

@ -7,45 +7,55 @@ This package provides an API for the GeoIP2 [web services]
(http://dev.maxmind.com/geoip/geoip2/downloadable). The API also works with
the free [GeoLite2 databases](http://dev.maxmind.com/geoip/geoip2/geolite2/).
## Installation ##
### Define Your Dependencies ###
## Install via Composer ##
We recommend installing this package with [Composer](http://getcomposer.org/).
To do this, add `geoip2/geoip2` to your `composer.json` file.
```json
{
"require": {
"geoip2/geoip2": "0.6.*"
}
}
### Download Composer ###
To download Composer, run in the root directory of your project:
```bash
curl -sS https://getcomposer.org/installer | php
```
### Install Composer ###
Run in your project root:
```
curl -s http://getcomposer.org/installer | php
```
You should now have the file `composer.phar` in your project directory.
### Install Dependencies ###
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 ###
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';
```
### Optional C Extension ###
## Install via Phar ##
Although we strongly recommend using Composer, we also provide a
[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
@ -68,12 +78,12 @@ 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 returned. If the database is invalid or corrupt, a
is thrown. If the database is invalid or corrupt, a
`\MaxMind\Db\InvalidDatabaseException` will be thrown.
See the API documentation for more details.
### Example ###
### City Example ###
```php
<?php
@ -104,6 +114,82 @@ 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 ###
@ -134,7 +220,7 @@ use GeoIp2\WebService\Client;
$client = new Client(42, 'abcdef123456');
// Replace "city" with the method corresponding to the web service that
// you are using, e.g., "country", "cityIspOrg", "omni".
// you are using, e.g., "country", "insights".
$record = $client->city('128.101.101.101');
print($record->country->isoCode . "\n"); // 'US'
@ -164,15 +250,12 @@ Because of these factors, it is possible for any end point to return a record
where some or all of the attributes are unpopulated.
See the
[GeoIP2 web service docs](http://dev.maxmind.com/geoip/geoip2/web-services)
[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`
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 ##
[GeoNames](http://www.geonames.org/) offers web services and downloadable
@ -220,13 +303,18 @@ to the client API, please see
This code requires PHP 5.3 or greater. Older versions of PHP are not
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 ##
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 ##
@ -234,7 +322,7 @@ The GeoIP2 PHP API uses [Semantic Versioning](http://semver.org/).
## 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.

26
bin/benchmark.php Executable file
View 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");

View File

@ -1,63 +0,0 @@
#!/bin/bash
TAG=$1
if [ -z $TAG ]; then
echo "Please specify a tag"
exit 1
fi
if [ -n "$(git status --porcelain)" ]; then
echo ". is not clean." >&2
exit 1
fi
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
cd .gh-pages
else
echo "Updating .gh-pages"
cd .gh-pages
git pull
fi
if [ -n "$(git status --porcelain)" ]; then
echo ".gh-pages is not clean" >&2
exit 1
fi
apigen --quiet --download --title "GeoIP2 PHP API $TAG" --source ../src --destination doc/$TAG
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
cd ..
git tag -a $TAG
git push
git push --tags

36
box.json Normal file
View 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
}

View File

@ -1,7 +1,7 @@
{
"name": "geoip2/geoip2",
"description": "MaxMind GeoIP2 PHP API",
"keywords": [ "geoip", "geolocation", "maxmind" ],
"keywords": ["geoip", "geoip2", "geolocation", "ip", "maxmind"],
"homepage": "https://github.com/maxmind/GeoIP2-php",
"type": "library",
"license": "Apache-2.0",
@ -14,17 +14,17 @@
],
"require": {
"guzzle/guzzle": "3.*",
"maxmind-db/reader": "0.3.*",
"maxmind-db/reader": "~1.0",
"php": ">=5.3.1"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"phpunit/phpunit": "4.2.*",
"satooshi/php-coveralls": "dev-master"
},
"autoload": {
"psr-0": {
"GeoIp2": "src/",
"" : "compat/"
}
"JsonSerializable": "compat/"
}
}
}

15
dev-bin/phar-test.php Executable file
View 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
View 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 +1 @@
Subproject commit f7b9342b84f2d2af61d9ee57352a7cbb76db6bd0
Subproject commit e53ed8cde6951be3bbd0fdb300d69c898b399a97

17
phar-stub.php Normal file
View 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));
}
}

View File

@ -8,13 +8,9 @@ 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 <code>country</code>
* and <code>city</code> methods. We also provide <code>cityIspOrg</code>
* and <code>omni</code> methods to ease compatibility with the web service
* client, although we may offer the ability to specify additional databases
* to replicate these web services in the future (e.g., the ISP/Org database).
* IP addresses can be looked up using the database specific methods.
*
* **Usage**
* ## 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
@ -25,7 +21,7 @@ use MaxMind\Db\Reader as DbReader;
* 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 <code>null</code> value.
* 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
@ -71,7 +67,7 @@ class Reader implements ProviderInterface
*/
public function city($ipAddress)
{
return $this->modelFor('City', $ipAddress);
return $this->modelFor('City', 'City', $ipAddress);
}
/**
@ -88,55 +84,139 @@ class Reader implements ProviderInterface
*/
public function country($ipAddress)
{
return $this->modelFor('Country', $ipAddress);
return $this->modelFor('Country', 'Country', $ipAddress);
}
/**
* This method returns a GeoIP2 City/ISP/Org model.
* This method returns a GeoIP2 Anonymous IP model.
*
* @param string $ipAddress IPv4 or IPv6 address as a string.
*
* @return \GeoIp2\Model\CityIspOrg
* @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 cityIspOrg($ipAddress)
public function anonymousIp($ipAddress)
{
return $this->modelFor('CityIspOrg', $ipAddress);
return $this->flatModelFor(
'AnonymousIp',
'GeoIP2-Anonymous-IP',
$ipAddress
);
}
/**
* This method returns a GeoIP2 Omni model.
* This method returns a GeoIP2 Connection Type model.
*
* @param string $ipAddress IPv4 or IPv6 address as a string.
*
* @return \GeoIp2\Model\Omni
* @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 omni($ipAddress)
public function connectionType($ipAddress)
{
return $this->modelFor('Omni', $ipAddress);
return $this->flatModelFor(
'ConnectionType',
'GeoIP2-Connection-Type',
$ipAddress
);
}
private function modelFor($class, $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."
);
}
$record['traits']['ip_address'] = $ipAddress;
$class = "GeoIp2\\Model\\" . $class;
return $record;
}
return new $class($record, $this->locales);
/**
* @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();
}
/**

View 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;
}
}

View 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');
}
}

View File

@ -3,11 +3,10 @@
namespace GeoIp2\Model;
/**
* This class provides a model for the data returned by the GeoIP2
* City end point.
* Model class for the data returned by GeoIP2 City web service and database.
*
* The only difference between the City, City/ISP/Org, and Omni model
* classes is which fields in each record may be populated. See
* 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
@ -33,8 +32,8 @@ namespace GeoIp2\Model;
*
* @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.
* 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

View File

@ -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 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
{
}

View 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');
}
}

View File

@ -3,11 +3,10 @@
namespace GeoIp2\Model;
/**
* This class provides a model for the data returned by the GeoIP2 Country
* end point.
* Model class for the data returned by GeoIP2 Country web service and database.
*
* The only difference between the City, City/ISP/Org, and Omni model
* classes is which fields in each record may be populated. See
* 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
@ -27,29 +26,28 @@ namespace GeoIp2\Model;
*
* @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.
* 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 implements \JsonSerializable
class Country extends AbstractModel
{
private $continent;
private $country;
private $locales;
private $maxmind;
private $registeredCountry;
private $representedCountry;
private $traits;
private $raw;
protected $continent;
protected $country;
protected $locales;
protected $maxmind;
protected $registeredCountry;
protected $representedCountry;
protected $traits;
/**
* @ignore
*/
public function __construct($raw, $locales = array('en'))
{
$this->raw = $raw;
parent::__construct($raw);
$this->continent = new \GeoIp2\Record\Continent(
$this->get('continent'),
@ -72,37 +70,4 @@ class Country implements \JsonSerializable
$this->locales = $locales;
}
/**
* @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");
}
/**
* @ignore
*/
public function __isset($attr)
{
return $attr != "instance" && isset($this->$attr);
}
public function jsonSerialize()
{
return $this->raw;
}
}

View 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');
}
}

View File

@ -3,11 +3,10 @@
namespace GeoIp2\Model;
/**
* This class provides a model for the data returned by the GeoIP2
* Omni end point.
* Model class for the data returned by GeoIP2 Precision: Insights web service.
*
* The only difference between the City, City/ISP/Org, and Omni model
* classes is which fields in each record may be populated. See
* 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
@ -33,8 +32,8 @@ namespace GeoIp2\Model;
*
* @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.
* 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
@ -52,6 +51,6 @@ namespace GeoIp2\Model;
* @property \GeoIp2\Record\Traits $traits Data for the traits of the
* requested IP address.
*/
class Omni extends CityIspOrg
class Insights extends City
{
}

45
src/GeoIp2/Model/Isp.php Normal file
View 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');
}
}

View File

@ -17,18 +17,4 @@ interface ProviderInterface
* @return \GeoIp2\Model\City A City model for the requested IP address.
*/
public function city($ipAddress);
/**
* @param ipAddress
* IPv4 or IPv6 address to lookup.
* @return \GeoIp2\Model\CityIspOrg A CityIspOrg model for the requested IP address.
*/
public function cityIspOrg($ipAddress);
/**
* @param ipAddress
* IPv4 or IPv6 address to lookup.
* @return \GeoIp2\Model\Omni An Omni model for the requested IP address.
*/
public function omni($ipAddress);
}

View File

@ -11,7 +11,7 @@ abstract class AbstractRecord implements \JsonSerializable
*/
public function __construct($record)
{
$this->record = $record;
$this->record = isset($record) ? $record : array();
}
/**
@ -25,7 +25,11 @@ abstract class AbstractRecord implements \JsonSerializable
if ($this->__isset($attr)) {
return $this->record[$key];
} elseif ($this->validAttribute($attr)) {
return null;
if (preg_match('/^is_/', $key)) {
return false;
} else {
return null;
}
} else {
throw new \RuntimeException("Unknown attribute: $attr");
}

View File

@ -9,7 +9,7 @@ namespace GeoIp2\Record;
*
* @property int $confidence A value from 0-100 indicating MaxMind's
* 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
* is returned by all end points.

View File

@ -9,7 +9,7 @@ namespace GeoIp2\Record;
*
* @property int $accuracyRadius The radius in kilometers around the
* 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
* point number. This attribute is returned by all end points except the

View File

@ -14,7 +14,7 @@ namespace GeoIp2\Record;
*
* @property int $confidence A value from 0-100 indicating MaxMind's
* 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
{

View File

@ -7,31 +7,26 @@ namespace GeoIp2\Record;
*
* This class contains the country-level data associated with an IP address
* for the IP's represented country. The represented country is the country
* represented by something like a military base or embassy.
*
* This record is returned by all the end points.
* represented by something like a military base.
*
* @property int $confidence A value from 0-100 indicating MaxMind's
* 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
* returned by all end points.
* @property int $geonameId The GeoName ID for the country.
*
* @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
* returned by all end points.
* two-character ISO 3166-1 alpha code} for the country.
*
* @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 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
* representing the country. Currently we only return <code>military</code>
* but this could expand to include other types such as <code>embassy</code>
* in the future. Returned by all endpoints.
* but this could expand to include other types in the future.
*/
class RepresentedCountry extends Country
{
@ -39,7 +34,7 @@ class RepresentedCountry extends Country
'confidence',
'geonameId',
'isoCode',
'namespace',
'names',
'type'
);
}

View File

@ -10,7 +10,7 @@ namespace GeoIp2\Record;
*
* @property int $confidence This is a value from 0-100 indicating MaxMind's
* 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
* attribute is returned by all end points except Country.

View File

@ -11,18 +11,18 @@ namespace GeoIp2\Record;
* @property int $autonomousSystemNumber The {@link
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
* 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
* associated with the registered {@link
* http://en.wikipedia.org/wiki/Autonomous_system_(Internet) autonomous
* 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
* IP address. This will be something like "example.com" or "example.co.uk",
* 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
* is for. If you performed a "me" lookup against the web service, this
@ -40,12 +40,12 @@ namespace GeoIp2\Record;
* end points.
*
* @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.
*
* @property string $organization The name of the organization associated
* with the IP address. This attribute is only available from the City/ISP/Org
* and Omni end points.
* with the IP address. This attribute is only available from the City and
* Insights web service end points.
*
* @property string $userType <p>The user type associated with the IP
* address. This can be one of the following values:</p>
@ -66,7 +66,10 @@ namespace GeoIp2\Record;
* <li>search_engine_spider
* <li>traveler
* </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
{

View File

@ -15,10 +15,10 @@ 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.
* 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
@ -30,13 +30,12 @@ use Guzzle\Http\Exception\ServerErrorResponseException;
* 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**
* ## 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.
* 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
@ -52,6 +51,8 @@ class Client implements ProviderInterface
private $locales;
private $host;
private $guzzleClient;
private $timeout;
private $connectTimeout;
/**
* Constructor.
@ -63,13 +64,17 @@ class Client implements ProviderInterface
* @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
$guzzleClient = null,
$timeout = null,
$connectTimeout = null
) {
$this->userId = $userId;
$this->licenseKey = $licenseKey;
@ -77,10 +82,12 @@ class Client implements ProviderInterface
$this->host = $host;
// To enable unit testing
$this->guzzleClient = $guzzleClient;
$this->timeout = $timeout;
$this->connectTimeout = $connectTimeout;
}
/**
* This method calls the GeoIP2 City endpoint.
* 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
@ -112,7 +119,7 @@ class Client implements ProviderInterface
}
/**
* This method calls the GeoIP2 Country endpoint.
* 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
@ -144,13 +151,13 @@ class Client implements ProviderInterface
}
/**
* This method calls the GeoIP2 City/ISP/Org endpoint.
* 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\CityIspOrg
* @return \GeoIp2\Model\Insights
*
* @throws \GeoIp2\Exception\AddressNotFoundException if the address you
* provided is not in our database (e.g., a private address).
@ -170,41 +177,9 @@ class Client implements ProviderInterface
* class to the above exceptions. It will be thrown directly if a 200
* status code is returned but the body is invalid.
*/
public function cityIspOrg($ipAddress = 'me')
public function insights($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\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 omni($ipAddress = 'me')
{
return $this->responseFor('omni', 'Omni', $ipAddress);
return $this->responseFor('insights', 'Insights', $ipAddress);
}
private function responseFor($endpoint, $class, $ipAddress)
@ -213,7 +188,14 @@ class Client implements ProviderInterface
$client = $this->guzzleClient ?
$this->guzzleClient : new GuzzleClient();
$request = $client->get($uri, array('Accept' => 'application/json'));
$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);
@ -354,6 +336,6 @@ class Client implements ProviderInterface
private function baseUri()
{
return 'https://' . $this->host . '/geoip/v2.0';
return 'https://' . $this->host . '/geoip/v2.1';
}
}

View File

@ -8,44 +8,39 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
{
public function testDefaultLocale()
{
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
// Needed for PHP 5.3
$that = $this;
$this->checkAllMethods(
function ($method) use (&$that, &$reader) {
$record = $reader->$method('81.2.69.160');
$that->assertEquals('United Kingdom', $record->country->name);
}
);
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()
{
$reader = new Reader(
'maxmind-db/test-data/GeoIP2-City-Test.mmdb',
array('xx', 'ru', 'pt-BR', 'es', 'en')
);
$that = $this;
$this->checkAllMethods(
function ($method) use (&$that, &$reader) {
$record = $reader->$method('81.2.69.160');
$that->assertEquals('Великобритания', $record->country->name);
}
);
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()
{
$reader = new Reader('maxmind-db/test-data/GeoIP2-City-Test.mmdb');
$that = $this;
$this->checkAllMethods(
function ($method) use (&$that, &$reader) {
$record = $reader->$method('81.2.69.160');
$that->assertEquals('81.2.69.160', $record->traits->ipAddress);
}
);
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();
}
@ -60,6 +55,28 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
$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
@ -71,10 +88,67 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
$reader->close();
}
public function checkAllMethods($testCb)
public function testAnonymousIp()
{
foreach (array('city', 'cityIspOrg', 'country', 'omni') as $method) {
$testCb($method);
}
$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();
}
}

View File

@ -2,9 +2,9 @@
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()
@ -62,19 +62,19 @@ class OmniTest extends \PHPUnit_Framework_TestCase
'autonomous_system_organization' => 'AS Organization',
'domain' => 'example.com',
'ip_address' => '1.2.3.4',
'is_satellite_provider' => 1,
'is_satellite_provider' => true,
'isp' => 'Comcast',
'organization' => 'Blorg',
'user_type' => 'college',
),
);
$model = new Omni($raw, array('en'));
$model = new Insights($raw, array('en'));
$this->assertInstanceOf(
'GeoIp2\Model\Omni',
'GeoIp2\Model\Insights',
$model,
'GeoIp2\Model\Omni object'
'GeoIp2\Model\Insights object'
);
$this->assertInstanceOf(
@ -130,6 +130,18 @@ class OmniTest extends \PHPUnit_Framework_TestCase
'$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(
22,
$model->maxmind->queriesRemaining,
@ -147,12 +159,12 @@ class OmniTest extends \PHPUnit_Framework_TestCase
{
$raw = array('traits' => array('ip_address' => '5.6.7.8'));
$model = new Omni($raw, array('en'));
$model = new Insights($raw, array('en'));
$this->assertInstanceOf(
'GeoIp2\Model\Omni',
'GeoIp2\Model\Insights',
$model,
'GeoIp2\Model\Omni object with no data except traits.ipAddress'
'GeoIp2\Model\Insights object with no data except traits.ipAddress'
);
$this->assertInstanceOf(
@ -231,12 +243,12 @@ class OmniTest extends \PHPUnit_Framework_TestCase
);
// checking whether there are exceptions with unknown keys
$model = new Omni($raw, array('en'));
$model = new Insights($raw, array('en'));
$this->assertInstanceOf(
'GeoIp2\Model\Omni',
'GeoIp2\Model\Insights',
$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(

View File

@ -198,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(
42,
$omni->continent->geonameId,
$record->continent->geonameId,
'continent geoname_id is 42'
);
}
@ -225,15 +226,15 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$client = $this->client($this->getResponse('me'));
$this->assertInstanceOf(
'GeoIp2\Model\CityIspOrg',
$client->cityIspOrg('me'),
'GeoIp2\Model\City',
$client->city('me'),
'can set ip parameter to me'
);
}
/**
* @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()
{
@ -244,7 +245,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
/**
* @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()
{
@ -332,7 +333,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException GeoIp2\Exception\HttpException
* @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()
{
@ -418,7 +419,9 @@ class ClientTest extends \PHPUnit_Framework_TestCase
'abcdef123456',
array('en'),
'geoip.maxmind.com',
$guzzleClient
$guzzleClient,
27,
72
);
$client->country('1.2.3.4');
@ -426,7 +429,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$request = $all_requests[0];
$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(),
'got expected URI for Country request'
);
@ -445,7 +448,21 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$this->assertStringMatchesFormat(
'GeoIP2 PHP API (Guzzle%s)',
$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'
);
}
@ -463,6 +480,10 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$locales,
'geoip.maxmind.com',
$guzzleClient
// intentionally not specifying the below, to ensure backwards compatibility
//,
// 1, // optional timeout
// 1 // optional connect timeout
);
return $client;