23 Commits

Author SHA1 Message Date
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
14 changed files with 235 additions and 27 deletions

4
.gitignore vendored
View File

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

View File

@@ -1,6 +1,17 @@
CHANGELOG CHANGELOG
========= =========
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) 2.0.0 (2014-09-22)
------------------ ------------------

View File

@@ -114,6 +114,24 @@ print($record->location->longitude . "\n"); // -93.2323
``` ```
### Anonymoous-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 ### ### Connection-Type Example ###
```php ```php
@@ -238,9 +256,6 @@ 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

View File

@@ -13,6 +13,8 @@
"finder": [ "finder": [
{ {
"name": [ "name": [
"LICENSE",
"LICENSE.*",
"*.php", "*.php",
"*.pem", "*.pem",
"*.pem.md5" "*.pem.md5"

View File

@@ -18,8 +18,6 @@
"php": ">=5.3.1" "php": ">=5.3.1"
}, },
"require-dev": { "require-dev": {
"apigen/apigen": "~2.8.0",
"nette/nette": "~2.1.3",
"phpunit/phpunit": "4.2.*", "phpunit/phpunit": "4.2.*",
"satooshi/php-coveralls": "dev-master" "satooshi/php-coveralls": "dev-master"
}, },

View File

@@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
set -e
TAG=$1 TAG=$1
if [ -z $TAG ]; then if [ -z $TAG ]; then
@@ -7,18 +9,39 @@ if [ -z $TAG ]; then
exit 1 exit 1
fi fi
if [ -f geoip2.phar ]; then
rm geoip2.phar
fi
if [ -n "$(git status --porcelain)" ]; then if [ -n "$(git status --porcelain)" ]; then
echo ". is not clean." >&2 echo ". is not clean." >&2
exit 1 exit 1
fi 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/kherge-archive/Box/releases/download/2.4.4/box-2.4.4.phar"
fi
php box.phar build
php composer.phar update
./vendor/bin/phpunit
if [ ! -d .gh-pages ]; then if [ ! -d .gh-pages ]; then
echo "Checking out gh-pages in .gh-pages" echo "Checking out gh-pages in .gh-pages"
git clone -b gh-pages git@git.maxmind.com:GeoIP2-php .gh-pages git clone -b gh-pages git@git.maxmind.com:GeoIP2-php .gh-pages
cd .gh-pages pushd .gh-pages
else else
echo "Updating .gh-pages" echo "Updating .gh-pages"
cd .gh-pages pushd .gh-pages
git pull git pull
fi fi
@@ -27,7 +50,25 @@ if [ -n "$(git status --porcelain)" ]; then
exit 1 exit 1
fi fi
../vendor/bin/apigen --quiet --download --title "GeoIP2 PHP API $TAG" --source ../src --destination doc/$TAG # 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 PAGE=index.md
cat <<EOF > $PAGE cat <<EOF > $PAGE
@@ -57,7 +98,8 @@ fi
git push git@github.com:maxmind/GeoIP2-php.git git push git@github.com:maxmind/GeoIP2-php.git
git push git push
cd .. popd
git tag -a $TAG git tag -a $TAG
git push git push
git push --tags git push --tags

View File

@@ -8,13 +8,9 @@ use MaxMind\Db\Reader as DbReader;
/** /**
* Instances of this class provide a reader for the GeoIP2 database format. * Instances of this class provide a reader for the GeoIP2 database format.
* IP addresses can be looked up using the <code>country</code> * IP addresses can be looked up using the database specific methods.
* 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).
* *
* **Usage** * ## Usage ##
* *
* The basic API for this class is the same for every database. First, you * 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 * 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, * 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 * each of which represents part of the data returned by the database. If
* the database does not contain the requested information, the attributes * 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 * If the address is not in the database, an
* {@link \GeoIp2\Exception\AddressNotFoundException} exception will be * {@link \GeoIp2\Exception\AddressNotFoundException} exception will be
@@ -91,6 +87,39 @@ class Reader implements ProviderInterface
return $this->modelFor('Country', '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) public function connectionType($ipAddress)
{ {
return $this->flatModelFor( return $this->flatModelFor(
@@ -100,6 +129,18 @@ class Reader implements ProviderInterface
); );
} }
/**
* 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) public function domain($ipAddress)
{ {
return $this->flatModelFor( return $this->flatModelFor(
@@ -109,6 +150,18 @@ class Reader implements ProviderInterface
); );
} }
/**
* 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) public function isp($ipAddress)
{ {
return $this->flatModelFor( return $this->flatModelFor(

View File

@@ -23,7 +23,15 @@ abstract class AbstractModel implements \JsonSerializable
*/ */
protected function get($field) protected function get($field)
{ {
return isset($this->raw[$field]) ? $this->raw[$field] : null; if (isset($this->raw[$field])) {
return $this->raw[$field];
} else {
if (preg_match('/^is_/', $field)) {
return false;
} else {
return null;
}
}
} }
/** /**

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

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

View File

@@ -30,13 +30,12 @@ use Guzzle\Http\Exception\ServerErrorResponseException;
* The web service may not return any information for an entire record, in * 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. * 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 * 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 * points. First you create a web service object with your MaxMind `$userId`
* <code>$userId</code> and <code>$licenseKey</code>, then you call the method * and `$licenseKey`, then you call the method corresponding to a specific end
* corresponding to a specific end point, passing it the IP address you want * point, passing it the IP address you want to look up.
* to look up.
* *
* If the request succeeds, the method call will return a model class for * 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 * the end point you called. This model in turn contains multiple record

View File

@@ -88,6 +88,20 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
$reader->close(); $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() public function testConnectionType()
{ {

View File

@@ -62,7 +62,7 @@ class InsightsTest 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',
@@ -130,6 +130,18 @@ class InsightsTest extends \PHPUnit_Framework_TestCase
'$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,