Иногда приходится определять с какой именно страны к нам зашел пользователь на PHP. В этом нам поможет MaxMind. Конечно, для nginx есть модуль, но когда хочется иметь все проще, но, может быть, чуть медленнее на PHP, то почему бы и нет?..
Более детальная информация находится на GitHub.
Если еще нет композера, то поставьте его (ссылка на офиц. сайт композера)...
curl -sS https://getcomposer.org/installer | php
Далее установим сам пакет PHP:
php composer.phar require geoip2/geoip2:~2.0
В нужном файле подключить:
require 'vendor/autoload.php';
Установить GeoIP:
https://zoomadmin.com/HowToInstall/UbuntuPackage/geoip-database
sudo apt-get update -y
sudo apt-get install -y geoip-database
Если Вы не хотите устанавливать GeoIP по определенным причинам, то сами базы можно скачать с сайта maxmind. НО! Для начала необходимо там зарегистрироваться...
Сам сайт:
https://www.maxmind.com/en/geolite2/signup
Регистрация и т.п...
Вводим данные, email должен быть настоящим...
Сам архив с базой IP Country (страны) выглядит так:
Города ...
обратите внимание, что файл
/usr/local/share/GeoIP/GeoIP2-City.mmdb
должен находится в указанном Вами каталоге.
<?php require_once 'vendor/autoload.php'; use GeoIp2\Database\Reader; // This creates the Reader object, which should be reused across // lookups. $reader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb'); // Replace "city" with the appropriate method for your database, e.g., // "country". $record = $reader->city('128.101.101.101'); print($record->country->isoCode . "\n"); // 'US' print($record->country->name . "\n"); // 'United States' print($record->country->names['zh-CN'] . "\n"); // '美国' print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota' print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN' print($record->city->name . "\n"); // 'Minneapolis' print($record->postal->code . "\n"); // '55455' print($record->location->latitude . "\n"); // 44.9733 print($record->location->longitude . "\n"); // -93.2323 print($record->traits->network . "\n"); // '128.101.101.101/32'
Страны...
обратите внимание, что файл
folder/GeoLite2-Country.mmdb
должен находится в указанном Вами каталоге.
<?php
#https://dev.maxmind.com/geoip/geoip2/geolite2/
#ini_set('display_errors',1);
require_once '../vendor/autoload.php';
use GeoIp2\Database\Reader;
// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader(getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb');
// Replace "city" with the appropriate method for your database, e.g.,
function ip():String //get user IP
{
$ip='';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip=$_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip=$_SERVER['REMOTE_ADDR'];
}
if(!filter_var($ip, FILTER_VALIDATE_IP)){
return '127.0.0.1';
}
return $ip;
}
$ip=ip();
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
echo 'Some error...';
exit;
}
// "country".
$country = $reader->country($ip);
print($country->country->isoCode);
ГЛАВНОЕ!
Точность определения зависит от выбранного Вами пакета. В пакете без оплаты, точность минимальная, чем больше платите — тем больше точность... Скрипт может отдать пустую строку, если он не определил страну по определенному IP, к примеру, 127.0.0.1
Помните о том, что в Вашем PHP приложении нужно закешировать переменную с вызовом функции получения страны по IP. Т.е. просто сделать так (код ниже)... Хотя в самом скрипте все максимально оптимизировано и базы хранятся в бинарнике (если Вы не используете CSV), но все-равно нужно помнить об оптимизации.
К примеру, у меня сайт, на котором требуется определять IP находится на одном сервере, а скрипт, который определяет страну — на другом. Поэтому я запрашиваю инфу по CURL...
function ip():String
{
$ip='';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip=$_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip=$_SERVER['REMOTE_ADDR'];
}
if(!filter_var($ip, FILTER_VALIDATE_IP)){
return '127.0.0.1';
}
return $ip;
}
function getCountry(){
if(!isset($_SESSION['country'])){
$qwe=explode(',',ip());
$link_='';
is_array($qwe) ? $link_='https://getcountry-from-ip.org/folder/IP.php?ip='.$qwe[0] : $link_='https://getcountry-from-ip/folder/IP.php?ip='.ip();
$ch = curl_init($link_);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response=curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($responseCode === 200){
if(empty($response) OR $response==""){$response='';}
$_SESSION['country']=$response;
return $response;
}else{
$_SESSION['country']='RU';
return 'RU';
}
}else{
return $_SESSION['country'];
}
}
Можно достучаться через web:
https://getcountry-from-ip.org/folder/IP.php?ip=192.168.0.1
Теперь, когда Вам нужна страна пользователя:
$country = getCountry();
Дальше используйте эту переменную или используйте $_SESSION
... так как функция getCountry()
записывает в сессию страну.
$country = $_SESSION['country'];
Сам файл скрипта на сервере, где я определяю страну по IP:
<?php
#https://dev.maxmind.com/geoip/geoip2/geolite2/
#ini_set('display_errors',1);
require_once '../vendor/autoload.php';
use GeoIp2\Database\Reader;
// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader(getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb');
// Replace "city" with the appropriate method for your database, e.g.,
$ip='';
if(isset($_GET['ip'])){$ip=$_GET['ip'];}else{
echo 'Some error...';
exit;
}
if(empty($_GET['ip'])){
echo 'Some error...';
exit;
}
$p_ = stripos($ip, ',');
if ($p_ !== false) {
$ip=explode(',',$ip);
$ip=trim($ip[0]);
}
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
echo 'Some error...';
exit;
}
// "country".
$country = $reader->country($ip);
print($country->country->isoCode);
/*
print($record->country->name . "\n"); // 'United States'
print($record->country->names['zh-CN'] . "\n"); // '美国'
print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'
print($record->city->name . "\n"); // 'Minneapolis'
print($record->postal->code . "\n"); // '55455'
print($record->location->latitude . "\n"); // 44.9733
print($record->location->longitude . "\n"); // -93.2323 */
Получается сама база лежит в каталоге:
getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb'
Файлы, которые были загружены с помощью композера нужно кинуть в корень Вашего проекта:
внутри папки vendor
(сгенерировано автоматически):
желательно запретить из web доступ к папке vendor
(для nginx):
location ~* ^/(composer.phar|composer.json|composer.lock) {
deny all;
}
location ~* ^/(vendor)($|\/) {deny all;}