Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8c3c38a

Browse files
Created HostIpXml all alternative to HostIp (#1057)
* Created HostIpXml all alternative to HostIp(json) because JSON does not have lat,lng anymore. !squash code style fixes * added require to provider composer.json * updated function fqn * added interface to AbstractHostIp
1 parent 1f3865d commit 8c3c38a

11 files changed

+376
-75
lines changed

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@
4646
"ext-geoip": "Enabling the geoip extension allows you to use the MaxMindProvider.",
4747
"geoip/geoip": "If you are going to use the MaxMindBinaryProvider (conflict with geoip extension).",
4848
"geoip2/geoip2": "If you are going to use the GeoIP2DatabaseProvider.",
49-
"symfony/stopwatch": "If you want to use the TimedGeocoder"
49+
"symfony/stopwatch": "If you want to use the TimedGeocoder",
50+
"ext-simplexml": "If you want to use HostIpXml",
51+
"ext-json": "If you want to use HostIp"
5052
},
5153
"extra": {
5254
"branch-alias": {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\HostIp;
14+
15+
use Geocoder\Collection;
16+
use Geocoder\Exception\UnsupportedOperation;
17+
use Geocoder\Http\Provider\AbstractHttpProvider;
18+
use Geocoder\Model\Address;
19+
use Geocoder\Model\AddressCollection;
20+
use Geocoder\Query\GeocodeQuery;
21+
use Geocoder\Query\ReverseQuery;
22+
23+
/**
24+
* @author William Durand <[email protected]>
25+
* @author Oleg Andreyev <[email protected]>
26+
*/
27+
abstract class AbstractHostIp extends AbstractHttpProvider implements \Geocoder\Provider\Provider
28+
{
29+
abstract protected function executeQuery(string $url): AddressCollection;
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function geocodeQuery(GeocodeQuery $query): Collection
35+
{
36+
$address = $query->getText();
37+
if (!filter_var($address, FILTER_VALIDATE_IP)) {
38+
throw new UnsupportedOperation('The '.get_class($this).' provider does not support Street addresses.');
39+
}
40+
41+
// This API does not support IPv6
42+
if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
43+
throw new UnsupportedOperation('The HostIp provider does not support IPv6 addresses.');
44+
}
45+
46+
if ('127.0.0.1' === $address) {
47+
return new AddressCollection([$this->getLocationForLocalhost()]);
48+
}
49+
50+
$url = sprintf(static::ENDPOINT_URL, $address);
51+
52+
return $this->executeQuery($url);
53+
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function reverseQuery(ReverseQuery $query): Collection
59+
{
60+
throw new UnsupportedOperation('The HostIp provider is not able to do reverse geocoding.');
61+
}
62+
63+
/**
64+
* @param array $data
65+
*
66+
* @return bool
67+
*/
68+
protected function isUnknownLocation(array $data): bool
69+
{
70+
return empty($data['lat'])
71+
&& empty($data['lng'])
72+
&& '(Unknown City?)' === $data['city']
73+
&& '(Unknown Country?)' === $data['country_name']
74+
&& 'XX' === $data;
75+
}
76+
77+
/**
78+
* @param array $data
79+
*
80+
* @return bool
81+
*/
82+
protected function isPrivateLocation(array $data): bool
83+
{
84+
return empty($data['lat'])
85+
&& empty($data['lng'])
86+
&& '(Private Address)' === $data['city']
87+
&& '(Private Address)' === $data['country_name']
88+
&& 'XX' === $data;
89+
}
90+
91+
/**
92+
* @param array $data
93+
*
94+
* @return AddressCollection
95+
*/
96+
protected function prepareAddressCollection(array $data): AddressCollection
97+
{
98+
// Return empty collection if address was not found
99+
if ($this->isUnknownLocation($data)) {
100+
return new AddressCollection([]);
101+
}
102+
103+
// Return empty collection if address was not found
104+
if ($this->isPrivateLocation($data)) {
105+
return new AddressCollection([]);
106+
}
107+
108+
return new AddressCollection([
109+
Address::createFromArray([
110+
'providedBy' => $this->getName(),
111+
'latitude' => $data['lat'] ?? null,
112+
'longitude' => $data['lng'] ?? null,
113+
'locality' => $data['city'],
114+
'country' => $data['country_name'],
115+
'countryCode' => $data['country_code'],
116+
]),
117+
]);
118+
}
119+
}

src/Provider/HostIp/HostIp.php

Lines changed: 4 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,20 @@
1212

1313
namespace Geocoder\Provider\HostIp;
1414

15-
use Geocoder\Exception\UnsupportedOperation;
1615
use Geocoder\Collection;
17-
use Geocoder\Model\Address;
1816
use Geocoder\Model\AddressCollection;
19-
use Geocoder\Query\GeocodeQuery;
20-
use Geocoder\Query\ReverseQuery;
21-
use Geocoder\Http\Provider\AbstractHttpProvider;
22-
use Geocoder\Provider\Provider;
17+
use function json_decode;
2318

2419
/**
2520
* @author William Durand <[email protected]>
2621
*/
27-
final class HostIp extends AbstractHttpProvider implements Provider
22+
final class HostIp extends AbstractHostIp
2823
{
2924
/**
3025
* @var string
3126
*/
3227
const ENDPOINT_URL = 'http://api.hostip.info/get_json.php?ip=%s&position=true';
3328

34-
/**
35-
* {@inheritdoc}
36-
*/
37-
public function geocodeQuery(GeocodeQuery $query): Collection
38-
{
39-
$address = $query->getText();
40-
if (!filter_var($address, FILTER_VALIDATE_IP)) {
41-
throw new UnsupportedOperation('The HostIp provider does not support Street addresses.');
42-
}
43-
44-
// This API does not support IPv6
45-
if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
46-
throw new UnsupportedOperation('The HostIp provider does not support IPv6 addresses.');
47-
}
48-
49-
if ('127.0.0.1' === $address) {
50-
return new AddressCollection([$this->getLocationForLocalhost()]);
51-
}
52-
53-
$url = sprintf(self::ENDPOINT_URL, $address);
54-
55-
return $this->executeQuery($url);
56-
}
57-
58-
/**
59-
* {@inheritdoc}
60-
*/
61-
public function reverseQuery(ReverseQuery $query): Collection
62-
{
63-
throw new UnsupportedOperation('The HostIp provider is not able to do reverse geocoding.');
64-
}
65-
6629
/**
6730
* {@inheritdoc}
6831
*/
@@ -76,7 +39,7 @@ public function getName(): string
7639
*
7740
* @return Collection
7841
*/
79-
private function executeQuery(string $url): AddressCollection
42+
protected function executeQuery(string $url): AddressCollection
8043
{
8144
$content = $this->getUrlContents($url);
8245
$data = json_decode($content, true);
@@ -85,33 +48,6 @@ private function executeQuery(string $url): AddressCollection
8548
return new AddressCollection([]);
8649
}
8750

88-
// Return empty collection if address was not found
89-
if (null === $data['lat']
90-
&& null === $data['lng']
91-
&& '(Unknown City?)' === $data['city']
92-
&& '(Unknown Country?)' === $data['country_name']
93-
&& 'XX' === $data['country_code']) {
94-
return new AddressCollection([]);
95-
}
96-
97-
// Return empty collection if address was not found
98-
if (null === $data['lat']
99-
&& null === $data['lng']
100-
&& '(Private Address)' === $data['city']
101-
&& '(Private Address)' === $data['country_name']
102-
&& 'XX' === $data['country_code']) {
103-
return new AddressCollection([]);
104-
}
105-
106-
return new AddressCollection([
107-
Address::createFromArray([
108-
'providedBy' => $this->getName(),
109-
'latitude' => $data['lat'],
110-
'longitude' => $data['lng'],
111-
'locality' => $data['city'],
112-
'country' => $data['country_name'],
113-
'countryCode' => $data['country_code'],
114-
]),
115-
]);
51+
return $this->prepareAddressCollection($data);
11652
}
11753
}

