243 lines
8.2 KiB
PHP
243 lines
8.2 KiB
PHP
<?php
|
|
/*
|
|
Copyright 2013-2019 Yellow Tree, Siegen, Germany
|
|
Author: Benjamin Pick (wp-geoip-detect| |posteo.de)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
namespace YellowTree\GeoipDetect\DataSources\Ipstack;
|
|
|
|
use YellowTree\GeoipDetect\DataSources\AbstractDataSource;
|
|
|
|
class Reader implements \YellowTree\GeoipDetect\DataSources\ReaderInterface {
|
|
|
|
const URL = 'api.ipstack.com/';
|
|
protected $options = array();
|
|
protected $params = array();
|
|
|
|
function __construct($params, $locales, $options) {
|
|
$this->params= $params;
|
|
$this->params['language'] = reset($locales);
|
|
if (empty($this->params['language'])) {
|
|
$this->params['language'] = 'en';
|
|
}
|
|
|
|
$default_options = array(
|
|
'timeout' => 1,
|
|
);
|
|
$this->options = $options + $default_options;
|
|
}
|
|
|
|
protected function locales($locale, $value) {
|
|
$locales = array('en' => $value);
|
|
if ($locale != 'en') {
|
|
$locales[$locale] = $value;
|
|
}
|
|
return $locales;
|
|
}
|
|
|
|
public function city($ip) {
|
|
$data = $this->api_call($ip);
|
|
|
|
if (!$data)
|
|
return null;
|
|
|
|
$r = array();
|
|
|
|
$r['extra']['original'] = $data;
|
|
|
|
if (isset($data['success']) && $data['success'] === false) {
|
|
throw new \RuntimeException($data['error']['info']);
|
|
// Example error:
|
|
/* @see https://ipstack.com/documentation#errors
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": 104,
|
|
"type": "monthly_limit_reached",
|
|
"info": "Your monthly API request volume has been reached. Please upgrade your plan."
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
$locale = $this->params['language'];
|
|
if (!empty($data['continent_name']))
|
|
$r['continent']['names'] = $this->locales($locale, $data['continent_name']);
|
|
if (!empty($data['continent_code']))
|
|
$r['continent']['code'] = strtoupper($data['continent_code']);
|
|
if (!empty($data['country_name']))
|
|
$r['country']['names'] = $this->locales($locale, $data['country_name']);
|
|
if (!empty($data['country_code']))
|
|
$r['country']['iso_code'] = strtoupper($data['country_code']);
|
|
|
|
if (!empty($data['region_code'])) {
|
|
$r['subdivisions'][0] = array(
|
|
'iso_code' => $data['region_code'],
|
|
'names' => $this->locales($locale, $data['region_name']),
|
|
);
|
|
}
|
|
|
|
if (!empty($data['city']))
|
|
$r['city']['names'] = $this->locales($locale, $data['city']);
|
|
if (!empty($data['latitude']))
|
|
$r['location']['latitude'] = $data['latitude'];
|
|
if (!empty($data['longitude']))
|
|
$r['location']['longitude'] = $data['longitude'];
|
|
|
|
if (isset($data['is_eu']))
|
|
$r['country']['is_in_european_union'] = $data['is_eu'];
|
|
if (isset($data['timezone']['id']))
|
|
$r['location']['time_zone'] = $data['timezone']['id'];
|
|
|
|
if (isset($data['connection']['asn']))
|
|
$r['traits']['autonomous_system_number'] = $data['connection']['asn'];
|
|
if (isset($data['connection']['isp']))
|
|
$r['traits']['isp'] = $data['connection']['isp'];
|
|
if (isset($data['security']['is_proxy']))
|
|
$r['traits']['is_anonymous_vpn'] = $data['security']['is_proxy'] && $data['security']['proxy_type'] == 'vpn';
|
|
if (isset($data['security']['is_tor']))
|
|
$r['traits']['is_tor_exit_node'] = $data['security']['is_tor'];
|
|
|
|
if (!empty($data['location']['country_flag_emoji']))
|
|
$r['extra']['flag'] = strtoupper($data['location']['country_flag_emoji']);
|
|
|
|
|
|
$r['traits']['ip_address'] = $ip;
|
|
|
|
$record = new \GeoIp2\Model\City($r, array('en'));
|
|
|
|
return $record;
|
|
}
|
|
|
|
public function country($ip) {
|
|
return $this->city($ip); // too much info shouldn't hurt ...
|
|
}
|
|
|
|
public function close() {
|
|
|
|
}
|
|
|
|
private function build_url($ip) {
|
|
$url = $this->params['ssl'] ? 'https' : 'http';
|
|
$url .= '://' . self::URL . $ip;
|
|
|
|
$params = [
|
|
'access_key' => $this->params['key'],
|
|
'language' => $this->params['language'],
|
|
];
|
|
return $url . '?' . \http_build_query($params);
|
|
}
|
|
|
|
private function api_call($ip) {
|
|
|
|
try {
|
|
// Setting timeout limit to speed up sites
|
|
$context = stream_context_create(
|
|
array(
|
|
'http' => array(
|
|
'timeout' => $this->options['timeout'],
|
|
),
|
|
)
|
|
);
|
|
// Using @file... to supress errors
|
|
// Example output: {"country_name":"UNITED STATES","country_code":"US","city":"Aurora, TX","ip":"12.215.42.19"}
|
|
|
|
$body = @file_get_contents($this->build_url($ip), false, $context);
|
|
$data = json_decode($body, true);
|
|
|
|
return $data;
|
|
} catch (\Exception $e) {
|
|
// If the API isn't available, we have to do this
|
|
throw $e;
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class IpstackSource extends AbstractDataSource {
|
|
protected $params = array();
|
|
|
|
public function __construct() {
|
|
$this->params['key'] = get_option('geoip-detect-ipstack_key', '');
|
|
$this->params['ssl'] = get_option('geoip-detect-ipstack_ssl', 0);
|
|
}
|
|
|
|
public function getId() { return 'ipstack'; }
|
|
public function getLabel() { return __('Ipstack Web-API', 'geoip-detect'); }
|
|
|
|
public function getDescriptionHTML() { return __('<a href="https://ipstack.com/">Ipstack</a>', 'geoip-detect'); }
|
|
public function getStatusInformationHTML() {
|
|
$html = '';
|
|
|
|
$html .= \sprintf(__('SSL: %s', 'geoip-detect'), $this->params['ssl'] ? __('Enabled', 'geoip-detect') : __('Disabled', 'geoip-detect')) . '<br />';
|
|
|
|
|
|
if (!$this->isWorking())
|
|
$html .= '<div class="geoip_detect_error">' . __('Ipstack only works with an API key.', 'geoip-detect') . '</div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
public function getParameterHTML() {
|
|
$label_key = __('API Access Key:', 'geoip-detect');
|
|
$label_ssl = __('Access the API via SSL:', 'geoip-detect');
|
|
|
|
$key = esc_attr($this->params['key']);
|
|
|
|
$html = <<<HTML
|
|
$label_key <input type="text" autocomplete="off" size="20" name="options_ipstack[key]" value="$key" /><br />
|
|
$label_ssl <select name="options_ipstack[ssl]">
|
|
HTML;
|
|
$html .= '<option value="0" ' . (!$this->params['ssl'] ? ' selected="selected"' : '') . '">' . __('HTTP (without encryption, not GDPR-compatible)', 'geoip-detect') . '</option>';
|
|
$html .= '<option value="1" ' . ($this->params['ssl'] ? ' selected="selected"' : '') . '">' . __('HTTPS (with encryption - paid plans only)', 'geoip-detect') . '</option>';
|
|
$html .= '</select>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
public function saveParameters($post) {
|
|
$message = '';
|
|
|
|
if (isset($post['options_ipstack']['key'])) {
|
|
update_option('geoip-detect-ipstack_key', $post['options_ipstack']['key']);
|
|
$this->params['key']= $post['options_ipstack']['key'];
|
|
}
|
|
|
|
if (isset($post['options_ipstack']['ssl'])) {
|
|
$ssl = (int) $post['options_ipstack']['ssl'];
|
|
update_option('geoip-detect-ipstack_ssl', $ssl);
|
|
$this->params['ssl'] = $post['options_ipstack']['ssl'];
|
|
}
|
|
|
|
if (geoip_detect2_is_source_active('ipstack') && !$this->isWorking())
|
|
$message .= __('Ipstack only works with an API key.', 'geoip-detect');
|
|
|
|
return $message;
|
|
}
|
|
|
|
public function getReader($locales = array('en'), $options = array()) {
|
|
return new Reader($this->params, $locales, $options);
|
|
}
|
|
|
|
public function isWorking() {
|
|
return !empty($this->params['key']);
|
|
}
|
|
|
|
}
|
|
geoip_detect2_register_source(new IpstackSource());
|