src/Provider/HostIp/HostIpXml.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\HostIp;
14+
15+
use Geocoder\Collection;
16+
use Geocoder\Model\AddressCollection;
17+
use function simplexml_load_string;
18+
19+
/**
20+
* @author Oleg Andreyev <[email protected]>
21+
*/
22+
final class HostIpXml extends AbstractHostIp
23+
{
24+
/**
25+
* @var string
26+
*/
27+
const ENDPOINT_URL = 'http://api.hostip.info/get_xml.php?ip=%s&position=true';
28+
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function getName(): string
33+
{
34+
return 'host_ip_xml';
35+
}
36+
37+
/**
38+
* @param string $url
39+
*
40+
* @return Collection
41+
*/
42+
protected function executeQuery(string $url): AddressCollection
43+
{
44+
$content = $this->getUrlContents($url);
45+
$xml = simplexml_load_string($content);
46+
47+
$hostIp = $xml->xpath('/HostipLookupResultSet/gml:featureMember/Hostip');
48+
if (empty($hostIp[0])) {
49+
return new AddressCollection([]);
50+
}
51+
$hostIp = $hostIp[0];
52+
53+
$city = (string) $hostIp->xpath('.//gml:name')[0];
54+
$countryName = (string) $hostIp->xpath('.//countryName')[0];
55+
$countryCode = (string) $hostIp->xpath('.//countryAbbrev')[0];
56+
$coords = $hostIp->xpath('.//ipLocation/gml:pointProperty/gml:Point/gml:coordinates');
57+
58+
if (empty($coords)) {
59+
list($lng, $lat) = [null, null];
60+
} else {
61+
list($lng, $lat) = explode(',', (string) $coords[0], 2);
62+
}
63+
64+
return $this->prepareAddressCollection([
65+
'lat' => $lat,
66+
'lng' => $lng,
67+
'city' => $city,
68+
'country_name' => $countryName,
69+
'country_code' => $countryCode,
70+
]);
71+
}
72+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
s:117:"{"country_name":"UNITED STATES","country_code":"US","city":"(Unknown city)","ip":"33.33.33.22","lat":null,"lng":null}";
1+
s:95:"{"country_name":"UNITED STATES","country_code":"US","city":"(Unknown city)","ip":"33.33.33.22"}";
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
s:700:"<?xml version="1.0" encoding="ISO-8859-1" ?>
2+
<HostipLookupResultSet version="1.0.1" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
3+
<gml:description>This is the Hostip Lookup Service</gml:description>
4+
<gml:name>hostip</gml:name>
5+
<gml:boundedBy>
6+
<gml:Null>inapplicable</gml:Null>
7+
</gml:boundedBy>
8+
<gml:featureMember>
9+
<Hostip>
10+
<ip>33.33.33.22</ip>
11+
<gml:name>(Unknown city)</gml:name>
12+
<countryName>UNITED STATES</countryName>
13+
<countryAbbrev>US</countryAbbrev>
14+
<!-- Co-ordinates are unavailable -->
15+
</Hostip>
16+
</gml:featureMember>
17+
</HostipLookupResultSet>
18+
";
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
s:923:"<?xml version="1.0" encoding="ISO-8859-1" ?>
2+
<HostipLookupResultSet version="1.0.1" xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
3+
<gml:description>This is the Hostip Lookup Service</gml:description>
4+
<gml:name>hostip</gml:name>
5+
<gml:boundedBy>
6+
<gml:Null>inapplicable</gml:Null>
7+
</gml:boundedBy>
8+
<gml:featureMember>
9+
<Hostip>
10+
<ip>77.38.216.139</ip>
11+
<gml:name>Riga</gml:name>
12+
<countryName>LATVIA</countryName>
13+
<countryAbbrev>LV</countryAbbrev>
14+
<!-- Co-ordinates are available as lng,lat -->
15+
<ipLocation>
16+
<gml:pointProperty>
17+
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
18+
<gml:coordinates>24.0833,56.8833</gml:coordinates>
19+
</gml:Point>
20+
</gml:pointProperty>
21+
</ipLocation>
22+
</Hostip>
23+
</gml:featureMember>
24+
</HostipLookupResultSet>
25+
";
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
s:113:"{"country_name":"FRANCE","country_code":"FR","city":"Aulnat","ip":"88.188.221.14","lat":"45.5333","lng":"2.6167"}";
1+
s:82:"{"country_name":"FRANCE","country_code":"FR","city":"Aulnat","ip":"88.188.221.14"}";

src/Provider/HostIp/Tests/HostIpTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function testGetName()
3333

3434
/**
3535
* @expectedException \Geocoder\Exception\UnsupportedOperation
36-
* @expectedExceptionMessage The HostIp provider does not support Street addresses.
36+
* @expectedExceptionMessage The Geocoder\Provider\HostIp\HostIp provider does not support Street addresses.
3737
*/
3838
public function testGeocodeWithAddress()
3939
{
@@ -83,8 +83,7 @@ public function testGeocodeWithRealIPv4()
8383
/** @var Location $result */
8484
$result = $results->first();
8585
$this->assertInstanceOf('\Geocoder\Model\Address', $result);
86-
$this->assertEquals(45.5333, $result->getCoordinates()->getLatitude(), '', 0.0001);
87-
$this->assertEquals(2.6167, $result->getCoordinates()->getLongitude(), '', 0.0001);
86+
$this->assertEquals(null, $result->getCoordinates());
8887
$this->assertNull($result->getPostalCode());
8988
$this->assertEquals('Aulnat', $result->getLocality());
9089
$this->assertEmpty($result->getAdminLevels());

0 commit comments

Comments
 (0)